Bug 1692730 [wpt PR 27623] - Introduce <selectmenu> with basic shadow structure and some controller code, a=testonly

Automatic update from web-platform-tests
Introduce <selectmenu> with basic shadow structure and some controller code

Begin implementing the <selectmenu> element, a version of <select> with
a fully author-customizable UI.

See https://groups.google.com/u/1/a/chromium.org/g/blink-dev/c/9TcfjaOs5zg/m/WAiv6WpUAAAJ
and associated links for additional context.

Establish the basic shadow DOM structure, with a button (which
includes an arrow icon and a container to show the value), and
a listbox based on <popup>.  There are <slot> elements to add
<option>s to the popup and replace any of the default parts.

Include some basic styles. The default button part looks something
like the native <select>, but the default listbox will need more
work to improve its appearance.

Add basic controller code using NativeEventListeners. Clicking
the button part opens the listbox <popup>, and the value property
and text shown in the button are updated when an option is clicked.
This controller code is applied to the default parts and to
author-supplied parts that are included via the <slot>s.

Add tests to validate some basic scenarios involving the
controller code. Note, a couple of the
selectmenu-value.tentative.html
tests fail because updates to the value property are not yet
synchronous (should they be?).

There are many TODOs and open questions to investigate, but
this change establishes a starting point for exploring
an approach to customizable form controls.

Bug: 1121840
Change-Id: I68c0513b0e30813cbaa3b69fc2acb9086c7400ba
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2693857
Commit-Queue: Dan Clark <daniec@microsoft.com>
Reviewed-by: Mason Freed <masonfreed@chromium.org>
Reviewed-by: Ionel Popescu <iopopesc@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#855581}

--

wpt-commits: 6ba9b6bb71afb574b48982a6bffee37051b833f6
wpt-pr: 27623
This commit is contained in:
Daniel Clark 2021-02-22 21:53:46 +00:00 коммит произвёл moz-wptsync-bot
Родитель 24620776d1
Коммит bef884ebfd
2 изменённых файлов: 203 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,76 @@
<!DOCTYPE html>
<title>HTMLSelectMenuElement Test: popup</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<selectmenu id="selectMenu0">
<option>one</option>
<option id="selectMenu0-child2">two</option>
<div id="selectMenu0-child3">I'm a div with no part attr</div>
<option>three</option>
<option>four</option>
</selectmenu>
<selectmenu id="selectMenu1">
<div slot="button" part="button" id="selectMenu1-button">
Custom button
</div>
<popup slot="listbox" part="listbox">
<option>one</option>
<option id="selectMenu1-child2">two</option>
<div part="option" id="selectMenu1-child3">three</div>
</popup>
</selectmenu>
<selectmenu id="selectMenu2">
<!-- Swap out the listbox part without providing a replacement -->
<div slot="listbox"></div>
</selectmenu>
<script>
function clickOn(element) {
const actions = new test_driver.Actions();
return actions.pointerMove(0, 0, {origin: element})
.pointerDown({button: actions.ButtonType.LEFT})
.pointerUp({button: actions.ButtonType.LEFT})
.send();
}
promise_test(async () => {
const selectMenu0 = document.getElementById("selectMenu0");
const selectMenu0Child2 = document.getElementById("selectMenu0-child2");
const selectMenu0Child3 = document.getElementById("selectMenu0-child3");
assert_equals(selectMenu0.value, "one");
await clickOn(selectMenu0);
await clickOn(selectMenu0Child2);
assert_equals(selectMenu0.value, "two");
await clickOn(selectMenu0);
await clickOn(selectMenu0Child3);
assert_equals(selectMenu0.value, "two", "Clicking a non-option should not change the value");
}, "Opening the popup and clicking an option should change the selectmenu's value");
promise_test(async () => {
const selectMenu1 = document.getElementById("selectMenu1");
const selectMenu1Button = document.getElementById("selectMenu1-button");
const selectMenu1Child2 = document.getElementById("selectMenu1-child2");
const selectMenu1Child3 = document.getElementById("selectMenu1-child3");
assert_equals(selectMenu1.value, "one");
await clickOn(selectMenu1Button);
await clickOn(selectMenu1Child2);
assert_equals(selectMenu1.value, "two", "Clicking an <option> should change the value");
await clickOn(selectMenu1Button);
await clickOn(selectMenu1Child3);
assert_equals(selectMenu1.value, "three", "Clicking a <div part='option'> should change the value");
}, "With custom button and popup: opening the popup and clicking an option should change the selectmenu's value");
promise_test(async () => {
const selectMenu2 = document.getElementById("selectMenu2");
await clickOn(selectMenu2);
assert_equals(selectMenu2.value, "");
}, "Clicking a popup with no listbox part does nothing");
</script>

Просмотреть файл

