Skip to content

Commit

Permalink
fix(combobox): add combobox pattern (#3894)
Browse files Browse the repository at this point in the history
* feat(combobox): begin working branch for combobox additions

* feat(combobox): add size attribute (#3887)

* feat(combobox): wip

* chore: update sizes and stories

* chore: add isoverlayopen decorator to stories

---------

Co-authored-by: Westbrook Johnson <westbrook.johnson@gmail.com>
Co-authored-by: Najika Yoo <naj.halsema@gmail.com>

* chore: add benchmark test for lightdom combobox (#3898)

* chore: add benchmark test for lightdom combobox

* chore: add object version of benchmark test

* chore: rename files

---------

Co-authored-by: Najika Yoo <naj.halsema@gmail.com>

* test(combobox): update data management tests for current API

* test(combobox): get more tests passing and skip tests that will be visited in future work (#3919)

* test(combobox): get more tests passing and skip tests that will be visited in future work

* ci: update golden images cache

* test(combobox): ignore Combobox Item code

* chore(combobox): cleanup unused code (#3922)

* chore(combobox): cleanup unused code

* ci: update golden images cache

* fix(combobox): add support for external tooltip elements (#3930)

* fix(combobox): add support for external tooltip elements

* chore(combobox): remove unused code paths

* ci: update golden images cache

* docs(combobox): include slot present in API docs

* fix(combobox): allow intern Menu to hold a selection when autocomplete === "none" (#3951)

* test(combobox): add accessibility tests (#3953)

* chore: add labels to combobox input

* chore: get tests passing

* test(combobox): get a11y tests passing

* chore: remove unused positionlistbox method

* test: get tests passing, change spelling of activeDescendant

* chore: missed some descendents

* chore: add help text demo and test

* ci: update hash

* chore: address review comments

* chore: abstract shared data to index files

* test(combobox): update tests and stories to use legible data

* ci: update hash

* chore: label menu and rename stories

* ci: update hash

---------

Co-authored-by: Najika Yoo <naj.halsema@gmail.com>

* test(combobox): fulfil accessibility contract (#3974)

* chore: add tooltip to ariadescribedby

* test(combobox): add a11y test for tooltip

---------

Co-authored-by: Najika Yoo <naj.halsema@gmail.com>

* chore(bundle): include combobox

* chore(combobox): clean up property availability and types

* chore(combobox): clean up property availability and type

* refactor(combobox): update ComboboxOption type

* ci: update golden images cache

* refactor(combobox): simplify typing and correct query location when moving items into viewport

* docs: use human useful content in stories

* ci: update golden images cache

* refactor(combobox): default "autocomplete" to "none"

* docs: correct story configuration

* docs(combobox): create initial documentation

* docs(combobox): apply docs feedback

* docs(combobox): use only working examples in live mode

* fix(combobox): maintain focus on input element when toggling menu

* docs(combobox): improve clarity

* ci: update golden images cache

* docs(combobox): add story demonstrating controlled-component usage (#3988)

* docs(combobox): add story demonstrating controlled-component usage

* Update packages/combobox/stories/combobox.stories.ts

Co-authored-by: Westbrook Johnson <wesjohns@adobe.com>

---------

Co-authored-by: Westbrook Johnson <wesjohns@adobe.com>

* fix(combobox): add support for "readonly" and "disabled"

* docs(textfield): expand on attribute/property descriptions

* fix(combobox): add support for "readonly" and "disabled"

* ci: update golden images cache

* fix(textfield): prevent outline on :focus-visible elements that are disabled

* fix(combobox): correct value to itemText interchange when something is "selected" (#3994)

---------

Co-authored-by: Najika Halsema Yoo <44980010+najikahalsema@users.noreply.github.com>
Co-authored-by: Najika Yoo <naj.halsema@gmail.com>
Co-authored-by: Hunter Loftis <hunter@hunterloftis.com>
  • Loading branch information
4 people committed Feb 2, 2024
1 parent d42bb71 commit 47d7d71
Show file tree
Hide file tree
Showing 38 changed files with 4,776 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ executors:
parameters:
current_golden_images_hash:
type: string
default: 0ee048a172d6cdf6f7b82def40e024f69c8abb6b
default: 3f18b907cc7ccfebda57963ffe10e1c132c17761
wireit_cache_name:
type: string
default: wireit
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@
"tools/**/*.ts",
"!tools/**/*.d.ts",
"tasks/esbuild-packages.js",
"tasks/ts-tools.js"
"tasks/ts-tools.js",
"packages/**/exports.json",
"tools/**/exports.json"
],
"output": [
"packages/**/*.js",
Expand Down
162 changes: 162 additions & 0 deletions packages/combobox/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
## Description

An `<sp-combobox>` allows users to filter lists to only the options matching a query. It's composed of a textfield, a picker button, and child menu items.

### Usage

[![See it on NPM!](https://img.shields.io/npm/v/@spectrum-web-components/combobox?style=for-the-badge)](https://www.npmjs.com/package/@spectrum-web-components/combobox)
[![How big is this package in your project?](https://img.shields.io/bundlephobia/minzip/@spectrum-web-components/combobox?style=for-the-badge)](https://bundlephobia.com/result?p=@spectrum-web-components/combobox)

```
yarn add @spectrum-web-components/combobox
```

Import the side effectful registration of `<sp-combobox>` via:

```
import '@spectrum-web-components/combobox/sp-combobox.js';
```

When looking to leverage the `Combobox` base class as a type and/or for extension purposes, do so via:

```
import { Combobox } from '@spectrum-web-components/combobox';
```

## Sizes

<sp-tabs selected="m" auto label="Size Attribute Options">
<sp-tab value="s">Small</sp-tab>
<sp-tab-panel value="s">

```html
<sp-combobox size="s" label="Color">
<sp-menu-item value="red">Red</sp-menu-item>
<sp-menu-item value="green">Green</sp-menu-item>
<sp-menu-item value="blue">Blue</sp-menu-item>
</sp-combobox>
```

</sp-tab-panel>
<sp-tab value="m">Medium</sp-tab>
<sp-tab-panel value="m">

```html
<sp-combobox size="m" label="Color">
<sp-menu-item value="red">Red</sp-menu-item>
<sp-menu-item value="green">Green</sp-menu-item>
<sp-menu-item value="blue">Blue</sp-menu-item>
</sp-combobox>
```

</sp-tab-panel>
<sp-tab value="l">Large</sp-tab>
<sp-tab-panel value="l">

```html
<sp-combobox size="l" label="Color">
<sp-menu-item value="red">Red</sp-menu-item>
<sp-menu-item value="green">Green</sp-menu-item>
<sp-menu-item value="blue">Blue</sp-menu-item>
</sp-combobox>
```

</sp-tab-panel>
<sp-tab value="xl">Extra Large</sp-tab>
<sp-tab-panel value="xl">

```html
<sp-combobox size="xl" label="Color">
<sp-menu-item value="red">Red</sp-menu-item>
<sp-menu-item value="green">Green</sp-menu-item>
<sp-menu-item value="blue">Blue</sp-menu-item>
</sp-combobox>
```

</sp-tab-panel>
</sp-tabs>

## Labeling

A combobox must be labeled.
Typically, you should render a visible label via `<sp-field-label>`.
For exceptional cases, provide an accessible label via the `label` attribute.

```html
<sp-field-label for="color">Color</sp-field-label>
<sp-combobox id="color">
<sp-menu-item value="red">Red</sp-menu-item>
<sp-menu-item value="green">Green</sp-menu-item>
<sp-menu-item value="blue">Blue</sp-menu-item>
</sp-combobox>
```

## Providing options

Combobox options are presented as a popup menu.
Menu items can be provided via markup as `<sp-menu-item>` children, or by assigning an array to the `options` property of an `<sp-combobox>`.

### Options property

Instead of providing `<sp-menu-item>` children, you can assign an array of `ComboboxOptions` to the `options` property, and `<sp-combobox>` will create matching menu items:

```html-no-demo
<sp-combobox id="color" label="Color"></sp-combobox>
<script>
document.getElementById('color').options = [
{ value: "red", itemText: "Red" },
{ value: "green", itemText: "Green" },
{ value: "blue", itemText: "Blue" }
];
</script>
```

### Dynamic options

When you replace the `options` Array, or add/remove `<sp-menu-item>` children, the `<sp-combobox>` will detect that change and update its popup menu contents.
For example, using [Lit](https://lit.dev/):

```ts
render() {
return html`<sp-combobox label="Color" .options=${this.colorOptions}></sp-combobox>`;
}

mutate() {
this.colorOptions = [
...this.colorOptions,
{ value: 'purple', itemText: 'Purple' }
];
}
```

## Autocomplete

The text in an `<sp-combobox>` is editable, and the string the user has typed in will become the `value` of the combobox unless the user selects a different value in the popup menu.

### None

`autocomplete="none"`

The suggested popup menu items will remain the same regardless of the currently-input value.
Whenever the currently-typed input exactly matches the `value` of a popup menu item, that item is automatically selected.

### List

`autocomplete="list"`

The popup menu items are filtered to only those completing the currently-input value.

## Focus and Accessibility

The combobox supports both mouse and keyboard navigation.
Mobile behavior is currently unspecified.

When an `<sp-combobox>` is focused, pressing the down arrow moves focus to the first menu item in the popup menu.
The up and down arrows then move between available menu items.

The escape key dismisses the popup menu if open.
Otherwise, it clears the combobox's textfield.

The enter key sets the `value` of the focused `<sp-combobox>`.
If the popup menu is open, the value is set to the `value` of the selected menu item, returning focus back to the combobox's textfield.
4 changes: 4 additions & 0 deletions packages/combobox/exports.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"./src/*": "./src/*",
"./sp-combobox.js": "./sp-combobox.js"
}
77 changes: 77 additions & 0 deletions packages/combobox/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"name": "@spectrum-web-components/combobox",
"version": "0.0.1",
"publishConfig": {
"access": "public"
},
"description": "",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/adobe/spectrum-web-components.git",
"directory": "packages/combobox"
},
"author": "",
"homepage": "https://adobe.github.io/spectrum-web-components/components/combobox",
"bugs": {
"url": "https://github.com/adobe/spectrum-web-components/issues"
},
"main": "src/index.js",
"module": "src/index.js",
"type": "module",
"exports": {
".": {
"development": "./src/index.dev.js",
"default": "./src/index.js"
},
"./package.json": "./package.json",
"./src/Combobox.js": {
"development": "./src/Combobox.dev.js",
"default": "./src/Combobox.js"
},
"./src/combobox.css.js": "./src/combobox.css.js",
"./src/index.js": {
"development": "./src/index.dev.js",
"default": "./src/index.js"
},
"./sp-combobox.js": {
"development": "./sp-combobox.dev.js",
"default": "./sp-combobox.js"
}
},
"scripts": {
"test": "echo \"Error: run tests from mono-repo root.\" && exit 1"
},
"files": [
"*.d.ts",
"*.js",
"*.js.map",
"/src/",
"custom-elements.json"
],
"keywords": [
"spectrum css",
"web components",
"lit-element",
"lit-html"
],
"dependencies": {
"@spectrum-web-components/action-button": "^0.40.1",
"@spectrum-web-components/base": "^0.40.1",
"@spectrum-web-components/icon": "^0.40.1",
"@spectrum-web-components/icons-ui": "^0.40.1",
"@spectrum-web-components/menu": "^0.40.1",
"@spectrum-web-components/overlay": "^0.40.1",
"@spectrum-web-components/picker-button": "^0.40.1",
"@spectrum-web-components/popover": "^0.40.1",
"@spectrum-web-components/textfield": "^0.40.1"
},
"devDependencies": {
"@spectrum-css/combobox": "^2.0.46"
},
"types": "./src/index.d.ts",
"sideEffects": [
"./sp-*.js",
"./sp-*.ts"
]
}
21 changes: 21 additions & 0 deletions packages/combobox/sp-combobox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

import { Combobox } from './src/Combobox.js';

customElements.define('sp-combobox', Combobox);

declare global {
interface HTMLElementTagNameMap {
'sp-combobox': Combobox;
}
}
Loading

0 comments on commit 47d7d71

Please sign in to comment.