From 3aec76f51209bb7605d1eaf7b00c84534e42f152 Mon Sep 17 00:00:00 2001 From: Andrew Seguin Date: Tue, 11 Nov 2025 06:20:43 -0700 Subject: [PATCH] fix(multiple): change value inputs to 'values' for array-based types --- src/aria/combobox/combobox.spec.ts | 84 +++--- src/aria/listbox/listbox.spec.ts | 156 +++++------ src/aria/listbox/listbox.ts | 10 +- src/aria/menu/menu.ts | 4 +- .../list-selection/list-selection.spec.ts | 112 ++++---- .../list-selection/list-selection.ts | 24 +- src/aria/private/behaviors/list/list.spec.ts | 52 ++-- src/aria/private/combobox/combobox.spec.ts | 104 ++++---- src/aria/private/listbox/combobox-listbox.ts | 4 +- src/aria/private/listbox/listbox.spec.ts | 252 ++++++++++-------- src/aria/private/listbox/listbox.ts | 4 +- src/aria/private/listbox/option.ts | 2 +- src/aria/private/menu/menu.spec.ts | 2 +- src/aria/private/menu/menu.ts | 4 +- src/aria/private/tabs/tabs.spec.ts | 18 +- src/aria/private/tabs/tabs.ts | 6 +- src/aria/private/toolbar/toolbar-widget.ts | 2 +- src/aria/private/toolbar/toolbar.ts | 4 +- src/aria/private/tree/combobox-tree.ts | 2 +- src/aria/private/tree/tree.spec.ts | 218 ++++++++------- src/aria/private/tree/tree.ts | 10 +- src/aria/tabs/tabs.ts | 2 +- src/aria/tree/tree.spec.ts | 244 ++++++++--------- src/aria/tree/tree.ts | 10 +- .../combobox-dialog-example.html | 2 +- .../listbox-configurable-example.html | 2 +- .../aria/toolbar/simple-toolbar.ts | 2 +- .../tree-configurable-example.html | 2 +- 28 files changed, 694 insertions(+), 644 deletions(-) diff --git a/src/aria/combobox/combobox.spec.ts b/src/aria/combobox/combobox.spec.ts index 7ff4dd7ca4a0..7d6bb8cf3fed 100644 --- a/src/aria/combobox/combobox.spec.ts +++ b/src/aria/combobox/combobox.spec.ts @@ -281,7 +281,7 @@ describe('Combobox', () => { click(options[0]); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); expect(inputElement.value).toBe('Alabama'); }); @@ -290,7 +290,7 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); expect(inputElement.value).toBe('Alabama'); }); @@ -298,7 +298,7 @@ describe('Combobox', () => { down(); down(); - expect(fixture.componentInstance.value()).toEqual([]); + expect(fixture.componentInstance.values()).toEqual([]); }); it('should select on focusout if the input text exactly matches an item', () => { @@ -306,7 +306,7 @@ describe('Combobox', () => { input('Alabama'); blur(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); }); it('should not select on focusout if the input text does not match an item', () => { @@ -314,7 +314,7 @@ describe('Combobox', () => { input('Appl'); blur(); - expect(fixture.componentInstance.value()).toEqual([]); + expect(fixture.componentInstance.values()).toEqual([]); expect(inputElement.value).toBe('Appl'); }); }); @@ -328,7 +328,7 @@ describe('Combobox', () => { click(options[1]); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['Alaska']); + expect(fixture.componentInstance.values()).toEqual(['Alaska']); expect(inputElement.value).toBe('Alaska'); }); @@ -337,26 +337,26 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Alaska']); + expect(fixture.componentInstance.values()).toEqual(['Alaska']); expect(inputElement.value).toBe('Alaska'); }); it('should select on navigation', () => { down(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); down(); - expect(fixture.componentInstance.value()).toEqual(['Alaska']); + expect(fixture.componentInstance.values()).toEqual(['Alaska']); down(); - expect(fixture.componentInstance.value()).toEqual(['Arizona']); + expect(fixture.componentInstance.values()).toEqual(['Arizona']); }); it('should select the first option on input', () => { focus(); input('W'); - expect(fixture.componentInstance.value()).toEqual(['Washington']); + expect(fixture.componentInstance.values()).toEqual(['Washington']); }); it('should commit the selected option on focusout', () => { @@ -365,7 +365,7 @@ describe('Combobox', () => { blur(); expect(inputElement.value).toBe('Georgia'); - expect(fixture.componentInstance.value()).toEqual(['Georgia']); + expect(fixture.componentInstance.values()).toEqual(['Georgia']); }); }); @@ -378,7 +378,7 @@ describe('Combobox', () => { click(options[2]); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['Arizona']); + expect(fixture.componentInstance.values()).toEqual(['Arizona']); expect(inputElement.value).toBe('Arizona'); }); @@ -388,16 +388,16 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Arizona']); + expect(fixture.componentInstance.values()).toEqual(['Arizona']); expect(inputElement.value).toBe('Arizona'); }); it('should select on navigation', () => { down(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); down(); - expect(fixture.componentInstance.value()).toEqual(['Alaska']); + expect(fixture.componentInstance.values()).toEqual(['Alaska']); }); it('should update input value on navigation', () => { @@ -412,7 +412,7 @@ describe('Combobox', () => { focus(); input('Cali'); - expect(fixture.componentInstance.value()).toEqual(['California']); + expect(fixture.componentInstance.values()).toEqual(['California']); }); it('should insert a highlighted completion string on input', () => { @@ -449,7 +449,7 @@ describe('Combobox', () => { blur(); expect(inputElement.value).toBe('California'); - expect(fixture.componentInstance.value()).toEqual(['California']); + expect(fixture.componentInstance.values()).toEqual(['California']); }); }); }); @@ -549,7 +549,7 @@ describe('Combobox', () => { // focus(); // fixture.componentInstance.value.set(['Banana']); // fixture.detectChanges(); - // expect(fixture.componentInstance.value()).toEqual(['Banana']); + // expect(fixture.componentInstance.values()).toEqual(['Banana']); // const bananaOption = getOption('Banana')!; // expect(bananaOption.getAttribute('aria-selected')).toBe('true'); // }); @@ -786,7 +786,7 @@ describe('Combobox', () => { click(item); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['April']); + expect(fixture.componentInstance.values()).toEqual(['April']); expect(inputElement.value).toBe('April'); }); @@ -794,7 +794,7 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Winter']); + expect(fixture.componentInstance.values()).toEqual(['Winter']); expect(inputElement.value).toBe('Winter'); }); @@ -803,14 +803,14 @@ describe('Combobox', () => { input('November'); blur(); - expect(fixture.componentInstance.value()).toEqual(['November']); + expect(fixture.componentInstance.values()).toEqual(['November']); }); it('should not select on navigation', () => { down(); down(); - expect(fixture.componentInstance.value()).toEqual([]); + expect(fixture.componentInstance.values()).toEqual([]); }); it('should not select on focusout if the input text does not match an item', () => { @@ -818,7 +818,7 @@ describe('Combobox', () => { input('Appl'); blur(); - expect(fixture.componentInstance.value()).toEqual([]); + expect(fixture.componentInstance.values()).toEqual([]); expect(inputElement.value).toBe('Appl'); }); }); @@ -834,7 +834,7 @@ describe('Combobox', () => { click(item); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['February']); + expect(fixture.componentInstance.values()).toEqual(['February']); expect(inputElement.value).toBe('February'); }); @@ -843,22 +843,22 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Spring']); + expect(fixture.componentInstance.values()).toEqual(['Spring']); expect(inputElement.value).toBe('Spring'); }); it('should select on navigation', () => { down(); - expect(fixture.componentInstance.value()).toEqual(['Winter']); + expect(fixture.componentInstance.values()).toEqual(['Winter']); down(); - expect(fixture.componentInstance.value()).toEqual(['Spring']); + expect(fixture.componentInstance.values()).toEqual(['Spring']); }); it('should select the first option on input', () => { focus(); input('Dec'); - expect(fixture.componentInstance.value()).toEqual(['December']); + expect(fixture.componentInstance.values()).toEqual(['December']); }); it('should commit the selected option on focusout', () => { @@ -867,7 +867,7 @@ describe('Combobox', () => { blur(); expect(inputElement.value).toBe('June'); - expect(fixture.componentInstance.value()).toEqual(['June']); + expect(fixture.componentInstance.values()).toEqual(['June']); }); }); @@ -882,7 +882,7 @@ describe('Combobox', () => { click(item); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['February']); + expect(fixture.componentInstance.values()).toEqual(['February']); expect(inputElement.value).toBe('February'); }); @@ -891,16 +891,16 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Spring']); + expect(fixture.componentInstance.values()).toEqual(['Spring']); expect(inputElement.value).toBe('Spring'); }); it('should select on navigation', () => { down(); - expect(fixture.componentInstance.value()).toEqual(['Winter']); + expect(fixture.componentInstance.values()).toEqual(['Winter']); down(); - expect(fixture.componentInstance.value()).toEqual(['Spring']); + expect(fixture.componentInstance.values()).toEqual(['Spring']); }); it('should update input value on navigation', () => { @@ -915,7 +915,7 @@ describe('Combobox', () => { focus(); input('Sept'); - expect(fixture.componentInstance.value()).toEqual(['September']); + expect(fixture.componentInstance.values()).toEqual(['September']); }); it('should insert a highlighted completion string on input', () => { @@ -933,7 +933,7 @@ describe('Combobox', () => { blur(); expect(inputElement.value).toBe('January'); - expect(fixture.componentInstance.value()).toEqual(['January']); + expect(fixture.componentInstance.values()).toEqual(['January']); }); }); }); @@ -1060,9 +1060,9 @@ describe('Combobox', () => { it('should update the selected item when the value is set programmatically', () => { setupCombobox(); focus(); - fixture.componentInstance.value.set(['August']); + fixture.componentInstance.values.set(['August']); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['August']); + expect(fixture.componentInstance.values()).toEqual(['August']); expect(getTreeItem('August')!.getAttribute('aria-selected')).toBe('true'); }); }); @@ -1106,7 +1106,7 @@ describe('Combobox', () => { /> -
+
@for (option of options(); track option) {
{ class ComboboxListboxExample { readonly = signal(false); searchString = signal(''); - value = signal([]); + values = signal([]); filterMode = signal<'manual' | 'auto-select' | 'highlight'>('manual'); options = computed(() => @@ -1149,7 +1149,7 @@ class ComboboxListboxExample { /> -
    +
      ([]); + values = signal([]); nodes = computed(() => this.filterTreeNodes(TREE_NODES)); filterMode = signal<'manual' | 'auto-select' | 'highlight'>('manual'); diff --git a/src/aria/listbox/listbox.spec.ts b/src/aria/listbox/listbox.spec.ts index 01b1c96db52e..df138a3eca61 100644 --- a/src/aria/listbox/listbox.spec.ts +++ b/src/aria/listbox/listbox.spec.ts @@ -52,7 +52,7 @@ describe('Listbox', () => { orientation?: 'horizontal' | 'vertical'; disabled?: boolean; readonly?: boolean; - value?: number[]; + values?: number[]; softDisabled?: boolean; focusMode?: 'roving' | 'activedescendant'; multi?: boolean; @@ -73,7 +73,7 @@ describe('Listbox', () => { if (opts?.orientation !== undefined) testComponent.orientation = opts.orientation; if (opts?.disabled !== undefined) testComponent.disabled = opts.disabled; if (opts?.readonly !== undefined) testComponent.readonly = opts.readonly; - if (opts?.value !== undefined) testComponent.value = opts.value; + if (opts?.values !== undefined) testComponent.values = opts.values; if (opts?.softDisabled !== undefined) testComponent.softDisabled = opts.softDisabled; if (opts?.focusMode !== undefined) testComponent.focusMode = opts.focusMode; if (opts?.multi !== undefined) testComponent.multi = opts.multi; @@ -173,7 +173,7 @@ describe('Listbox', () => { }); it('should set aria-selected to "true" for selected options', () => { - setupListbox({multi: true, value: [1, 3]}); + setupListbox({multi: true, values: [1, 3]}); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); expect(optionElements[2].getAttribute('aria-selected')).toBe('false'); @@ -200,7 +200,7 @@ describe('Listbox', () => { expect(listboxElement.getAttribute('tabindex')).toBe('0'); }); - it('should set initial focus (tabindex="0") on the first non-disabled option if no value is set', () => { + it('should set initial focus (tabindex="0") on the first non-disabled option if no values are set', () => { setupListbox({focusMode: 'roving'}); expect(optionElements[0].getAttribute('tabindex')).toBe('0'); expect(optionElements[1].getAttribute('tabindex')).toBe('-1'); @@ -210,7 +210,7 @@ describe('Listbox', () => { }); it('should set initial focus (tabindex="0") on the first selected option', () => { - setupListbox({focusMode: 'roving', value: [2]}); + setupListbox({focusMode: 'roving', values: [2]}); expect(optionElements[0].getAttribute('tabindex')).toBe('-1'); expect(optionElements[1].getAttribute('tabindex')).toBe('-1'); expect(optionElements[2].getAttribute('tabindex')).toBe('0'); @@ -221,7 +221,7 @@ describe('Listbox', () => { it('should set initial focus (tabindex="0") on the first non-disabled option if selected option is disabled when softDisabled is false', () => { setupListbox({ focusMode: 'roving', - value: [1], + values: [1], disabledOptions: [0], softDisabled: false, }); @@ -232,7 +232,7 @@ describe('Listbox', () => { it('should set initial focus (tabindex="0") on the first option if selected option is disabled', () => { setupListbox({ focusMode: 'roving', - value: [0], + values: [0], disabledOptions: [0], }); expect(optionElements[0].getAttribute('tabindex')).toBe('0'); @@ -257,19 +257,19 @@ describe('Listbox', () => { }); it('should set aria-activedescendant to the ID of the first selected option', () => { - setupListbox({focusMode: 'activedescendant', value: [2]}); + setupListbox({focusMode: 'activedescendant', values: [2]}); expect(listboxElement.getAttribute('aria-activedescendant')).toBe(optionElements[2].id); }); it('should set aria-activedescendant to the ID of the first non-disabled option if selected option is disabled', () => { - setupListbox({focusMode: 'activedescendant', value: [0], disabledOptions: [0]}); + setupListbox({focusMode: 'activedescendant', values: [0], disabledOptions: [0]}); expect(listboxElement.getAttribute('aria-activedescendant')).toBe(optionElements[0].id); }); it('should set aria-activedescendant to the ID of the first non-disabled option if selected option is disabled when softDisabled is false', () => { setupListbox({ focusMode: 'activedescendant', - value: [1], + values: [1], disabledOptions: [0], softDisabled: false, }); @@ -289,28 +289,28 @@ describe('Listbox', () => { describe('value and selection', () => { it('should select the options corresponding to the value input', () => { - setupListbox({multi: true, value: [1, 3]}); + setupListbox({multi: true, values: [1, 3]}); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); expect(optionElements[3].getAttribute('aria-selected')).toBe('true'); - expect(listboxInstance.value()).toEqual([1, 3]); + expect(listboxInstance.values()).toEqual([1, 3]); }); it('should update the value model when an option is selected via UI (single select)', () => { setupListbox({multi: false}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); click(2); - expect(listboxInstance.value()).toEqual([2]); + expect(listboxInstance.values()).toEqual([2]); }); it('should update the value model when options are selected via UI (multi select)', () => { setupListbox({multi: true}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); click(3); - expect(listboxInstance.value()).toEqual([1, 3]); + expect(listboxInstance.values()).toEqual([1, 3]); click(1); - expect(listboxInstance.value()).toEqual([3]); + expect(listboxInstance.values()).toEqual([3]); }); describe('pointer interactions', () => { @@ -318,14 +318,14 @@ describe('Listbox', () => { it('should select an option on click', () => { setupListbox({multi: false}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should select a new option and deselect the old one on click', () => { - setupListbox({multi: false, value: [0]}); + setupListbox({multi: false, values: [0]}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); @@ -334,30 +334,30 @@ describe('Listbox', () => { describe('multi select', () => { describe('selection follows focus', () => { it('should select only the clicked option with a simple click', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should toggle the selected state of an option with ctrl + click', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); click(1, {ctrlKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('true'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); click(0, {ctrlKey: true}); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should select a range starting from the first option on shift + click', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); click(2, {shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2]); expect(optionElements[0].getAttribute('aria-selected')).toBe('true'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); expect(optionElements[2].getAttribute('aria-selected')).toBe('true'); @@ -367,46 +367,46 @@ describe('Listbox', () => { setupListbox({multi: true, selectionMode: 'follow'}); click(1); click(3, {shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([1, 2, 3]); + expect(listboxInstance.values().sort()).toEqual([1, 2, 3]); }); it('should not select disabled options on shift + click', () => { setupListbox({multi: true, selectionMode: 'follow', disabledOptions: [1]}); click(2, {shiftKey: true}); - expect(listboxInstance.value()).toEqual([0, 2]); + expect(listboxInstance.values()).toEqual([0, 2]); }); }); describe('explicit selection', () => { it('should toggle selection of the clicked option with a simple click', () => { - setupListbox({multi: true, selectionMode: 'explicit', value: [0]}); + setupListbox({multi: true, selectionMode: 'explicit', values: [0]}); click(1); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('true'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); click(0); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); }); it('should select a range starting from the first option on shift + click', () => { - setupListbox({multi: true, selectionMode: 'explicit', value: [0]}); + setupListbox({multi: true, selectionMode: 'explicit', values: [0]}); click(2, {shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2]); }); it('should select a range starting from the current active option on shift + click', () => { setupListbox({multi: true, selectionMode: 'explicit'}); click(1); click(3, {shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([1, 2, 3]); + expect(listboxInstance.values().sort()).toEqual([1, 2, 3]); }); it('should not select disabled options on shift + click', () => { setupListbox({multi: true, selectionMode: 'follow', disabledOptions: [1]}); click(2, {shiftKey: true}); - expect(listboxInstance.value()).toEqual([0, 2]); + expect(listboxInstance.values()).toEqual([0, 2]); }); }); }); @@ -418,30 +418,30 @@ describe('Listbox', () => { it('should select the next option on ArrowDown', () => { setupListbox({multi: false, selectionMode: 'follow'}); down(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); down(); - expect(listboxInstance.value()).toEqual([2]); + expect(listboxInstance.values()).toEqual([2]); expect(optionElements[2].getAttribute('aria-selected')).toBe('true'); }); it('should select the previous option on ArrowUp', () => { - setupListbox({multi: false, selectionMode: 'follow', value: [2]}); + setupListbox({multi: false, selectionMode: 'follow', values: [2]}); up(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should select the first option on Home', () => { - setupListbox({multi: false, selectionMode: 'follow', value: [2]}); + setupListbox({multi: false, selectionMode: 'follow', values: [2]}); home(); - expect(listboxInstance.value()).toEqual([0]); + expect(listboxInstance.values()).toEqual([0]); }); it('should select the last option on End', () => { - setupListbox({multi: false, selectionMode: 'follow', value: [2]}); + setupListbox({multi: false, selectionMode: 'follow', values: [2]}); end(); - expect(listboxInstance.value()).toEqual([4]); + expect(listboxInstance.values()).toEqual([4]); }); }); @@ -452,7 +452,7 @@ describe('Listbox', () => { up(); home(); end(); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); expect(optionElements[1].getAttribute('aria-selected')).toBe('false'); }); @@ -460,12 +460,12 @@ describe('Listbox', () => { setupListbox({multi: false, selectionMode: 'explicit'}); down(); space(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); down(); down(); space(); - expect(listboxInstance.value()).toEqual([3]); + expect(listboxInstance.values()).toEqual([3]); expect(optionElements[1].getAttribute('aria-selected')).toBe('false'); expect(optionElements[3].getAttribute('aria-selected')).toBe('true'); }); @@ -474,7 +474,7 @@ describe('Listbox', () => { setupListbox({multi: false, selectionMode: 'explicit'}); down(); enter(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); }); @@ -483,46 +483,46 @@ describe('Listbox', () => { describe('multi select', () => { describe('selection follows focus', () => { it('should select only the focused option on ArrowDown (no modifier)', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); down(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should move focus but not change selection on ctrl + ArrowDown, then toggle with ctrl + Space', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); down({ctrlKey: true}); - expect(listboxInstance.value()).toEqual([0]); + expect(listboxInstance.values()).toEqual([0]); space({ctrlKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); }); it('should toggle selection of the focused item on ctrl + Space', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); space({ctrlKey: true}); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); down(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); space({ctrlKey: true}); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); }); it('should extend selection on shift + ArrowDown', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); down({shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); down({shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2]); }); it('should select all on Ctrl+A, then select active on second Ctrl+A', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); keydown('A', {ctrlKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2, 3, 4]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2, 3, 4]); keydown('A', {ctrlKey: true}); - expect(listboxInstance.value()).toEqual([0]); + expect(listboxInstance.values()).toEqual([0]); }); }); @@ -530,43 +530,43 @@ describe('Listbox', () => { it('should move focus but not select on ArrowDown', () => { setupListbox({multi: true, selectionMode: 'explicit'}); down(); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); }); it('should toggle selection of the focused item on Space', () => { setupListbox({multi: true, selectionMode: 'explicit'}); down(); space(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); down(); space(); - expect(listboxInstance.value().sort()).toEqual([1, 2]); + expect(listboxInstance.values().sort()).toEqual([1, 2]); space(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); }); it('should toggle selection of the focused item on Enter', () => { setupListbox({multi: true, selectionMode: 'explicit'}); down(); enter(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); }); it('should extend selection on Shift+ArrowDown', () => { setupListbox({multi: true, selectionMode: 'explicit'}); down({shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); down({shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2]); }); it('should toggle selection of all options on Ctrl+A', () => { - setupListbox({multi: true, selectionMode: 'explicit', value: [0]}); + setupListbox({multi: true, selectionMode: 'explicit', values: [0]}); keydown('A', {ctrlKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2, 3, 4]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2, 3, 4]); keydown('A', {ctrlKey: true}); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); }); }); }); @@ -711,7 +711,7 @@ describe('Listbox', () => { setupListbox({options: getOptions(), focusMode, selectionMode: 'follow'}); type('O'); expect(isFocused(4)).toBe(true); - expect(listboxInstance.value()).toEqual([4]); + expect(listboxInstance.values()).toEqual([4]); expect(optionElements[4].getAttribute('aria-selected')).toBe('true'); }); @@ -719,7 +719,7 @@ describe('Listbox', () => { setupListbox({options: getOptions(), focusMode, selectionMode: 'explicit'}); type('O'); expect(isFocused(4)).toBe(true); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); expect(optionElements[4].getAttribute('aria-selected')).toBe('false'); }); @@ -766,7 +766,7 @@ describe('Listbox', () => { expect(optionElements.length).toBe(0); expect(() => down()).not.toThrow(); expect(() => space()).not.toThrow(); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); }); }); }); @@ -782,7 +782,7 @@ interface TestOption {
        { readonly = input(false, {transform: booleanAttribute}); /** The values of the current selected items. */ - value = model([]); + values = model([]); /** The Listbox UIPattern. */ readonly _pattern: ListboxPattern; @@ -169,13 +169,13 @@ export class Listbox { } }); - // Ensure that the value is always in sync with the available options. + // Ensure that the values are always in sync with the available options. afterRenderEffect(() => { const items = inputs.items(); - const value = untracked(() => this.value()); + const values = untracked(() => this.values()); - if (items && value.some(v => !items.some(i => i.value() === v))) { - this.value.set(value.filter(v => items.some(i => i.value() === v))); + if (items && values.some(v => !items.some(i => i.value() === v))) { + this.values.set(values.filter(v => items.some(i => i.value() === v))); } }); } diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index c56aa3abab3a..0e818f2d6bb4 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -279,8 +279,8 @@ export class MenuBar { /** The directionality (LTR / RTL) context for the application (or a subtree of it). */ readonly textDirection = inject(Directionality).valueSignal; - /** The value of the menu. */ - readonly value = model([]); + /** The values of the menu. */ + readonly values = model([]); /** Whether the menu should wrap its items. */ readonly wrap = input(true); diff --git a/src/aria/private/behaviors/list-selection/list-selection.spec.ts b/src/aria/private/behaviors/list-selection/list-selection.spec.ts index ef54329c7131..735b984105ee 100644 --- a/src/aria/private/behaviors/list-selection/list-selection.spec.ts +++ b/src/aria/private/behaviors/list-selection/list-selection.spec.ts @@ -27,7 +27,7 @@ function getSelection(inputs: TestInputs = {}): ListSelection { it('should select an item', () => { const selection = getSelection(); selection.select(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should select multiple options', () => { @@ -65,7 +65,7 @@ describe('List Selection', () => { selection.inputs.focusManager.focus(items[1]); selection.select(); // [0, 1] - expect(selection.inputs.value()).toEqual([0, 1]); + expect(selection.inputs.values()).toEqual([0, 1]); }); it('should not select multiple options', () => { @@ -74,7 +74,7 @@ describe('List Selection', () => { selection.select(); // [0] selection.inputs.focusManager.focus(items[1]); selection.select(); // [1] - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); it('should not select disabled items', () => { @@ -82,7 +82,7 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].disabled.set(true); selection.select(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should not select non-selectable items', () => { @@ -90,14 +90,14 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.select(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should do nothing to already selected items', () => { const selection = getSelection(); selection.select(); // [0] selection.select(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); }); @@ -105,7 +105,7 @@ describe('List Selection', () => { it('should deselect an item', () => { const selection = getSelection(); selection.deselect(); // [] - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should not deselect disabled items', () => { @@ -114,7 +114,7 @@ describe('List Selection', () => { selection.select(); // [0] items[0].disabled.set(true); selection.deselect(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should not deselect non-selectable items', () => { @@ -123,7 +123,7 @@ describe('List Selection', () => { selection.select(); // [0] items[0].selectable.set(false); selection.deselect(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); }); @@ -131,14 +131,14 @@ describe('List Selection', () => { it('should select an unselected item', () => { const selection = getSelection(); selection.toggle(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should deselect a selected item', () => { const selection = getSelection(); selection.select(); // [0] selection.toggle(); // [] - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should not toggle non-selectable items', () => { @@ -146,7 +146,7 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.toggle(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); }); @@ -154,14 +154,14 @@ describe('List Selection', () => { it('should select an unselected item', () => { const selection = getSelection({multi: signal(true)}); selection.toggleOne(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should deselect a selected item', () => { const selection = getSelection({multi: signal(true)}); selection.select(); // [0] selection.toggleOne(); // [] - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should only leave one item selected', () => { @@ -170,7 +170,7 @@ describe('List Selection', () => { selection.select(); // [0] selection.inputs.focusManager.focus(items[1]); selection.toggleOne(); // [1] - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); it('should not toggle non-selectable items', () => { @@ -178,7 +178,7 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.toggleOne(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); }); @@ -186,13 +186,13 @@ describe('List Selection', () => { it('should select all items', () => { const selection = getSelection({multi: signal(true)}); selection.selectAll(); - expect(selection.inputs.value()).toEqual([0, 1, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([0, 1, 2, 3, 4]); }); it('should do nothing if a list is not multiselectable', () => { const selection = getSelection({multi: signal(false)}); selection.selectAll(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should not select non-selectable items', () => { @@ -200,7 +200,7 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[1].selectable.set(false); selection.selectAll(); - expect(selection.inputs.value()).toEqual([0, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([0, 2, 3, 4]); }); }); @@ -209,14 +209,14 @@ describe('List Selection', () => { const selection = getSelection({multi: signal(true)}); selection.selectAll(); // [0, 1, 2, 3, 4] selection.deselectAll(); // [] - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should deselect items that are not in the list', () => { const selection = getSelection({multi: signal(true)}); - selection.inputs.value.update(() => [5]); + selection.inputs.values.update(() => [5]); selection.deselectAll(); - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should not deselect non-selectable items', () => { @@ -225,7 +225,7 @@ describe('List Selection', () => { selection.selectAll(); // [0, 1, 2, 3, 4] items[1].selectable.set(false); selection.deselectAll(); // [1] - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); }); @@ -233,14 +233,14 @@ describe('List Selection', () => { it('should select all items', () => { const selection = getSelection({multi: signal(true)}); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([0, 1, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([0, 1, 2, 3, 4]); }); it('should deselect all if all items are selected', () => { const selection = getSelection({multi: signal(true)}); selection.selectAll(); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should ignore disabled items when determining if all items are selected', () => { @@ -248,9 +248,9 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].disabled.set(true); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([1, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([1, 2, 3, 4]); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should ignore non-selectable items when determining if all items are selected', () => { @@ -258,9 +258,9 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([1, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([1, 2, 3, 4]); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); }); @@ -271,7 +271,7 @@ describe('List Selection', () => { selection.selectOne(); // [0] selection.inputs.focusManager.focus(items[1]); selection.selectOne(); // [1] - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); it('should not select disabled items', () => { @@ -280,7 +280,7 @@ describe('List Selection', () => { items[0].disabled.set(true); selection.select(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should not select non-selectable items', () => { @@ -288,14 +288,14 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.selectOne(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should do nothing to already selected items', () => { const selection = getSelection({multi: signal(true)}); selection.selectOne(); // [0] selection.selectOne(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should do nothing if the current active item is disabled', () => { @@ -304,12 +304,12 @@ describe('List Selection', () => { selection.inputs.focusManager.focus(items[1]); selection.select(); - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); selection.inputs.focusManager.focus(items[0]); items[0].disabled.set(true); selection.selectOne(); - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); it('should not select an item if the list is not multiselectable and not all items are deselected', () => { @@ -318,12 +318,12 @@ describe('List Selection', () => { selection.inputs.focusManager.focus(items[1]); selection.select(); - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); items[1].disabled.set(true); selection.inputs.focusManager.focus(items[2]); selection.selectOne(); - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); }); @@ -334,7 +334,7 @@ describe('List Selection', () => { selection.select(); // [0] selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 1, 2] - expect(selection.inputs.value()).toEqual([0, 1, 2]); + expect(selection.inputs.values()).toEqual([0, 1, 2]); }); it('should select all items from an anchor at a higher index', () => { @@ -346,7 +346,7 @@ describe('List Selection', () => { selection.inputs.focusManager.focus(items[1]); selection.selectRange(); // [3, 2, 1] - expect(selection.inputs.value()).toEqual([3, 2, 1]); + expect(selection.inputs.values()).toEqual([3, 2, 1]); }); it('should deselect items within the range when the range is changed', () => { @@ -355,15 +355,15 @@ describe('List Selection', () => { selection.inputs.activeItem.set(items[2]); selection.select(); // [2] - expect(selection.inputs.value()).toEqual([2]); + expect(selection.inputs.values()).toEqual([2]); selection.inputs.focusManager.focus(items[4]); selection.selectRange(); // [2, 3, 4] - expect(selection.inputs.value()).toEqual([2, 3, 4]); + expect(selection.inputs.values()).toEqual([2, 3, 4]); selection.inputs.focusManager.focus(items[0]); selection.selectRange(); // [2, 1, 0] - expect(selection.inputs.value()).toEqual([2, 1, 0]); + expect(selection.inputs.values()).toEqual([2, 1, 0]); }); it('should not select a disabled item', () => { @@ -372,15 +372,15 @@ describe('List Selection', () => { items[1].disabled.set(true); selection.select(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); selection.inputs.focusManager.focus(items[1]); selection.selectRange(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 2] - expect(selection.inputs.value()).toEqual([0, 2]); + expect(selection.inputs.values()).toEqual([0, 2]); }); it('should not select a non-selectable item', () => { @@ -390,7 +390,7 @@ describe('List Selection', () => { selection.select(); // [0] selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 2] - expect(selection.inputs.value()).toEqual([0, 2]); + expect(selection.inputs.values()).toEqual([0, 2]); }); it('should not deselect a disabled item', () => { @@ -401,15 +401,15 @@ describe('List Selection', () => { items[1].disabled.set(true); selection.select(); // [0, 1] - expect(selection.inputs.value()).toEqual([1, 0]); + expect(selection.inputs.values()).toEqual([1, 0]); selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 1, 2] - expect(selection.inputs.value()).toEqual([1, 0, 2]); + expect(selection.inputs.values()).toEqual([1, 0, 2]); selection.inputs.focusManager.focus(items[0]); selection.selectRange(); // [0, 1] - expect(selection.inputs.value()).toEqual([1, 0]); + expect(selection.inputs.values()).toEqual([1, 0]); }); it('should not deselect a non-selectable item', () => { @@ -418,13 +418,13 @@ describe('List Selection', () => { selection.select(items[1]); // [1] items[1].selectable.set(false); selection.select(); // [0, 1] - expect(selection.inputs.value()).toEqual([1, 0]); + expect(selection.inputs.values()).toEqual([1, 0]); selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 1, 2] - expect(selection.inputs.value()).toEqual([1, 0, 2]); + expect(selection.inputs.values()).toEqual([1, 0, 2]); selection.inputs.focusManager.focus(items[0]); selection.selectRange(); // [0, 1] - expect(selection.inputs.value()).toEqual([1, 0]); + expect(selection.inputs.values()).toEqual([1, 0]); }); }); @@ -434,10 +434,10 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; selection.inputs.focusManager.focus(items[2]); selection.beginRangeSelection(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); selection.inputs.focusManager.focus(items[4]); selection.selectRange(); // [2, 3, 4] - expect(selection.inputs.value()).toEqual([2, 3, 4]); + expect(selection.inputs.values()).toEqual([2, 3, 4]); }); it('should be able to select a range starting on a disabled item', () => { @@ -447,7 +447,7 @@ describe('List Selection', () => { selection.beginRangeSelection(0); selection.inputs.focusManager.focus(items[2]); selection.selectRange(); - expect(selection.inputs.value()).toEqual([1, 2]); + expect(selection.inputs.values()).toEqual([1, 2]); }); }); }); diff --git a/src/aria/private/behaviors/list-selection/list-selection.ts b/src/aria/private/behaviors/list-selection/list-selection.ts index f9ef4a33fe16..6f7c191defec 100644 --- a/src/aria/private/behaviors/list-selection/list-selection.ts +++ b/src/aria/private/behaviors/list-selection/list-selection.ts @@ -10,7 +10,7 @@ import {computed, signal} from '@angular/core'; import {SignalLike, WritableSignalLike} from '../signal-like/signal-like'; import {ListFocus, ListFocusInputs, ListFocusItem} from '../list-focus/list-focus'; -/** Represents an item in a collection, such as a listbox option, than can be selected. */ +/** Represents an item in a collection, such as a listbox option, that can be selected. */ export interface ListSelectionItem extends ListFocusItem { /** The value of the item. */ value: SignalLike; @@ -25,7 +25,7 @@ export interface ListSelectionInputs, V> extends multi: SignalLike; /** The current value of the list selection. */ - value: WritableSignalLike; + values: WritableSignalLike; /** The selection strategy used by the list. */ selectionMode: SignalLike<'follow' | 'explicit'>; @@ -41,7 +41,7 @@ export class ListSelection, V> { /** The currently selected items. */ selectedItems = computed(() => - this.inputs.items().filter(item => this.inputs.value().includes(item.value())), + this.inputs.items().filter(item => this.inputs.values().includes(item.value())), ); constructor(readonly inputs: ListSelectionInputs & {focusManager: ListFocus}) {} @@ -54,7 +54,7 @@ export class ListSelection, V> { !item || item.disabled() || !item.selectable() || - this.inputs.value().includes(item.value()) + this.inputs.values().includes(item.value()) ) { return; } @@ -67,7 +67,7 @@ export class ListSelection, V> { if (opts.anchor) { this.beginRangeSelection(index); } - this.inputs.value.update(values => values.concat(item.value())); + this.inputs.values.update(values => values.concat(item.value())); } /** Deselects the item at the current active index. */ @@ -75,7 +75,7 @@ export class ListSelection, V> { item = item ?? this.inputs.focusManager.inputs.activeItem(); if (item && !item.disabled() && item.selectable()) { - this.inputs.value.update(values => values.filter(value => value !== item.value())); + this.inputs.values.update(values => values.filter(value => value !== item.value())); } } @@ -83,7 +83,7 @@ export class ListSelection, V> { toggle(item?: ListSelectionItem) { item = item ?? this.inputs.focusManager.inputs.activeItem(); if (item) { - this.inputs.value().includes(item.value()) ? this.deselect(item) : this.select(item); + this.inputs.values().includes(item.value()) ? this.deselect(item) : this.select(item); } } @@ -91,7 +91,7 @@ export class ListSelection, V> { toggleOne() { const item = this.inputs.focusManager.inputs.activeItem(); if (item) { - this.inputs.value().includes(item.value()) ? this.deselect() : this.selectOne(); + this.inputs.values().includes(item.value()) ? this.deselect() : this.selectOne(); } } @@ -123,12 +123,12 @@ export class ListSelection, V> { // inverse (and more common) effect of keeping enabled items selected when they aren't in the // list. - for (const value of this.inputs.value()) { + for (const value of this.inputs.values()) { const item = this.inputs.items().find(i => i.value() === value); item ? this.deselect(item) - : this.inputs.value.update(values => values.filter(v => v !== value)); + : this.inputs.values.update(values => values.filter(v => v !== value)); } } @@ -142,7 +142,7 @@ export class ListSelection, V> { .filter(i => !i.disabled() && i.selectable()) .map(i => i.value()); - selectableValues.every(i => this.inputs.value().includes(i)) + selectableValues.every(i => this.inputs.values().includes(i)) ? this.deselectAll() : this.selectAll(); } @@ -156,7 +156,7 @@ export class ListSelection, V> { this.deselectAll(); - if (this.inputs.value().length > 0 && !this.inputs.multi()) { + if (this.inputs.values().length > 0 && !this.inputs.multi()) { return; } diff --git a/src/aria/private/behaviors/list/list.spec.ts b/src/aria/private/behaviors/list/list.spec.ts index 3deab9c3e49b..0ac2fe68f883 100644 --- a/src/aria/private/behaviors/list/list.spec.ts +++ b/src/aria/private/behaviors/list/list.spec.ts @@ -22,7 +22,7 @@ type TestList = List, V>; describe('List Behavior', () => { function getList(inputs: Partial> & Pick, 'items'>): TestList { return new List({ - value: inputs.value ?? signal([]), + values: inputs.values ?? signal([]), activeItem: signal(undefined), typeaheadDelay: inputs.typeaheadDelay ?? signal(0.5), wrap: inputs.wrap ?? signal(true), @@ -137,7 +137,7 @@ describe('List Behavior', () => { it('should not select items', () => { list.next({selectOne: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should have a tab index of 0', () => { @@ -167,7 +167,7 @@ describe('List Behavior', () => { it('should not select items', () => { list.next({selectOne: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should have a tab index of 0', () => { @@ -254,7 +254,7 @@ describe('List Behavior', () => { beforeEach(() => { const patterns = getDefaultPatterns({ - value: signal([]), + values: signal([]), multi: signal(false), }); list = patterns.list; @@ -263,39 +263,39 @@ describe('List Behavior', () => { it('should not select when navigating', () => { list.next(); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should select an item when navigating with selectOne:true', () => { list.next({selectOne: true}); - expect(list.inputs.value()).toEqual(['Apricot']); + expect(list.inputs.values()).toEqual(['Apricot']); }); it('should not select a non-selectable item when navigating with selectOne:true', () => { items[1].selectable.set(false); list.next({selectOne: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should toggle an item when navigating with toggle:true', () => { list.goto(items[1], {selectOne: true}); - expect(list.inputs.value()).toEqual(['Apricot']); + expect(list.inputs.values()).toEqual(['Apricot']); list.goto(items[1], {toggle: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should not toggle a non-selectable item when navigating with toggle:true', () => { items[1].selectable.set(false); list.goto(items[1], {toggle: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should only allow one selected item', () => { list.next({selectOne: true}); - expect(list.inputs.value()).toEqual(['Apricot']); + expect(list.inputs.values()).toEqual(['Apricot']); list.next({selectOne: true}); - expect(list.inputs.value()).toEqual(['Banana']); + expect(list.inputs.values()).toEqual(['Banana']); }); }); @@ -305,7 +305,7 @@ describe('List Behavior', () => { beforeEach(() => { const patterns = getDefaultPatterns({ - value: signal([]), + values: signal([]), multi: signal(true), }); list = patterns.list; @@ -314,57 +314,57 @@ describe('List Behavior', () => { it('should not select when navigating', () => { list.next(); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should select an item with toggle:true', () => { list.next({toggle: true}); - expect(list.inputs.value()).toEqual(['Apricot']); + expect(list.inputs.values()).toEqual(['Apricot']); }); it('should not select a non-selectable item with toggle:true', () => { items[1].selectable.set(false); list.next({toggle: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should allow multiple selected items', () => { list.next({toggle: true}); list.next({toggle: true}); - expect(list.inputs.value()).toEqual(['Apricot', 'Banana']); + expect(list.inputs.values()).toEqual(['Apricot', 'Banana']); }); it('should select a range of items with selectRange:true', () => { list.anchor(0); list.next({selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(list.inputs.values()).toEqual(['Apple', 'Apricot']); list.next({selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Apricot', 'Banana']); + expect(list.inputs.values()).toEqual(['Apple', 'Apricot', 'Banana']); list.prev({selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(list.inputs.values()).toEqual(['Apple', 'Apricot']); list.prev({selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple']); + expect(list.inputs.values()).toEqual(['Apple']); }); it('should not wrap when range selecting', () => { list.anchor(0); list.prev({selectRange: true}); expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should not select disabled items in a range', () => { items[1].disabled.set(true); list.anchor(0); list.goto(items[3], {selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Banana', 'Blackberry']); + expect(list.inputs.values()).toEqual(['Apple', 'Banana', 'Blackberry']); }); it('should not select non-selectable items in a range', () => { items[1].selectable.set(false); list.anchor(0); list.goto(items[3], {selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Banana', 'Blackberry']); + expect(list.inputs.values()).toEqual(['Apple', 'Banana', 'Blackberry']); }); }); }); @@ -404,14 +404,14 @@ describe('List Behavior', () => { it('should select an item via typeahead', () => { const {list} = getDefaultPatterns({multi: signal(false)}); list.search('b', {selectOne: true}); - expect(list.inputs.value()).toEqual(['Banana']); + expect(list.inputs.values()).toEqual(['Banana']); }); it('should not select a non-selectable item via typeahead', () => { const {list, items} = getDefaultPatterns({multi: signal(false)}); items[2].selectable.set(false); // 'Banana' list.search('b', {selectOne: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); }); }); diff --git a/src/aria/private/combobox/combobox.spec.ts b/src/aria/private/combobox/combobox.spec.ts index d97876882b38..6dc275584a47 100644 --- a/src/aria/private/combobox/combobox.spec.ts +++ b/src/aria/private/combobox/combobox.spec.ts @@ -122,7 +122,7 @@ function getListboxPattern( const listbox = new ComboboxListboxPattern({ id: signal('listbox-1'), items: options, - value: signal(initialValue ? [initialValue] : []), + values: signal(initialValue ? [initialValue] : []), combobox: signal(combobox) as any, activeItem: signal(undefined), typeaheadDelay: signal(0.5), @@ -166,7 +166,7 @@ function getTreePattern( const tree = new ComboboxTreePattern({ id: signal('tree-1'), allItems: items, - value: signal(initialValue ? [initialValue] : []), + values: signal(initialValue ? [initialValue] : []), combobox: signal(combobox) as any, activeItem: signal(undefined), typeaheadDelay: signal(0.5), @@ -377,7 +377,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickOption(listbox.inputs.items(), 0)); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); expect(inputEl.value).toBe('Apple'); }); @@ -385,7 +385,7 @@ describe('Combobox with Listbox Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); expect(inputEl.value).toBe('Apple'); }); @@ -393,37 +393,37 @@ describe('Combobox with Listbox Pattern', () => { type('Apple'); combobox.onFocusOut(new FocusEvent('focusout')); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should deselect on close if the input text does not match any options', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); type('Appl', {backspace: true}); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); combobox.onKeydown(escape()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should not select on navigation', () => { combobox.onKeydown(down()); expect(listbox.getSelectedItems().length).toBe(0); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should not select on input', () => { type('A'); expect(listbox.getSelectedItems().length).toBe(0); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should not select on focusout if the input text does not match an item', () => { type('Appl'); combobox.onFocusOut(new FocusEvent('focusout')); expect(listbox.getSelectedItems().length).toBe(0); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); expect(inputEl.value).toBe('Appl'); }); }); @@ -438,7 +438,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickOption(listbox.inputs.items(), 3)); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[3]); - expect(listbox.inputs.value()).toEqual(['Blackberry']); + expect(listbox.inputs.values()).toEqual(['Blackberry']); expect(inputEl.value).toBe('Blackberry'); }); @@ -448,14 +448,14 @@ describe('Combobox with Listbox Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select the last item on arrow up when collapsed', () => { @@ -463,22 +463,22 @@ describe('Combobox with Listbox Pattern', () => { expect(listbox.getSelectedItems()[0]).toBe( listbox.inputs.items()[listbox.inputs.items().length - 1], ); - expect(listbox.inputs.value()).toEqual(['Cranberry']); + expect(listbox.inputs.values()).toEqual(['Cranberry']); }); it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[1]); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should select the first option on input', () => { type('A'); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); type('Apr'); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should commit the selected option on focusout', () => { @@ -499,7 +499,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickOption(listbox.inputs.items(), 3)); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[3]); - expect(listbox.inputs.value()).toEqual(['Blackberry']); + expect(listbox.inputs.values()).toEqual(['Blackberry']); expect(inputEl.value).toBe('Blackberry'); }); @@ -509,14 +509,14 @@ describe('Combobox with Listbox Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select the last item on arrow up when collapsed', () => { @@ -524,22 +524,22 @@ describe('Combobox with Listbox Pattern', () => { expect(listbox.getSelectedItems()[0]).toBe( listbox.inputs.items()[listbox.inputs.items().length - 1], ); - expect(listbox.inputs.value()).toEqual(['Cranberry']); + expect(listbox.inputs.values()).toEqual(['Cranberry']); }); it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[1]); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should select the first option on input', () => { type('A'); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); type('Apr'); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should commit the selected option on navigation', () => { @@ -586,7 +586,7 @@ describe('Combobox with Listbox Pattern', () => { const {combobox, listbox, inputEl} = getPatterns({readonly: true}); combobox.onPointerup(clickOption(listbox.inputs.items(), 2)); expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); expect(combobox.expanded()).toBe(false); }); @@ -608,7 +608,7 @@ describe('Combobox with Listbox Pattern', () => { combobox.onPointerup(clickOption(listbox.inputs.items(), 1)); combobox.onPointerup(clickOption(listbox.inputs.items(), 2)); - expect(listbox.inputs.value()).toEqual(['Apricot', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apricot', 'Banana']); expect(inputEl.value).toBe('Apricot, Banana'); }); }); @@ -741,7 +741,7 @@ describe('Combobox with Tree Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 0)); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.inputs.values()).toEqual(['Fruit']); expect(inputEl.value).toBe('Fruit'); }); @@ -749,7 +749,7 @@ describe('Combobox with Tree Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.inputs.values()).toEqual(['Fruit']); expect(inputEl.value).toBe('Fruit'); }); @@ -757,37 +757,37 @@ describe('Combobox with Tree Pattern', () => { combobox.onPointerup(clickInput(inputEl)); type('Apple'); combobox.onFocusOut(new FocusEvent('focusout')); - expect(tree.inputs.value()).toEqual(['Apple']); + expect(tree.inputs.values()).toEqual(['Apple']); }); it('should deselect on close if the input text does not match any options', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.inputs.values()).toEqual(['Fruit']); type('Frui', {backspace: true}); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.inputs.values()).toEqual(['Fruit']); combobox.onKeydown(escape()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should not select on navigation', () => { combobox.onKeydown(down()); expect(tree.getSelectedItems().length).toBe(0); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should not select on input', () => { type('A'); expect(tree.getSelectedItems().length).toBe(0); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should not select on focusout if the input text does not match an item', () => { type('Appl'); combobox.onFocusOut(new FocusEvent('focusout')); expect(tree.getSelectedItems().length).toBe(0); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); expect(inputEl.value).toBe('Appl'); }); }); @@ -802,7 +802,7 @@ describe('Combobox with Tree Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 2)); expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[2]); - expect(tree.inputs.value()).toEqual(['Banana']); + expect(tree.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); @@ -811,34 +811,34 @@ describe('Combobox with Tree Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Grains']); + expect(tree.inputs.values()).toEqual(['Grains']); expect(inputEl.value).toBe('Grains'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.inputs.values()).toEqual(['Fruit']); }); it('should select the last focusable item on arrow up when collapsed', () => { combobox.onKeydown(up()); - expect(tree.inputs.value()).toEqual(['Grains']); + expect(tree.inputs.values()).toEqual(['Grains']); }); it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(right()); combobox.onKeydown(right()); - expect(tree.inputs.value()).toEqual(['Apple']); + expect(tree.inputs.values()).toEqual(['Apple']); }); it('should select the first option on input', () => { type('B'); - expect(tree.inputs.value()).toEqual(['Banana']); + expect(tree.inputs.values()).toEqual(['Banana']); type('Bro'); - expect(tree.inputs.value()).toEqual(['Broccoli']); + expect(tree.inputs.values()).toEqual(['Broccoli']); }); it('should commit the selected option on focusout', () => { @@ -859,7 +859,7 @@ describe('Combobox with Tree Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 2)); expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[2]); - expect(tree.inputs.value()).toEqual(['Banana']); + expect(tree.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); @@ -868,34 +868,34 @@ describe('Combobox with Tree Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Grains']); + expect(tree.inputs.values()).toEqual(['Grains']); expect(inputEl.value).toBe('Grains'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.inputs.values()).toEqual(['Fruit']); }); it('should select the last focusable item on arrow up when collapsed', () => { combobox.onKeydown(up()); - expect(tree.inputs.value()).toEqual(['Grains']); + expect(tree.inputs.values()).toEqual(['Grains']); }); it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(right()); combobox.onKeydown(right()); - expect(tree.inputs.value()).toEqual(['Apple']); + expect(tree.inputs.values()).toEqual(['Apple']); }); it('should select the first option on input', () => { type('B'); - expect(tree.inputs.value()).toEqual(['Banana']); + expect(tree.inputs.values()).toEqual(['Banana']); type('Bro'); - expect(tree.inputs.value()).toEqual(['Broccoli']); + expect(tree.inputs.values()).toEqual(['Broccoli']); }); it('should commit the selected option on navigation', () => { @@ -905,7 +905,7 @@ describe('Combobox with Tree Pattern', () => { combobox.onKeydown(right()); expect(inputEl.value).toBe('Apple'); combobox.onKeydown(down()); - expect(tree.inputs.value()).toEqual(['Banana']); + expect(tree.inputs.values()).toEqual(['Banana']); }); it('should commit the selected option on focusout', () => { @@ -930,7 +930,7 @@ describe('Combobox with Tree Pattern', () => { combobox.onPointerup(clickInput(inputEl)); expect(combobox.expanded()).toBe(true); combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 0)); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.inputs.values()).toEqual(['Fruit']); expect(inputEl.value).toBe('Fruit'); expect(combobox.expanded()).toBe(false); }); diff --git a/src/aria/private/listbox/combobox-listbox.ts b/src/aria/private/listbox/combobox-listbox.ts index 02735c6c4aa6..96cf94eb4655 100644 --- a/src/aria/private/listbox/combobox-listbox.ts +++ b/src/aria/private/listbox/combobox-listbox.ts @@ -98,7 +98,7 @@ export class ComboboxListboxPattern getSelectedItems = () => { // NOTE: We need to do this funky for loop to preserve the order of the selected values. const items = []; - for (const value of this.inputs.value()) { + for (const value of this.inputs.values()) { const item = this.items().find(i => i.value() === value); if (item) { items.push(item); @@ -108,5 +108,5 @@ export class ComboboxListboxPattern }; /** Sets the value of the combobox listbox. */ - setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); + setValue = (value: V | undefined) => this.inputs.values.set(value ? [value] : []); } diff --git a/src/aria/private/listbox/listbox.spec.ts b/src/aria/private/listbox/listbox.spec.ts index 2dbfe867d950..42a1615e5f80 100644 --- a/src/aria/private/listbox/listbox.spec.ts +++ b/src/aria/private/listbox/listbox.spec.ts @@ -34,7 +34,7 @@ describe('Listbox Pattern', () => { return new ListboxPattern({ id: signal('listbox-1'), items: inputs.items, - value: inputs.value ?? signal([]), + values: inputs.values ?? signal([]), activeItem: signal(undefined), typeaheadDelay: inputs.typeaheadDelay ?? signal(0.5), wrap: inputs.wrap ?? signal(true), @@ -174,45 +174,45 @@ describe('Listbox Pattern', () => { describe('follows focus & single select', () => { it('should select an option on navigation', () => { const {listbox} = getDefaultPatterns({ - value: signal(['Apple']), + values: signal(['Apple']), multi: signal(false), selectionMode: signal('follow'), }); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[1]); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onKeydown(up()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(end()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[8]); - expect(listbox.inputs.value()).toEqual(['Cranberry']); + expect(listbox.inputs.values()).toEqual(['Cranberry']); listbox.onKeydown(home()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should not be able to change selection when in readonly mode', () => { const {listbox} = getDefaultPatterns({ - value: signal(['Apple']), + values: signal(['Apple']), readonly: signal(true), multi: signal(false), selectionMode: signal('follow'), }); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[1]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); }); @@ -221,7 +221,7 @@ describe('Listbox Pattern', () => { beforeEach(() => { listbox = getDefaultPatterns({ - value: signal([]), + values: signal([]), selectionMode: signal('explicit'), multi: signal(false), }).listbox; @@ -229,30 +229,30 @@ describe('Listbox Pattern', () => { it('should select an option on Space', () => { listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select an option on Enter', () => { listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should only allow one selected option', () => { listbox.onKeydown(enter()); listbox.onKeydown(down()); listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should not be able to change selection when in readonly mode', () => { const readonly = listbox.inputs.readonly as WritableSignal; readonly.set(true); listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(down()); listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); }); @@ -262,7 +262,7 @@ describe('Listbox Pattern', () => { beforeEach(() => { const patterns = getDefaultPatterns({ - value: signal([]), + values: signal([]), selectionMode: signal('explicit'), multi: signal(true), }); @@ -272,37 +272,37 @@ describe('Listbox Pattern', () => { it('should select an option on Space', () => { listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select an option on Enter', () => { listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should allow multiple selected options', () => { listbox.onKeydown(enter()); listbox.onKeydown(down()); listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); }); it('should select a range of options on Shift + ArrowDown/ArrowUp', () => { listbox.onKeydown(shift()); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot', 'Banana']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should not allow wrapping while Shift is held down', () => { listbox.onKeydown(shift()); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should select a range of options on Shift + Space (or Enter)', () => { @@ -312,20 +312,20 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apricot', 'Banana', 'Blackberry']); + expect(listbox.inputs.values()).toEqual(['Apricot', 'Banana', 'Blackberry']); }); it('should deselect options outside the range on subsequent on Shift + Space (or Enter)', () => { listbox.onKeydown(down()); listbox.onKeydown(down()); listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); listbox.onKeydown(down()); listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Blackberry', 'Blueberry']); listbox.onKeydown(up()); listbox.onKeydown(up()); @@ -333,7 +333,7 @@ describe('Listbox Pattern', () => { listbox.onKeydown(up()); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); it('should select the focused option and all options up to the first option on Ctrl + Shift + Home', () => { @@ -342,7 +342,7 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(home({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual(['Blackberry', 'Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Blackberry', 'Banana', 'Apricot', 'Apple']); }); it('should select the focused option and all options down to the last option on Ctrl + Shift + End', () => { @@ -353,31 +353,36 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(end({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual(['Cantaloupe', 'Cherry', 'Clementine', 'Cranberry']); + expect(listbox.inputs.values()).toEqual([ + 'Cantaloupe', + 'Cherry', + 'Clementine', + 'Cranberry', + ]); }); it('should not be able to change selection when in readonly mode', () => { const readonly = listbox.inputs.readonly as WritableSignal; readonly.set(true); listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(down()); listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(shift()); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(end({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(home({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should not change the selected state of disabled options on Shift + ArrowUp / ArrowDown', () => { @@ -385,19 +390,19 @@ describe('Listbox Pattern', () => { options[1].disabled.set(true); listbox.onKeydown(shift()); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Banana']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select all options on Ctrl + A', () => { - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(a({control: true})); - expect(listbox.inputs.value()).toEqual([ + expect(listbox.inputs.values()).toEqual([ 'Apple', 'Apricot', 'Banana', @@ -411,10 +416,10 @@ describe('Listbox Pattern', () => { }); it('should deselect all options on Ctrl + A if all options are selected', () => { - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(a({control: true})); listbox.onKeydown(a({control: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); }); @@ -424,7 +429,7 @@ describe('Listbox Pattern', () => { beforeEach(() => { const patterns = getDefaultPatterns({ - value: signal(['Apple']), + values: signal(['Apple']), multi: signal(true), selectionMode: signal('follow'), }); @@ -433,25 +438,25 @@ describe('Listbox Pattern', () => { }); it('should select an option on navigation', () => { - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onKeydown(up()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(end()); - expect(listbox.inputs.value()).toEqual(['Cranberry']); + expect(listbox.inputs.values()).toEqual(['Cranberry']); listbox.onKeydown(home()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should navigate without selecting an option if the Ctrl key is pressed', () => { - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(up({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(end({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(home({control: true})); }); @@ -459,26 +464,26 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down({control: true})); listbox.onKeydown(down({control: true})); listbox.onKeydown(space({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Banana']); }); it('should select a range of options on Shift + ArrowDown/ArrowUp', () => { listbox.onKeydown(shift()); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot', 'Banana']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should not allow wrapping while Shift is held down', () => { listbox.listBehavior.deselectAll(); listbox.onKeydown(shift()); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should select a range of options on Shift + Space (or Enter)', () => { @@ -487,19 +492,19 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down({control: true})); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apricot', 'Banana', 'Blackberry']); + expect(listbox.inputs.values()).toEqual(['Apricot', 'Banana', 'Blackberry']); }); it('should deselect options outside the range on subsequent on Shift + Space (or Enter)', () => { listbox.onKeydown(down()); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); listbox.onKeydown(down({control: true})); listbox.onKeydown(down({control: true})); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Blackberry', 'Blueberry']); listbox.onKeydown(up({control: true})); listbox.onKeydown(up({control: true})); @@ -507,7 +512,7 @@ describe('Listbox Pattern', () => { listbox.onKeydown(up({control: true})); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); it('should select the focused option and all options up to the first option on Ctrl + Shift + Home', () => { @@ -516,7 +521,7 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(home({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual(['Blackberry', 'Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Blackberry', 'Banana', 'Apricot', 'Apple']); }); it('should select the focused option and all options down to the last option on Ctrl + Shift + End', () => { @@ -527,38 +532,43 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(end({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual(['Cantaloupe', 'Cherry', 'Clementine', 'Cranberry']); + expect(listbox.inputs.values()).toEqual([ + 'Cantaloupe', + 'Cherry', + 'Clementine', + 'Cranberry', + ]); }); it('should not be able to change selection when in readonly mode', () => { const readonly = listbox.inputs.readonly as WritableSignal; readonly.set(true); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(up()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(space({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should not select disabled options', () => { options[2].disabled.set(true); (listbox.inputs.softDisabled as WritableSignal).set(true); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Blackberry']); + expect(listbox.inputs.values()).toEqual(['Blackberry']); }); it('should deselect all except one option on Ctrl + A if all options are selected', () => { listbox.onKeydown(a({control: true})); listbox.onKeydown(a({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); }); }); @@ -579,7 +589,7 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); }); @@ -590,17 +600,17 @@ describe('Listbox Pattern', () => { selectionMode: signal('explicit'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should deselect a selected option on click', () => { const {listbox, options} = getDefaultPatterns({ multi: signal(false), - value: signal(['Apple']), + values: signal(['Apple']), selectionMode: signal('explicit'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); }); @@ -611,17 +621,17 @@ describe('Listbox Pattern', () => { selectionMode: signal('explicit'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should deselect a selected option on click', () => { const {listbox, options} = getDefaultPatterns({ multi: signal(true), - value: signal(['Apple']), + values: signal(['Apple']), selectionMode: signal('explicit'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should select options from anchor on shift + click', () => { @@ -632,7 +642,12 @@ describe('Listbox Pattern', () => { listbox.onPointerdown(click(options, 2)); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 5, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry', 'Cantaloupe']); + expect(listbox.inputs.values()).toEqual([ + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cantaloupe', + ]); }); it('should deselect options outside the range on subsequent shift + clicks', () => { @@ -643,9 +658,14 @@ describe('Listbox Pattern', () => { listbox.onPointerdown(click(options, 2)); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 5, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry', 'Cantaloupe']); + expect(listbox.inputs.values()).toEqual([ + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cantaloupe', + ]); listbox.onPointerdown(click(options, 0, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); }); @@ -656,11 +676,11 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onPointerdown(click(options, 1)); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onPointerdown(click(options, 2)); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); }); it('should select an unselected option on ctrl + click', () => { @@ -669,11 +689,11 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onPointerdown(click(options, 1, {control: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onPointerdown(click(options, 2, {control: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot', 'Banana']); }); it('should deselect a selected option on ctrl + click', () => { @@ -682,9 +702,9 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onPointerdown(click(options, 0, {control: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should select a range of options on shift + click', () => { @@ -695,7 +715,12 @@ describe('Listbox Pattern', () => { listbox.onPointerdown(click(options, 2)); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 5, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry', 'Cantaloupe']); + expect(listbox.inputs.values()).toEqual([ + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cantaloupe', + ]); }); it('should deselect options outside the range on subsequent shift + clicks', () => { @@ -706,9 +731,14 @@ describe('Listbox Pattern', () => { listbox.onPointerdown(click(options, 2)); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 5, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry', 'Cantaloupe']); + expect(listbox.inputs.values()).toEqual([ + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cantaloupe', + ]); listbox.onPointerdown(click(options, 0, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); it('should select a range up to but not including a disabled option on shift + click', () => { @@ -719,11 +749,11 @@ describe('Listbox Pattern', () => { }); options[2].disabled.set(true); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 2, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); expect(listbox.inputs.activeItem()).toEqual(options[2]); }); @@ -735,11 +765,11 @@ describe('Listbox Pattern', () => { }); options[2].disabled.set(true); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onPointerdown(click(options, 2)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); }); @@ -749,11 +779,11 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onPointerdown(click(options, 1)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onPointerdown(click(options, 2)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should maintain the range selection between pointer and keyboard', () => { @@ -767,9 +797,9 @@ describe('Listbox Pattern', () => { listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Blackberry', 'Blueberry']); listbox.onPointerdown(click(options, 0, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); it('should select a range from the currently focused option', () => { @@ -778,12 +808,12 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down({control: true})); listbox.onKeydown(down({control: true})); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 4, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Banana', 'Blackberry', 'Blueberry']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Banana', 'Blackberry', 'Blueberry']); }); }); @@ -805,7 +835,7 @@ describe('Listbox Pattern', () => { it('should set the active index to the first selected option', () => { const {listbox} = getDefaultPatterns({ - value: signal(['Banana']), + values: signal(['Banana']), softDisabled: signal(false), }); listbox.setDefaultState(); @@ -814,7 +844,7 @@ describe('Listbox Pattern', () => { it('should set the active index to the first focusable selected option', () => { const {listbox, options} = getDefaultPatterns({ - value: signal(['Banana', 'Blackberry']), + values: signal(['Banana', 'Blackberry']), softDisabled: signal(false), }); options[2].disabled.set(true); @@ -824,7 +854,7 @@ describe('Listbox Pattern', () => { it('should set the active index to the first option if no selected option is focusable', () => { const {listbox, options} = getDefaultPatterns({ - value: signal(['Banana']), + values: signal(['Banana']), softDisabled: signal(false), }); options[2].disabled.set(true); diff --git a/src/aria/private/listbox/listbox.ts b/src/aria/private/listbox/listbox.ts index b4769c1ff061..e65fffb1e05f 100644 --- a/src/aria/private/listbox/listbox.ts +++ b/src/aria/private/listbox/listbox.ts @@ -199,9 +199,9 @@ export class ListboxPattern { validate(): string[] { const violations: string[] = []; - if (!this.inputs.multi() && this.inputs.value().length > 1) { + if (!this.inputs.multi() && this.inputs.values().length > 1) { violations.push( - `A single-select listbox should not have multiple selected options. Selected options: ${this.inputs.value().join(', ')}`, + `A single-select listbox should not have multiple selected options. Selected options: ${this.inputs.values().join(', ')}`, ); } diff --git a/src/aria/private/listbox/option.ts b/src/aria/private/listbox/option.ts index 166cb99bad5a..718774382f40 100644 --- a/src/aria/private/listbox/option.ts +++ b/src/aria/private/listbox/option.ts @@ -39,7 +39,7 @@ export class OptionPattern { active = computed(() => this.listbox()?.inputs.activeItem() === this); /** Whether the option is selected. */ - selected = computed(() => this.listbox()?.inputs.value().includes(this.value())); + selected = computed(() => this.listbox()?.inputs.values().includes(this.value())); /** Whether the option is selectable. */ selectable = () => true; diff --git a/src/aria/private/menu/menu.spec.ts b/src/aria/private/menu/menu.spec.ts index d38d2f30e504..d526c25dc533 100644 --- a/src/aria/private/menu/menu.spec.ts +++ b/src/aria/private/menu/menu.spec.ts @@ -57,7 +57,7 @@ function getMenuBarPattern(values: string[], opts?: {textDirection: 'ltr' | 'rtl textDirection: signal(opts?.textDirection || 'ltr'), multi: signal(false), selectionMode: signal('explicit'), - value: signal([]), + values: signal([]), wrap: signal(true), typeaheadDelay: signal(0.5), softDisabled: signal(true), diff --git a/src/aria/private/menu/menu.ts b/src/aria/private/menu/menu.ts index f9b4cec3c921..f9e1cd68cf3c 100644 --- a/src/aria/private/menu/menu.ts +++ b/src/aria/private/menu/menu.ts @@ -25,7 +25,7 @@ export interface MenuBarInputs extends Omit, V> /** The inputs for the MenuPattern class. */ export interface MenuInputs - extends Omit, V>, 'value' | 'disabled'> { + extends Omit, V>, 'values' | 'disabled'> { /** The unique ID of the menu. */ id: SignalLike; @@ -165,7 +165,7 @@ export class MenuPattern { this.id = inputs.id; this.listBehavior = new List, V>({ ...inputs, - value: signal([]), + values: signal([]), disabled: () => false, }); } diff --git a/src/aria/private/tabs/tabs.spec.ts b/src/aria/private/tabs/tabs.spec.ts index ea541399f350..8dd35117d3ba 100644 --- a/src/aria/private/tabs/tabs.spec.ts +++ b/src/aria/private/tabs/tabs.spec.ts @@ -65,7 +65,7 @@ describe('Tabs Pattern', () => { activeItem: signal(undefined), softDisabled: signal(true), items: signal([]), - value: signal(['tab-1']), + values: signal(['tab-1']), element: signal(document.createElement('div')), }; tabListPattern = new TabListPattern(tabListInputs); @@ -141,30 +141,30 @@ describe('Tabs Pattern', () => { it('sets the selected tab by setting `value`.', () => { expect(tabPatterns[0].selected()).toBeTrue(); expect(tabPatterns[1].selected()).toBeFalse(); - tabListInputs.value.set(['tab-2']); + tabListInputs.values.set(['tab-2']); expect(tabPatterns[0].selected()).toBeFalse(); expect(tabPatterns[1].selected()).toBeTrue(); }); it('sets a tabpanel to be not hidden if a tab is selected.', () => { - tabListInputs.value.set(['tab-1']); + tabListInputs.values.set(['tab-1']); expect(tabPatterns[0].selected()).toBeTrue(); expect(tabPanelPatterns[0].hidden()).toBeFalse(); }); it('sets a tabpanel to be hidden if a tab is not selected.', () => { - tabListInputs.value.set(['tab-1']); + tabListInputs.values.set(['tab-1']); expect(tabPatterns[1].selected()).toBeFalse(); expect(tabPanelPatterns[1].hidden()).toBeTrue(); }); it('should set a tabpanel tab index to 0 if the tab is selected.', () => { - tabListInputs.value.set(['tab-1']); + tabListInputs.values.set(['tab-1']); expect(tabPatterns[0].tabIndex()).toBe(0); }); it('should set a tabpanel tab index to -1 if the tab is not selected.', () => { - tabListInputs.value.set(['tab-1']); + tabListInputs.values.set(['tab-1']); expect(tabPatterns[1].tabIndex()).toBe(-1); expect(tabPatterns[2].tabIndex()).toBe(-1); }); @@ -203,7 +203,7 @@ describe('Tabs Pattern', () => { it('should set activeIndex to the first focusable tab if no tabs are selected', () => { tabListInputs.softDisabled.set(false); tabListInputs.activeItem.set(tabPatterns[2]); - tabListInputs.value.set([]); + tabListInputs.values.set([]); tabInputs[0].disabled.set(true); tabListPattern.setDefaultState(); expect(tabListInputs.activeItem()).toBe(tabPatterns[1]); @@ -211,14 +211,14 @@ describe('Tabs Pattern', () => { it('should set activeIndex to the first focusable and selected tab', () => { tabListInputs.activeItem.set(tabPatterns[0]); - tabListInputs.value.set([tabPatterns[2].value()]); + tabListInputs.values.set([tabPatterns[2].value()]); tabListPattern.setDefaultState(); expect(tabListInputs.activeItem()).toBe(tabPatterns[2]); }); it('should set activeIndex to the first focusable tab when the selected tab is not focusable', () => { tabListInputs.softDisabled.set(false); - tabListInputs.value.set([tabPatterns[1].value()]); + tabListInputs.values.set([tabPatterns[1].value()]); tabInputs[1].disabled.set(true); tabListPattern.setDefaultState(); expect(tabListInputs.activeItem()).toBe(tabPatterns[0]); diff --git a/src/aria/private/tabs/tabs.ts b/src/aria/private/tabs/tabs.ts index 8d4583931db8..50c4dc782175 100644 --- a/src/aria/private/tabs/tabs.ts +++ b/src/aria/private/tabs/tabs.ts @@ -68,7 +68,9 @@ export class TabPattern { readonly active = computed(() => this.inputs.tablist().inputs.activeItem() === this); /** Whether the tab is selected. */ - readonly selected = computed(() => !!this.inputs.tablist().inputs.value().includes(this.value())); + readonly selected = computed( + () => !!this.inputs.tablist().inputs.values().includes(this.value()), + ); /** The tab index of the tab. */ readonly tabIndex = computed(() => this.inputs.tablist().listBehavior.getItemTabindex(this)); @@ -205,7 +207,7 @@ export class TabListPattern { this.expansionManager = new ListExpansion({ ...inputs, multiExpandable: () => false, - expandedIds: this.inputs.value, + expandedIds: this.inputs.values, }); } diff --git a/src/aria/private/toolbar/toolbar-widget.ts b/src/aria/private/toolbar/toolbar-widget.ts index ff52c352bc20..242e02f71d8a 100644 --- a/src/aria/private/toolbar/toolbar-widget.ts +++ b/src/aria/private/toolbar/toolbar-widget.ts @@ -55,7 +55,7 @@ export class ToolbarWidgetPattern implements ListItem { /** Whether the widget is selected (only relevant in a selection group). */ readonly selected = computed(() => - this.toolbar().listBehavior.inputs.value().includes(this.value()), + this.toolbar().listBehavior.inputs.values().includes(this.value()), ); /** Whether the widget is currently the active one (focused). */ diff --git a/src/aria/private/toolbar/toolbar.ts b/src/aria/private/toolbar/toolbar.ts index 14e021e93241..68d63af0a53a 100644 --- a/src/aria/private/toolbar/toolbar.ts +++ b/src/aria/private/toolbar/toolbar.ts @@ -15,7 +15,7 @@ import {ToolbarWidgetPattern} from './toolbar-widget'; /** Represents the required inputs for a toolbar. */ export type ToolbarInputs = Omit< ListInputs, V>, - 'multi' | 'typeaheadDelay' | 'value' | 'selectionMode' | 'focusMode' + 'multi' | 'typeaheadDelay' | 'values' | 'selectionMode' | 'focusMode' > & { /** A function that returns the toolbar item associated with a given element. */ getItem: (e: Element) => ToolbarWidgetPattern | undefined; @@ -160,7 +160,7 @@ export class ToolbarPattern { multi: () => true, focusMode: () => 'roving', selectionMode: () => 'explicit', - value: signal([] as V[]), + values: signal([] as V[]), typeaheadDelay: () => 0, // Toolbar widgets do not support typeahead. }); } diff --git a/src/aria/private/tree/combobox-tree.ts b/src/aria/private/tree/combobox-tree.ts index 3f64ae752938..5e2120ce1e1f 100644 --- a/src/aria/private/tree/combobox-tree.ts +++ b/src/aria/private/tree/combobox-tree.ts @@ -92,7 +92,7 @@ export class ComboboxTreePattern getSelectedItems = () => this.inputs.allItems().filter(item => item.selected()); /** Sets the value of the combobox tree. */ - setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); + setValue = (value: V | undefined) => this.inputs.values.set(value ? [value] : []); /** Expands the currently focused item if it is expandable. */ expandItem = () => this.expand(); diff --git a/src/aria/private/tree/tree.spec.ts b/src/aria/private/tree/tree.spec.ts index a39fd3d5fddf..4da67ae80179 100644 --- a/src/aria/private/tree/tree.spec.ts +++ b/src/aria/private/tree/tree.spec.ts @@ -150,7 +150,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -204,7 +204,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(true), currentType: signal('page'), @@ -215,7 +215,7 @@ describe('Tree Pattern', () => { it('should have undefined selected state', () => { const {allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); expect(item0.selected()).toBeUndefined(); }); @@ -224,11 +224,11 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); expect(item0.current()).toBe('page'); expect(item1.current()).toBeUndefined(); - treeInputs.value.set(['Item 1']); + treeInputs.values.set(['Item 1']); treeInputs.currentType.set('step'); expect(item0.current()).toBeUndefined(); expect(item1.current()).toBe('step'); @@ -237,7 +237,7 @@ describe('Tree Pattern', () => { it('should have undefined current state when non-selectable', () => { const {allItems, itemPatternInputsMap} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); expect(item0.current()).toBe('page'); itemPatternInputsMap.get(item0.id())!.selectable.set(false); expect(item0.current()).toBeUndefined(); @@ -260,7 +260,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -446,7 +446,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -459,11 +459,11 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); expect(item0.selected()).toBe(true); expect(item1.selected()).toBe(false); - treeInputs.value.set(['Item 1']); + treeInputs.values.set(['Item 1']); expect(item0.selected()).toBe(false); expect(item1.selected()).toBe(true); }); @@ -471,7 +471,7 @@ describe('Tree Pattern', () => { it('should have undefined selected state when non-selectable', () => { const {allItems, itemPatternInputsMap} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); itemPatternInputsMap.get(item0.id())!.selectable.set(false); expect(item0.selected()).toBeUndefined(); }); @@ -483,11 +483,11 @@ describe('Tree Pattern', () => { tree.onKeydown(down()); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); tree.onKeydown(up()); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should not change selection when the tree is disabled', () => { @@ -495,7 +495,7 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -514,7 +514,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -526,45 +526,45 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should not deselect an item on Space', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should select an item on Enter', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should not deselect an item on Enter', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should only allow one selected item', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); tree.onKeydown(down()); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should not change selection when the tree is disabled', () => { @@ -572,10 +572,10 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -594,7 +594,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -606,14 +606,14 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should select an item on Enter', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should allow multiple selected items', () => { @@ -622,7 +622,7 @@ describe('Tree Pattern', () => { tree.onKeydown(enter()); tree.onKeydown(down()); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 1']); }); it('should select a range of visible items on Shift + ArrowDown/ArrowUp', () => { @@ -632,13 +632,13 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0']); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); tree.onKeydown(up({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0']); }); it('should not allow wrapping while Shift is held down', () => { @@ -648,7 +648,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(up({shift: true})); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should select a range of visible items on Shift + Space (or Enter)', () => { @@ -658,13 +658,13 @@ describe('Tree Pattern', () => { tree.onKeydown(down()); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0-0']); tree.onKeydown(down()); tree.onKeydown(down()); tree.onKeydown(shift()); tree.onKeydown(space({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1']); }); it('should select the focused item and all visible items up to the first on Ctrl + Shift + Home', () => { @@ -676,7 +676,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(home({control: true, shift: true})); - expect(tree.inputs.value()).toEqual(['Item 1', 'Item 0-1', 'Item 0-0', 'Item 0']); + expect(tree.inputs.values()).toEqual(['Item 1', 'Item 0-1', 'Item 0-0', 'Item 0']); }); it('should select the focused item and all visible items down to the last on Ctrl + Shift + End', () => { @@ -688,7 +688,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(end({control: true, shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); }); it('should not change selection when the tree is disabled', () => { @@ -696,10 +696,10 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should not select disabled items on Shift + ArrowUp / ArrowDown', () => { @@ -716,7 +716,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(down({shift: true})); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['A', 'C']); + expect(tree.inputs.values()).toEqual(['A', 'C']); }); it('should not select non-selectable items on Shift + ArrowUp / ArrowDown', () => { @@ -732,7 +732,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(down({shift: true})); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['A', 'C']); + expect(tree.inputs.values()).toEqual(['A', 'C']); }); it('should select all visible items on Ctrl + A', () => { @@ -741,7 +741,13 @@ describe('Tree Pattern', () => { item0.expansion.open(); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual([ + 'Item 0', + 'Item 0-0', + 'Item 0-1', + 'Item 1', + 'Item 2', + ]); }); it('should deselect all visible items on Ctrl + A if all are selected', () => { @@ -751,7 +757,7 @@ describe('Tree Pattern', () => { tree.onKeydown(a({control: true})); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -770,7 +776,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -782,42 +788,42 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate without selecting if the Ctrl key is pressed', () => { - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); const {tree, allItems} = createTree(treeExample, treeInputs); const item1 = getItemByValue(allItems(), 'Item 1'); tree.onKeydown(down({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); expect(tree.activeItem()).toBe(item1); }); it('should toggle an item selection state on Ctrl + Space', () => { - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(down({control: true})); tree.onKeydown(space({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 1']); tree.onKeydown(space({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should select a range of visible items on Shift + ArrowDown/ArrowUp', () => { - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); item0.expansion.open(); tree.onKeydown(shift()); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0']); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); }); it('should not allow wrapping while Shift is held down', () => { @@ -828,7 +834,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(up({shift: true})); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should select a range of visible items on Shift + Space (or Enter)', () => { @@ -841,7 +847,7 @@ describe('Tree Pattern', () => { tree.onKeydown(down({control: true})); tree.onKeydown(shift()); tree.onKeydown(space({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); }); it('should select the focused item and all visible items up to the first on Ctrl + Shift + Home', () => { @@ -853,7 +859,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(home({control: true, shift: true})); - expect(tree.inputs.value()).toEqual(['Item 1', 'Item 0-1', 'Item 0-0', 'Item 0']); + expect(tree.inputs.values()).toEqual(['Item 1', 'Item 0-1', 'Item 0-0', 'Item 0']); }); it('should select the focused item and all visible items down to the last on Ctrl + Shift + End', () => { @@ -865,7 +871,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(end({control: true, shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); }); it('should not change selection when the tree is disabled', () => { @@ -873,7 +879,7 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should not select disabled items on navigation', () => { @@ -884,11 +890,11 @@ describe('Tree Pattern', () => { ]; treeInputs.softDisabled.set(false); const {tree, allItems} = createTree(localTreeData, treeInputs); - treeInputs.value.set(['A']); + treeInputs.values.set(['A']); tree.listBehavior.goto(getItemByValue(allItems(), 'A')); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual(['C']); + expect(tree.inputs.values()).toEqual(['C']); }); it('should not select non-selectable items on navigation', () => { @@ -898,12 +904,12 @@ describe('Tree Pattern', () => { {value: 'C', disabled: false, selectable: true}, ]; const {tree, allItems} = createTree(localTreeData, treeInputs); - treeInputs.value.set(['A']); + treeInputs.values.set(['A']); tree.listBehavior.goto(getItemByValue(allItems(), 'A')); tree.onKeydown(down()); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual(['C']); + expect(tree.inputs.values()).toEqual(['C']); }); it('should deselect all except the focused item on Ctrl + A if all are selected', () => { @@ -914,9 +920,15 @@ describe('Tree Pattern', () => { tree.listBehavior.goto(item0_0); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual([ + 'Item 0', + 'Item 0-0', + 'Item 0-1', + 'Item 1', + 'Item 2', + ]); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0-0']); }); }); }); @@ -937,7 +949,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -951,7 +963,7 @@ describe('Tree Pattern', () => { tree.onPointerdown(createClickEvent(item1.element()!)); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should not change selection when the tree is disabled', () => { @@ -960,7 +972,7 @@ describe('Tree Pattern', () => { const item1 = getItemByValue(allItems(), 'Item 1'); tree.onPointerdown(createClickEvent(item1.element()!)); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -979,7 +991,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -993,7 +1005,7 @@ describe('Tree Pattern', () => { tree.onPointerdown(createClickEvent(item1.element()!)); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should not deselect item on click', () => { @@ -1002,11 +1014,11 @@ describe('Tree Pattern', () => { tree.onPointerdown(createClickEvent(item1.element()!)); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); tree.onPointerdown(createClickEvent(item1.element()!)); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should not change selection when the tree is disabled', () => { @@ -1015,7 +1027,7 @@ describe('Tree Pattern', () => { const item1 = getItemByValue(allItems(), 'Item 1'); tree.onPointerdown(createClickEvent(item1.element()!)); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -1034,7 +1046,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -1048,13 +1060,13 @@ describe('Tree Pattern', () => { const item1 = getItemByValue(allItems(), 'Item 1'); tree.onPointerdown(createClickEvent(item0.element()!)); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); tree.onPointerdown(createClickEvent(item1.element()!)); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 1']); tree.onPointerdown(createClickEvent(item0.element()!)); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate and select range from anchor on shift + click', () => { @@ -1065,7 +1077,7 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onPointerdown(createClickEvent(item1.element()!, {shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1']); }); }); @@ -1084,7 +1096,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -1098,9 +1110,9 @@ describe('Tree Pattern', () => { const item1 = getItemByValue(allItems(), 'Item 1'); tree.onPointerdown(createClickEvent(item0.element()!)); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); tree.onPointerdown(createClickEvent(item1.element()!)); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate and toggle selection on ctrl + click', () => { @@ -1110,9 +1122,9 @@ describe('Tree Pattern', () => { tree.onPointerdown(createClickEvent(item0.element()!)); // Select and expand Item 0 tree.onPointerdown(createClickEvent(item1.element()!, {control: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 1']); tree.onPointerdown(createClickEvent(item0.element()!, {control: true})); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate and select range from anchor on shift + click', () => { @@ -1123,7 +1135,13 @@ describe('Tree Pattern', () => { tree.onPointerdown(createClickEvent(item0.element()!)); // Select and expand Item 0 tree.onKeydown(shift()); tree.onPointerdown(createClickEvent(item2.element()!, {shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual([ + 'Item 0', + 'Item 0-0', + 'Item 0-1', + 'Item 1', + 'Item 2', + ]); }); it('should select a new range on subsequent shift + clicks, deselecting previous range', () => { @@ -1135,10 +1153,10 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onPointerdown(createClickEvent(item1.element()!, {shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1']); tree.onPointerdown(createClickEvent(item0_0.element()!, {shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0']); }); it('should not select disabled items on click', () => { @@ -1149,7 +1167,7 @@ describe('Tree Pattern', () => { const itemA = getItemByValue(allItems(), 'A'); tree.onPointerdown(createClickEvent(itemA.element()!)); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); expect(tree.activeItem()).toBe(itemA); }); @@ -1160,7 +1178,7 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(localTreeData, treeInputs); const itemA = getItemByValue(allItems(), 'A'); tree.onPointerdown(createClickEvent(itemA.element()!)); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); }); @@ -1180,7 +1198,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -1373,7 +1391,7 @@ describe('Tree Pattern', () => { tree.onKeydown(right()); expect(tree.activeItem()).toBe(item0_0); - expect(tree.inputs.value()).toEqual(['Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0-0']); }); it('should navigate and select the parent on collapseKey if collapsed (vertical)', () => { @@ -1386,7 +1404,7 @@ describe('Tree Pattern', () => { tree.onKeydown(left()); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); }); @@ -1403,11 +1421,11 @@ describe('Tree Pattern', () => { const item0_0 = getItemByValue(allItems(), 'Item 0-0'); tree.listBehavior.goto(item0); item0.expansion.open(); - tree.inputs.value.set(['Item 1']); // pre-select something else + tree.inputs.values.set(['Item 1']); // pre-select something else tree.onKeydown(right({control: true})); expect(tree.activeItem()).toBe(item0_0); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate without select the parent on Ctrl + collapseKey if collapsed (vertical)', () => { @@ -1417,11 +1435,11 @@ describe('Tree Pattern', () => { const item0_0 = getItemByValue(allItems(), 'Item 0-0'); item0.expansion.open(); tree.listBehavior.goto(item0_0); - tree.inputs.value.set(['Item 1']); // pre-select something else + tree.inputs.values.set(['Item 1']); // pre-select something else tree.onKeydown(left({control: true})); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); }); }); @@ -1441,7 +1459,7 @@ describe('Tree Pattern', () => { softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -1478,7 +1496,7 @@ describe('Tree Pattern', () => { {value: 'B', disabled: false, selectable: true}, {value: 'C', disabled: false, selectable: true}, ]; - treeInputs.value.set(['B']); + treeInputs.values.set(['B']); const {tree, allItems} = createTree(localTreeData, treeInputs); tree.setDefaultState(); @@ -1491,7 +1509,7 @@ describe('Tree Pattern', () => { {value: 'B', disabled: false, selectable: true}, {value: 'C', disabled: false, selectable: true}, ]; - treeInputs.value.set(['C', 'A']); + treeInputs.values.set(['C', 'A']); const {tree, allItems} = createTree(localTreeData, treeInputs); tree.setDefaultState(); @@ -1504,7 +1522,7 @@ describe('Tree Pattern', () => { {value: 'B', disabled: true, selectable: true}, {value: 'C', disabled: false, selectable: true}, ]; - treeInputs.value.set(['B']); + treeInputs.values.set(['B']); treeInputs.softDisabled.set(false); const {tree, allItems} = createTree(localTreeData, treeInputs); @@ -1518,7 +1536,7 @@ describe('Tree Pattern', () => { {value: 'B', disabled: true, selectable: true}, {value: 'C', disabled: false, selectable: true}, ]; - treeInputs.value.set(['B']); + treeInputs.values.set(['B']); treeInputs.softDisabled.set(true); const {tree, allItems} = createTree(localTreeData, treeInputs); @@ -1529,7 +1547,7 @@ describe('Tree Pattern', () => { it('should set activeIndex to first visible focusable item if selected item is not visible', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - treeInputs.value.set(['Item 0-0']); + treeInputs.values.set(['Item 0-0']); expect(item0.expanded()).toBe(false); expect(getItemByValue(allItems(), 'Item 0-0').visible()).toBe(false); diff --git a/src/aria/private/tree/tree.ts b/src/aria/private/tree/tree.ts index eacc7326cef8..6ea5bc6df944 100644 --- a/src/aria/private/tree/tree.ts +++ b/src/aria/private/tree/tree.ts @@ -104,7 +104,7 @@ export class TreeItemPattern implements ListItem, ExpansionItem { if (!this.selectable()) { return undefined; } - return this.tree().value().includes(this.value()); + return this.tree().values().includes(this.value()); }); /** The current type of this item. */ @@ -115,7 +115,7 @@ export class TreeItemPattern implements ListItem, ExpansionItem { if (!this.selectable()) { return undefined; } - return this.tree().value().includes(this.value()) ? this.tree().currentType() : undefined; + return this.tree().values().includes(this.value()) ? this.tree().currentType() : undefined; }); constructor(readonly inputs: TreeItemInputs) { @@ -372,8 +372,8 @@ export class TreePattern { /** The delay in milliseconds to wait before clearing the typeahead buffer. */ typeaheadDelay: SignalLike; - /** The current value of the tree (the selected items). */ - value: WritableSignalLike; + /** The current selected items of the tree. */ + values: WritableSignalLike; constructor(readonly inputs: TreeInputs) { this.id = inputs.id; @@ -390,7 +390,7 @@ export class TreePattern { this.multi = computed(() => (this.nav() ? false : this.inputs.multi())); this.selectionMode = inputs.selectionMode; this.typeaheadDelay = inputs.typeaheadDelay; - this.value = inputs.value; + this.values = inputs.values; this.listBehavior = new List({ ...inputs, diff --git a/src/aria/tabs/tabs.ts b/src/aria/tabs/tabs.ts index 9fc4bf5ff096..5ca3c8372f15 100644 --- a/src/aria/tabs/tabs.ts +++ b/src/aria/tabs/tabs.ts @@ -182,7 +182,7 @@ export class TabList implements OnInit, OnDestroy { readonly _pattern: TabListPattern = new TabListPattern({ ...this, items: this.tabs, - value: this._selection, + values: this._selection, activeItem: signal(undefined), element: () => this._elementRef.nativeElement, }); diff --git a/src/aria/tree/tree.spec.ts b/src/aria/tree/tree.spec.ts index 41ec89568f40..9ab2c1d6daf0 100644 --- a/src/aria/tree/tree.spec.ts +++ b/src/aria/tree/tree.spec.ts @@ -75,7 +75,7 @@ describe('Tree', () => { function updateTree( config: { nodes?: TestTreeNode[]; - value?: string[]; + values?: string[]; disabled?: boolean; orientation?: 'horizontal' | 'vertical'; multi?: boolean; @@ -88,7 +88,7 @@ describe('Tree', () => { } = {}, ) { if (config.nodes !== undefined) testComponent.nodes.set(config.nodes); - if (config.value !== undefined) treeInstance.value.set(config.value); + if (config.values !== undefined) treeInstance.values.set(config.values); if (config.disabled !== undefined) testComponent.disabled.set(config.disabled); if (config.orientation !== undefined) testComponent.orientation.set(config.orientation); if (config.multi !== undefined) testComponent.multi.set(config.multi); @@ -149,7 +149,7 @@ describe('Tree', () => { click(berriesEl); const vegetablesEl = getTreeItemElementByValue('vegetables')!; click(vegetablesEl); - updateTree({value: []}); + updateTree({values: []}); } afterEach(async () => { @@ -282,7 +282,7 @@ describe('Tree', () => { it('should set aria-selected to "true" for selected items', () => { expandAll(); - updateTree({value: ['apple']}); + updateTree({values: ['apple']}); const appleItem = getTreeItemElementByValue('apple')!; expect(appleItem.getAttribute('aria-selected')).toBe('true'); @@ -299,7 +299,7 @@ describe('Tree', () => { it('should set aria-current to specific current type when nav="true"', () => { expandAll(); - updateTree({nav: true, value: ['apple']}); + updateTree({nav: true, values: ['apple']}); const appleItem = getTreeItemElementByValue('apple')!; const bananaItem = getTreeItemElementByValue('banana')!; @@ -312,7 +312,7 @@ describe('Tree', () => { it('should not set aria-current when not selectable', () => { expandAll(); - updateTree({nav: true, value: ['apple']}); + updateTree({nav: true, values: ['apple']}); const appleItem = getTreeItemElementByValue('apple')!; expect(appleItem.getAttribute('aria-current')).toBe('page'); @@ -323,7 +323,7 @@ describe('Tree', () => { it('should not set aria-selected when nav="true"', () => { expandAll(); - updateTree({value: ['apple'], nav: true}); + updateTree({values: ['apple'], nav: true}); const appleItem = getTreeItemElementByValue('apple')!; expect(appleItem.hasAttribute('aria-selected')).toBe(false); @@ -333,7 +333,7 @@ describe('Tree', () => { it('should not set aria-selected when not selectable', () => { expandAll(); - updateTree({value: ['apple']}); + updateTree({values: ['apple']}); const appleItem = getTreeItemElementByValue('apple')!; expect(appleItem.getAttribute('aria-selected')).toBe('true'); @@ -377,7 +377,7 @@ describe('Tree', () => { }); it('should set initial focus (tabindex="0") on the first selected item', () => { - updateTree({value: ['vegetables', 'dairy'], focusMode: 'roving'}); + updateTree({values: ['vegetables', 'dairy'], focusMode: 'roving'}); const fruitsItem = getTreeItemElementByValue('fruits')!; const vegetablesItem = getTreeItemElementByValue('vegetables')!; @@ -411,7 +411,7 @@ describe('Tree', () => { }); it('should set aria-activedescendant to the ID of the first selected item', () => { - updateTree({value: ['vegetables', 'dairy'], focusMode: 'activedescendant'}); + updateTree({values: ['vegetables', 'dairy'], focusMode: 'activedescendant'}); const vegetablesItem = getTreeItemElementByValue('vegetables')!; expect(treeElement.getAttribute('aria-activedescendant')).toBe(vegetablesItem.id); @@ -439,7 +439,7 @@ describe('Tree', () => { it('should select items based on the initial value input', () => { setupTestTree(); expandAll(); - updateTree({value: ['apple', 'strawberry', 'carrot']}); + updateTree({values: ['apple', 'strawberry', 'carrot']}); expect(getTreeItemElementByValue('apple')!.getAttribute('aria-selected')).toBe('true'); expect(getTreeItemElementByValue('strawberry')!.getAttribute('aria-selected')).toBe('true'); @@ -460,12 +460,12 @@ describe('Tree', () => { const bananaEl = getTreeItemElementByValue('banana')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); expect(appleEl.getAttribute('aria-selected')).toBe('true'); expect(bananaEl.getAttribute('aria-selected')).toBe('false'); click(bananaEl); - expect(treeInstance.value()).toEqual(['banana']); + expect(treeInstance.values()).toEqual(['banana']); expect(appleEl.getAttribute('aria-selected')).toBe('false'); expect(bananaEl.getAttribute('aria-selected')).toBe('true'); }); @@ -493,11 +493,11 @@ describe('Tree', () => { const carrotEl = getTreeItemElementByValue('carrot')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); expect(appleEl.getAttribute('aria-selected')).toBe('true'); shiftClick(carrotEl); - expect(treeInstance.value()).toEqual([ + expect(treeInstance.values()).toEqual([ 'apple', 'banana', 'berries', @@ -511,24 +511,24 @@ describe('Tree', () => { const bananaEl = getTreeItemElementByValue('banana')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); click(bananaEl); - expect(treeInstance.value()).toEqual(['apple', 'banana']); + expect(treeInstance.values()).toEqual(['apple', 'banana']); click(appleEl); - expect(treeInstance.value()).toEqual(['banana']); + expect(treeInstance.values()).toEqual(['banana']); }); describe('selectable=false', () => { it('should not select an item on click', () => { - updateTree({value: ['banana']}); + updateTree({values: ['banana']}); updateTreeItemByValue('apple', {selectable: false}); const appleEl = getTreeItemElementByValue('apple')!; click(appleEl); - expect(treeInstance.value()).not.toContain('apple'); - expect(treeInstance.value()).toContain('banana'); + expect(treeInstance.values()).not.toContain('apple'); + expect(treeInstance.values()).toContain('banana'); }); }); }); @@ -545,13 +545,13 @@ describe('Tree', () => { ctrlClick(appleEl); ctrlClick(bananaEl); - expect(treeInstance.value()).toEqual(['apple', 'banana']); + expect(treeInstance.values()).toEqual(['apple', 'banana']); click(carrotEl); - expect(treeInstance.value()).toEqual(['carrot']); + expect(treeInstance.values()).toEqual(['carrot']); click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); }); it('should add to selection with ctrl+click and toggle individual items', () => { @@ -559,13 +559,13 @@ describe('Tree', () => { const berriesEl = getTreeItemElementByValue('berries')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); ctrlClick(berriesEl); - expect(treeInstance.value()).toEqual(['apple', 'berries']); + expect(treeInstance.values()).toEqual(['apple', 'berries']); ctrlClick(appleEl); - expect(treeInstance.value()).toEqual(['berries']); + expect(treeInstance.values()).toEqual(['berries']); }); it('should select a range with shift+click, anchoring from last selected/focused', () => { @@ -575,10 +575,10 @@ describe('Tree', () => { const broccoliEl = getTreeItemElementByValue('broccoli')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); shiftClick(carrotEl); - expect(treeInstance.value()).toEqual([ + expect(treeInstance.values()).toEqual([ 'apple', 'banana', 'berries', @@ -587,10 +587,10 @@ describe('Tree', () => { ]); click(berriesEl); - expect(treeInstance.value()).toEqual(['berries']); + expect(treeInstance.values()).toEqual(['berries']); shiftClick(broccoliEl); - expect(treeInstance.value()).toEqual([ + expect(treeInstance.values()).toEqual([ 'berries', 'strawberry', 'blueberry', @@ -609,9 +609,9 @@ describe('Tree', () => { click(appleEl); shiftClick(berriesEl); - expect(treeInstance.value()).not.toContain('banana'); - expect(treeInstance.value()).toContain('apple'); - expect(treeInstance.value()).toContain('berries'); + expect(treeInstance.values()).not.toContain('banana'); + expect(treeInstance.values()).toContain('apple'); + expect(treeInstance.values()).toContain('berries'); }); it('should not toggle selection of an item on simple click', () => { @@ -619,17 +619,17 @@ describe('Tree', () => { const appleEl = getTreeItemElementByValue('apple')!; click(appleEl); - expect(treeInstance.value()).not.toContain('apple'); + expect(treeInstance.values()).not.toContain('apple'); }); it('should not add to selection with ctrl+click', () => { - updateTree({value: ['banana']}); + updateTree({values: ['banana']}); updateTreeItemByValue('apple', {selectable: false}); const appleEl = getTreeItemElementByValue('apple')!; ctrlClick(appleEl); - expect(treeInstance.value()).not.toContain('apple'); - expect(treeInstance.value()).toContain('banana'); + expect(treeInstance.values()).not.toContain('apple'); + expect(treeInstance.values()).toContain('banana'); }); }); }); @@ -650,47 +650,47 @@ describe('Tree', () => { it('should select the focused item with Enter and deselect others', () => { enter(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); enter(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); it('should select the focused item with Space and deselect others', () => { space(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); space(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); it('should move focus with arrows without changing selection until Enter/Space', () => { enter(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); enter(); - expect(treeInstance.value()).toEqual(['grains']); + expect(treeInstance.values()).toEqual(['grains']); }); describe('selectable=false', () => { it('should not select the focused item with Enter', () => { updateTreeItemByValue('fruits', {selectable: false}); enter(); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('should not select the focused item with Space', () => { updateTreeItemByValue('fruits', {selectable: false}); space(); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); }); }); @@ -701,45 +701,45 @@ describe('Tree', () => { }); it('should select an item when it becomes focused with ArrowDown and deselect others', () => { - updateTree({value: ['fruits']}); - expect(treeInstance.value()).toEqual(['fruits']); + updateTree({values: ['fruits']}); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); down(); - expect(treeInstance.value()).toEqual(['grains']); + expect(treeInstance.values()).toEqual(['grains']); }); it('should select an item when it becomes focused with ArrowUp and deselect others', () => { - updateTree({value: ['grains']}); + updateTree({values: ['grains']}); up(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); it('should select the first item with Home and deselect others', () => { - updateTree({value: ['grains']}); - expect(treeInstance.value()).toEqual(['grains']); + updateTree({values: ['grains']}); + expect(treeInstance.values()).toEqual(['grains']); home(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should select the last visible item with End and deselect others', () => { - updateTree({value: ['fruits']}); - expect(treeInstance.value()).toEqual(['fruits']); + updateTree({values: ['fruits']}); + expect(treeInstance.values()).toEqual(['fruits']); end(); - expect(treeInstance.value()).toEqual(['dairy']); + expect(treeInstance.values()).toEqual(['dairy']); }); it('should select an item via typeahead and deselect others', () => { - updateTree({value: ['fruits']}); - expect(treeInstance.value()).toEqual(['fruits']); + updateTree({values: ['fruits']}); + expect(treeInstance.values()).toEqual(['fruits']); type('V'); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); }); }); @@ -757,35 +757,35 @@ describe('Tree', () => { it('should toggle selection of the focused item with Space, leaving other selections intact', () => { space(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); space(); - expect(treeInstance.value().sort()).toEqual(['fruits', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'vegetables']); }); it('should move focus with arrows without changing selection', () => { space(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should extend selection downwards with Shift+ArrowDown', () => { shift(); down({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'vegetables']); down({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'grains', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'grains', 'vegetables']); }); it('should extend selection upwards with Shift+ArrowUp', () => { end(); shift(); up({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['dairy', 'grains']); + expect(treeInstance.values().sort()).toEqual(['dairy', 'grains']); }); it('Ctrl+A should select all enabled visible items, then deselect all', () => { @@ -799,7 +799,7 @@ describe('Tree', () => { updateTreeItemByValue('broccoli', {disabled: true}); keydown('A', {ctrlKey: true}); - expect(treeInstance.value().sort()).toEqual([ + expect(treeInstance.values().sort()).toEqual([ 'apple', 'banana', 'berries', @@ -810,25 +810,25 @@ describe('Tree', () => { ]); keydown('A', {ctrlKey: true}); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('Ctrl+ArrowKey should move focus without changing selection', () => { space(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); up({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); describe('selectable=false', () => { it('should not toggle selection of the focused item with Space', () => { updateTreeItemByValue('fruits', {selectable: false}); space(); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('should not extend selection with Shift+ArrowDown', () => { @@ -836,8 +836,8 @@ describe('Tree', () => { shift(); down({shiftKey: true}); down({shiftKey: true}); - expect(treeInstance.value()).not.toContain('vegetables'); - expect(treeInstance.value().sort()).toEqual(['fruits', 'grains']); + expect(treeInstance.values()).not.toContain('vegetables'); + expect(treeInstance.values().sort()).toEqual(['fruits', 'grains']); }); it('Ctrl+A should not select non-selectable items', () => { @@ -845,7 +845,7 @@ describe('Tree', () => { updateTreeItemByValue('apple', {selectable: false}); updateTreeItemByValue('carrot', {selectable: false}); keydown('A', {ctrlKey: true}); - const value = treeInstance.value(); + const value = treeInstance.values(); expect(value).not.toContain('apple'); expect(value).not.toContain('carrot'); expect(value).toContain('banana'); @@ -860,98 +860,98 @@ describe('Tree', () => { }); it('should select the focused item and deselect others on ArrowDown', () => { - updateTree({value: ['fruits']}); - expect(treeInstance.value()).toEqual(['fruits']); + updateTree({values: ['fruits']}); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); it('should select the focused item and deselect others on ArrowUp', () => { - updateTree({value: ['vegetables']}); - expect(treeInstance.value()).toEqual(['vegetables']); + updateTree({values: ['vegetables']}); + expect(treeInstance.values()).toEqual(['vegetables']); up(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should move focus without changing selection on Ctrl+ArrowDown', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); expect(getFocusedTreeItemValue()).toBe('fruits'); down({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); expect(getFocusedTreeItemValue()).toBe('vegetables'); }); it('should move focus without changing selection on Ctrl+ArrowUp', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); down({ctrlKey: true}); expect(getFocusedTreeItemValue()).toBe('vegetables'); up({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); expect(getFocusedTreeItemValue()).toBe('fruits'); }); it('should toggle selection of the focused item on Ctrl+Space, adding to existing selection', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); down({ctrlKey: true}); expect(getFocusedTreeItemValue()).toBe('vegetables'); space({ctrlKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'vegetables']); space({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should toggle selection of the focused item on Ctrl+Enter, adding to existing selection', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); down({ctrlKey: true}); expect(getFocusedTreeItemValue()).toBe('vegetables'); enter({ctrlKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'vegetables']); enter({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should extend selection downwards with Shift+ArrowDown', () => { right(); // Expands fruits - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); shift(); down({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['apple', 'fruits']); + expect(treeInstance.values().sort()).toEqual(['apple', 'fruits']); down({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['apple', 'banana', 'fruits']); + expect(treeInstance.values().sort()).toEqual(['apple', 'banana', 'fruits']); }); it('should extend selection upwards with Shift+ArrowUp', () => { - updateTree({value: ['grains']}); + updateTree({values: ['grains']}); shift(); up({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['grains', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['grains', 'vegetables']); up({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'grains', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'grains', 'vegetables']); }); it('should select a range with Shift+Space, anchoring from last selected/focused item', () => { right(); // Expands fruits - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); down({ctrlKey: true}); down({ctrlKey: true}); expect(getFocusedTreeItemValue()).toBe('banana'); space({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['apple', 'banana', 'fruits']); + expect(treeInstance.values().sort()).toEqual(['apple', 'banana', 'fruits']); }); it('Ctrl+A: select all enabled visible items; second Ctrl+A deselects all except focused', () => { @@ -959,7 +959,7 @@ describe('Tree', () => { updateTreeItemByValue('vegetables', {disabled: true}); keydown('A', {ctrlKey: true}); - expect(treeInstance.value().sort()).toEqual([ + expect(treeInstance.values().sort()).toEqual([ 'apple', 'banana', 'berries', @@ -969,13 +969,13 @@ describe('Tree', () => { ]); keydown('A', {ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('typeahead should select the focused item and deselect others', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); type('V'); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); expect(getFocusedTreeItemValue()).toBe('vegetables'); }); @@ -983,14 +983,14 @@ describe('Tree', () => { it('should not select an item on ArrowDown', () => { updateTreeItemByValue('vegetables', {selectable: false}); down(); - expect(treeInstance.value()).not.toContain('vegetables'); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).not.toContain('vegetables'); + expect(treeInstance.values()).toEqual([]); }); it('should not toggle selection of the focused item on Ctrl+Space', () => { updateTreeItemByValue('fruits', {selectable: false}); space({ctrlKey: true}); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('should not extend selection with Shift+ArrowDown', () => { @@ -998,38 +998,38 @@ describe('Tree', () => { shift(); down({shiftKey: true}); down({shiftKey: true}); - expect(treeInstance.value()).not.toContain('vegetables'); - expect(treeInstance.value().sort()).toEqual(['fruits', 'grains']); + expect(treeInstance.values()).not.toContain('vegetables'); + expect(treeInstance.values().sort()).toEqual(['fruits', 'grains']); }); it('typeahead should not select the focused item', () => { updateTreeItemByValue('vegetables', {selectable: false}); type('v'); expect(getFocusedTreeItemValue()).toBe('vegetables'); - expect(treeInstance.value()).not.toContain('vegetables'); + expect(treeInstance.values()).not.toContain('vegetables'); }); }); it('should not select disabled items during Shift+ArrowKey navigation even if softDisabled is true', () => { right(); // Expands fruits updateTreeItemByValue('banana', {disabled: true}); - updateTree({value: ['apple'], softDisabled: true}); + updateTree({values: ['apple'], softDisabled: true}); expect(getFocusedTreeItemValue()).toBe('apple'); keydown('Shift'); down({shiftKey: true}); expect(getFocusedTreeItemValue()).toBe('banana'); - expect(treeInstance.value().sort()).toEqual(['apple']); + expect(treeInstance.values().sort()).toEqual(['apple']); down({shiftKey: true}); // Focus 'berries' expect(getFocusedTreeItemValue()).toBe('berries'); - expect(treeInstance.value().sort()).toEqual(['apple', 'berries']); + expect(treeInstance.values().sort()).toEqual(['apple', 'berries']); }); it('should not change selection if tree is disabled', () => { - updateTree({value: ['fruits'], disabled: true}); + updateTree({values: ['fruits'], disabled: true}); down(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); }); }); @@ -1416,14 +1416,14 @@ describe('Tree', () => { updateTree({selectionMode: 'follow'}); type('Gr'); expect(isFocused('grains')).toBe(true); - expect(treeInstance.value()).toEqual(['grains']); + expect(treeInstance.values()).toEqual(['grains']); }); it('should not select the focused item if selectionMode is "explicit"', () => { updateTree({selectionMode: 'explicit'}); type('Gr'); expect(isFocused('grains')).toBe(true); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('should skip disabled items with typeahead if softDisabled=false', () => { @@ -1465,7 +1465,7 @@ interface TestTreeNode { [softDisabled]="softDisabled()" [orientation]="orientation()" [disabled]="disabled()" - [(value)]="value" + [(values)]="values" [nav]="nav()" [currentType]="currentType()" #tree="ngTree" @@ -1533,7 +1533,7 @@ class TestTreeComponent { {value: 'grains', label: 'Grains'}, {value: 'dairy', label: 'Dairy'}, ]); - value = signal([]); + values = signal([]); disabled = signal(false); orientation = signal<'vertical' | 'horizontal'>('vertical'); multi = signal(false); diff --git a/src/aria/tree/tree.ts b/src/aria/tree/tree.ts index 6b876da5263c..52a037258766 100644 --- a/src/aria/tree/tree.ts +++ b/src/aria/tree/tree.ts @@ -52,7 +52,7 @@ function sortDirectives(a: HasElement, b: HasElement) { * Transforms nested lists into an accessible, ARIA-compliant tree structure. * * ```html - *
          + *
            *
          • Leaf Item 1
          • *
          • * Parent Item 1 @@ -129,7 +129,7 @@ export class Tree { readonly typeaheadDelay = input(0.5); /** Selected item values. */ - readonly value = model([]); + readonly values = model([]); /** Text direction. */ readonly textDirection = inject(Directionality).valueSignal; @@ -185,10 +185,10 @@ export class Tree { afterRenderEffect(() => { const items = inputs.allItems(); - const value = untracked(() => this.value()); + const values = untracked(() => this.values()); - if (items && value.some(v => !items.some(i => i.value() === v))) { - this.value.set(value.filter(v => items.some(i => i.value() === v))); + if (items && values.some(v => !items.some(i => i.value() === v))) { + this.values.set(values.filter(v => items.some(i => i.value() === v))); } }); } diff --git a/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.html b/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.html index 4a8d62f95840..67eae7296522 100644 --- a/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.html +++ b/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.html @@ -30,7 +30,7 @@
-
+
@for (option of options(); track option) {
{{option}} diff --git a/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.html b/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.html index f39e842e284e..e979b8fb8fd3 100644 --- a/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.html +++ b/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.html @@ -52,7 +52,7 @@
    -
    +
    @for (option of options; track option) {
    {{option}} diff --git a/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.html b/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.html index 341e8ed26e6b..6c69e1d210b3 100644 --- a/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.html +++ b/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.html @@ -36,7 +36,7 @@ [wrap]="wrap.value" [softDisabled]="softDisabled.value" [nav]="nav.value" - [(value)]="selectedValues" + [(values)]="selectedValues" #tree="ngTree" >