@ -0,0 +1,127 @@
<!DOCTYPE html>
<title>HTMLSelectMenuElement Test: value</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<selectmenu id="selectMenu0"></selectmenu>
<selectmenu id="selectMenu1">
<option>one</option>
<option>two</option>
<div>I'm a div with no part attr</div>
<option>three</option>
<option>four</option>
</selectmenu>
<selectmenu id="selectMenu2">
<div part="option">one</div>
<div part="option">two</div>
<div>I'm a div with no part attr</div>
<div part="option">three</div>
<div part="option">four</div>
</selectmenu>
<selectmenu id="selectMenu3">
<div>I'm a div with no part attr</div>
<option id="selectMenu3-child1">one</option>
<div part="option" id="selectMenu3-child2">two</div>
<option id="selectMenu3-child3">three</option>
</selectmenu>
<selectmenu id="selectMenu4">
<div part="option" id="selectMenu4-child1">two</div>
<div part="option" id="selectMenu4-child2">two</div>
</selectmenu>
<selectmenu id="selectMenu5">
<div slot="button" part="button">
<div part="selected-value" id="selectMenu5-custom-selected-value">Default custom selected-value text</div>
</div>
<option>one</option>
<option>two</option>
</selectmenu>
<selectmenu id="selectMenu6">
<div slot="button" part="button">
<div part="selected-value" id="selectMenu6-custom-selected-value">Default custom selected-value text</div>
</div>
<popup slot="listbox" part="listbox">
<option>one</option>
<div part="option">two</div>
</popup>
</selectmenu>
<script>
test(() => {
const selectMenu0 = document.getElementById("selectMenu0");
assert_equals(selectMenu0.value, "");
selectMenu0.value = "something";
assert_equals(selectMenu0.value, "", "Setting value should have no effect if there is no matching option");
}, "Test that HTMLSelectMenu with no options has empty string for value");
test(() => {
const selectMenu1 = document.getElementById("selectMenu1");
assert_equals(selectMenu1.value, "one", "value should start with the text of the first option part");
selectMenu1.value = "three";
assert_equals(selectMenu1.value, "three", "value can be set to the text of an option part");
selectMenu1.value = "I'm a div with no part attr";
assert_equals(selectMenu1.value, "three", "Setting value should have no effect if there is no matching option");
}, "Test value with HTMLOptionElement element option parts");
test(() => {
const selectMenu2 = document.getElementById("selectMenu2");
assert_equals(selectMenu2.value, "one", "value should start with the text of the first option part");
selectMenu2.value = "three";
assert_equals(selectMenu2.value, "three", "value can be set to the text of an option part");
selectMenu2.value = "I'm a div with no part attr";
assert_equals(selectMenu2.value, "three", "Setting value should have no effect if there is no matching option");
}, "Test value with non-HTMLOptionElement element option parts");
test(() => {
const selectMenu3 = document.getElementById("selectMenu3");
assert_equals(selectMenu3.value, "one", "value should start with the text of the first option part");
document.getElementById("selectMenu3-child3").remove();
assert_equals(selectMenu3.value, "one", "Removing a non-selected option should not change the value");
document.getElementById("selectMenu3-child1").remove();
assert_equals(selectMenu3.value, "two", "When the selected option is removed, the new first option should become selected");
document.getElementById("selectMenu3-child2").remove();
assert_equals(selectMenu3.value, "", "When all options are removed, value should be the empty string");
}, "Test that value is updated when options are removed");
test(() => {
const selectMenu4 = document.getElementById("selectMenu4");
assert_equals(selectMenu4.value, "one", "value should start with the text of the first option part");
document.getElementById("selectMenu4-child1").setAttribute("part", "notOption");
assert_equals(selectMenu4.value, "two", "Changing the part attribute of the selected option should remove its status as the selected option");
}, "Test that value is updated when the part attribute is removed");
test(() => {
const selectMenu5 = document.getElementById("selectMenu5");
let customSelectedValuePart = document.getElementById("selectMenu5-custom-selected-value");
assert_equals(selectMenu5.value, "one", "value should start with the text of the first option part");
assert_equals(customSelectedValuePart.innerText, "one", "Custom selected value part should be set to initial value of selectmenu");
selectMenu5.value = "two";
assert_equals(customSelectedValuePart.innerText, "two", "Custom selected value part should be updated when value of selectmenu changes");
}, "Test that slotted-in selected-value part is updated to value of selectmenu");
test(() => {
const selectMenu6 = document.getElementById("selectMenu6");
let customSelectedValuePart = document.getElementById("selectMenu6-custom-selected-value");
assert_equals(selectMenu6.value, "one", "value should start with the text of the first option part");
assert_equals(customSelectedValuePart.innerText, "one", "Custom selected value part should be set to initial value of selectmenu");
selectMenu6.value = "two";
assert_equals(customSelectedValuePart.innerText, "two", "Custom selected value part should be updated when value of selectmenu changes");
}, "Test that option parts in a slotted-in listbox are reflected in the value property");
</script>