@zendeskgarden/react-dropdowns 9.0.0-next.0 → 9.0.0-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -69
- package/dist/esm/context/useComboboxContext.js +18 -0
- package/dist/esm/context/useFieldContext.js +18 -0
- package/dist/esm/context/useItemContext.js +18 -0
- package/dist/esm/context/useItemGroupContext.js +14 -0
- package/dist/esm/context/useMenuContext.js +18 -0
- package/dist/esm/context/useOptionContext.js +18 -0
- package/dist/esm/elements/combobox/Combobox.js +330 -0
- package/dist/esm/elements/combobox/Field.js +75 -0
- package/dist/esm/elements/combobox/Hint.js +57 -0
- package/dist/esm/elements/combobox/Label.js +68 -0
- package/dist/esm/elements/combobox/Listbox.js +155 -0
- package/dist/esm/elements/combobox/Message.js +63 -0
- package/dist/esm/elements/combobox/OptGroup.js +93 -0
- package/dist/esm/elements/combobox/Option.js +133 -0
- package/dist/esm/elements/combobox/OptionMeta.js +55 -0
- package/dist/esm/elements/combobox/Tag.js +98 -0
- package/dist/esm/elements/combobox/TagAvatar.js +13 -0
- package/dist/esm/elements/combobox/TagGroup.js +35 -0
- package/dist/esm/elements/combobox/utils.js +36 -0
- package/dist/esm/elements/menu/Item.js +140 -0
- package/dist/esm/elements/menu/ItemGroup.js +96 -0
- package/dist/esm/elements/menu/ItemMeta.js +55 -0
- package/dist/esm/elements/menu/Menu.js +157 -0
- package/dist/esm/elements/menu/MenuList.js +170 -0
- package/dist/esm/elements/menu/Separator.js +58 -0
- package/dist/esm/elements/menu/utils.js +55 -0
- package/dist/esm/index.js +19 -0
- package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/check-lg-stroke.svg.js +28 -0
- package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/chevron-down-stroke.svg.js +25 -0
- package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/chevron-left-stroke.svg.js +25 -0
- package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/chevron-right-stroke.svg.js +25 -0
- package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/plus-stroke.svg.js +26 -0
- package/dist/esm/types/index.js +12 -0
- package/dist/esm/views/combobox/StyledCombobox.js +30 -0
- package/dist/esm/views/combobox/StyledContainer.js +22 -0
- package/dist/esm/views/combobox/StyledField.js +22 -0
- package/dist/esm/views/combobox/StyledFloatingListbox.js +27 -0
- package/dist/esm/views/combobox/StyledHint.js +23 -0
- package/dist/esm/views/combobox/StyledInput.js +41 -0
- package/dist/esm/views/combobox/StyledInputGroup.js +26 -0
- package/dist/esm/views/combobox/StyledInputIcon.js +43 -0
- package/dist/esm/views/combobox/StyledLabel.js +23 -0
- package/dist/esm/views/combobox/StyledListbox.js +31 -0
- package/dist/esm/views/combobox/StyledListboxSeparator.js +31 -0
- package/dist/esm/views/combobox/StyledMessage.js +23 -0
- package/dist/esm/views/combobox/StyledOptGroup.js +22 -0
- package/dist/esm/views/combobox/StyledOption.js +48 -0
- package/dist/esm/views/combobox/StyledOptionContent.js +22 -0
- package/dist/esm/views/combobox/StyledOptionIcon.js +29 -0
- package/dist/esm/views/combobox/StyledOptionMeta.js +31 -0
- package/dist/esm/views/combobox/StyledOptionTypeIcon.js +48 -0
- package/dist/esm/views/combobox/StyledTag.js +24 -0
- package/dist/esm/views/combobox/StyledTagsButton.js +28 -0
- package/dist/esm/views/combobox/StyledTrigger.js +94 -0
- package/dist/esm/views/combobox/StyledValue.js +32 -0
- package/dist/esm/views/menu/StyledButton.js +23 -0
- package/dist/esm/views/menu/StyledFloatingMenu.js +23 -0
- package/dist/esm/views/menu/StyledItem.js +23 -0
- package/dist/esm/views/menu/StyledItemContent.js +23 -0
- package/dist/esm/views/menu/StyledItemGroup.js +23 -0
- package/dist/esm/views/menu/StyledItemIcon.js +23 -0
- package/dist/esm/views/menu/StyledItemMeta.js +23 -0
- package/dist/esm/views/menu/StyledItemTypeIcon.js +24 -0
- package/dist/esm/views/menu/StyledMenu.js +27 -0
- package/dist/esm/views/menu/StyledSeparator.js +23 -0
- package/dist/index.cjs.js +1620 -1736
- package/dist/typings/context/useComboboxContext.d.ts +25 -0
- package/dist/typings/context/useFieldContext.d.ts +32 -0
- package/dist/typings/context/useItemContext.d.ts +14 -0
- package/dist/typings/context/useItemGroupContext.d.ts +15 -0
- package/dist/typings/context/useMenuContext.d.ts +23 -0
- package/dist/typings/context/useOptionContext.d.ts +14 -0
- package/dist/typings/elements/{Combobox → combobox}/Combobox.d.ts +0 -2
- package/dist/typings/elements/{Fields → combobox}/Field.d.ts +8 -1
- package/dist/typings/elements/{Fields → combobox}/Hint.d.ts +2 -0
- package/dist/typings/elements/{Fields → combobox}/Label.d.ts +3 -1
- package/dist/typings/elements/{Menu/Items/MediaBody.d.ts → combobox/Listbox.d.ts} +2 -4
- package/dist/typings/elements/{Fields → combobox}/Message.d.ts +3 -1
- package/dist/typings/elements/{Menu/Items/HeaderItem.d.ts → combobox/OptGroup.d.ts} +2 -2
- package/dist/typings/elements/{Menu/Items/MediaItem.d.ts → combobox/Option.d.ts} +5 -2
- package/dist/typings/elements/{Menu/Items/HeaderIcon.d.ts → combobox/OptionMeta.d.ts} +1 -1
- package/dist/typings/elements/combobox/Tag.d.ts +15 -0
- package/dist/typings/elements/combobox/TagAvatar.d.ts +14 -0
- package/dist/typings/elements/combobox/TagGroup.d.ts +12 -0
- package/dist/typings/elements/combobox/utils.d.ts +30 -0
- package/dist/typings/elements/{Menu/Items → menu}/Item.d.ts +5 -2
- package/dist/typings/elements/{Menu/Items/AddItem.d.ts → menu/ItemGroup.d.ts} +2 -2
- package/dist/typings/elements/{Menu/Items → menu}/ItemMeta.d.ts +2 -2
- package/dist/typings/elements/{Menu → menu}/Menu.d.ts +0 -2
- package/dist/typings/elements/menu/MenuList.d.ts +12 -0
- package/dist/typings/elements/{Menu → menu}/Separator.d.ts +1 -1
- package/dist/typings/elements/menu/utils.d.ts +29 -0
- package/dist/typings/index.d.ts +18 -25
- package/dist/typings/types/index.d.ts +242 -121
- package/dist/typings/{styled/items/StyledItemIcon.d.ts → views/combobox/StyledCombobox.d.ts} +4 -6
- package/dist/typings/{styled/multiselect/StyledMultiselectItemWrapper.d.ts → views/combobox/StyledContainer.d.ts} +1 -1
- package/dist/typings/{styled/select/StyledSelect.d.ts → views/combobox/StyledField.d.ts} +1 -1
- package/dist/typings/views/combobox/StyledFloatingListbox.d.ts +18 -0
- package/dist/typings/views/combobox/StyledHint.d.ts +11 -0
- package/dist/typings/views/combobox/StyledInput.d.ts +20 -0
- package/dist/typings/{styled/items/StyledAddItem.d.ts → views/combobox/StyledInputGroup.d.ts} +2 -4
- package/dist/typings/views/combobox/StyledInputIcon.d.ts +20 -0
- package/dist/typings/views/combobox/StyledLabel.d.ts +11 -0
- package/dist/typings/views/combobox/StyledListbox.d.ts +17 -0
- package/dist/typings/{styled/items/StyledNextItem.d.ts → views/combobox/StyledListboxSeparator.d.ts} +2 -4
- package/dist/typings/views/combobox/StyledMessage.d.ts +11 -0
- package/dist/typings/views/combobox/StyledOptGroup.d.ts +14 -0
- package/dist/typings/views/combobox/StyledOption.d.ts +18 -0
- package/dist/typings/views/combobox/StyledOptionContent.d.ts +10 -0
- package/dist/typings/views/combobox/StyledOptionIcon.d.ts +12 -0
- package/dist/typings/views/combobox/StyledOptionMeta.d.ts +14 -0
- package/dist/typings/views/combobox/StyledOptionTypeIcon.d.ts +17 -0
- package/dist/typings/views/combobox/StyledTag.d.ts +17 -0
- package/dist/typings/views/combobox/StyledTagsButton.d.ts +16 -0
- package/dist/typings/views/combobox/StyledTrigger.d.ts +24 -0
- package/dist/typings/views/combobox/StyledValue.d.ts +21 -0
- package/dist/typings/views/index.d.ts +38 -0
- package/dist/typings/views/menu/StyledButton.d.ts +20 -0
- package/dist/typings/views/menu/StyledFloatingMenu.d.ts +13 -0
- package/dist/typings/{styled/items/StyledPreviousItem.d.ts → views/menu/StyledItem.d.ts} +4 -4
- package/dist/typings/views/menu/StyledItemContent.d.ts +13 -0
- package/dist/typings/views/menu/StyledItemGroup.d.ts +13 -0
- package/dist/typings/views/menu/StyledItemIcon.d.ts +14 -0
- package/dist/typings/{styled/items → views/menu}/StyledItemMeta.d.ts +5 -10
- package/dist/typings/views/menu/StyledItemTypeIcon.d.ts +14 -0
- package/dist/typings/views/menu/StyledMenu.d.ts +19 -0
- package/dist/typings/{styled → views}/menu/StyledSeparator.d.ts +7 -4
- package/package.json +19 -17
- package/dist/index.esm.js +0 -2032
- package/dist/typings/elements/Autocomplete/Autocomplete.d.ts +0 -14
- package/dist/typings/elements/Dropdown/Dropdown.d.ts +0 -26
- package/dist/typings/elements/Menu/Items/MediaFigure.d.ts +0 -11
- package/dist/typings/elements/Menu/Items/NextItem.d.ts +0 -12
- package/dist/typings/elements/Menu/Items/PreviousItem.d.ts +0 -12
- package/dist/typings/elements/Multiselect/Multiselect.d.ts +0 -14
- package/dist/typings/elements/Select/Select.d.ts +0 -14
- package/dist/typings/elements/Trigger/Trigger.d.ts +0 -24
- package/dist/typings/styled/index.d.ts +0 -29
- package/dist/typings/styled/items/StyledItem.d.ts +0 -20
- package/dist/typings/styled/items/StyledNextIcon.d.ts +0 -12
- package/dist/typings/styled/items/StyledPreviousIcon.d.ts +0 -12
- package/dist/typings/styled/items/header/StyledHeaderIcon.d.ts +0 -14
- package/dist/typings/styled/items/header/StyledHeaderItem.d.ts +0 -16
- package/dist/typings/styled/items/media/StyledMediaBody.d.ts +0 -17
- package/dist/typings/styled/items/media/StyledMediaFigure.d.ts +0 -287
- package/dist/typings/styled/items/media/StyledMediaItem.d.ts +0 -13
- package/dist/typings/styled/menu/StyledMenu.d.ts +0 -20
- package/dist/typings/styled/menu/StyledMenuWrapper.d.ts +0 -16
- package/dist/typings/styled/multiselect/StyledMultiselectInput.d.ts +0 -22
- package/dist/typings/styled/multiselect/StyledMultiselectItemsContainer.d.ts +0 -16
- package/dist/typings/styled/multiselect/StyledMultiselectMoreAnchor.d.ts +0 -15
- package/dist/typings/styled/select/StyledFauxInput.d.ts +0 -22
- package/dist/typings/styled/select/StyledInput.d.ts +0 -15
- package/dist/typings/utils/garden-placements.d.ts +0 -26
- package/dist/typings/utils/useDropdownContext.d.ts +0 -28
- package/dist/typings/utils/useFieldContext.d.ts +0 -17
- package/dist/typings/utils/useItemContext.d.ts +0 -16
- package/dist/typings/utils/useMenuContext.d.ts +0 -17
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
# @zendeskgarden/react-dropdowns [![npm version]
|
|
1
|
+
# @zendeskgarden/react-dropdowns [![npm version][npm version badge]][npm version link]
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[npm version badge]: https://flat.badgen.net/npm/v/@zendeskgarden/react-dropdowns
|
|
4
|
+
[npm version link]: https://www.npmjs.com/package/@zendeskgarden/react-dropdowns
|
|
5
|
+
|
|
6
|
+
This package includes components related to dropdowns in the
|
|
4
7
|
[Garden Design System](https://zendeskgarden.github.io/).
|
|
5
8
|
|
|
6
9
|
## Installation
|
|
@@ -12,85 +15,86 @@ npm install @zendeskgarden/react-dropdowns
|
|
|
12
15
|
npm install react react-dom styled-components @zendeskgarden/react-theming
|
|
13
16
|
```
|
|
14
17
|
|
|
15
|
-
##
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Combobox
|
|
16
21
|
|
|
17
22
|
```jsx
|
|
18
23
|
import { ThemeProvider } from '@zendeskgarden/react-theming';
|
|
19
|
-
import {
|
|
24
|
+
import { Field, Label, Combobox, Option } from '@zendeskgarden/react-dropdowns';
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
27
|
* Place a `ThemeProvider` at the root of your React application
|
|
23
28
|
*/
|
|
24
29
|
<ThemeProvider>
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
</Menu>
|
|
34
|
-
</Dropdown>
|
|
30
|
+
<Field>
|
|
31
|
+
<Field.Label>Label</Field.Label>
|
|
32
|
+
<Combobox>
|
|
33
|
+
<Option value="One" />
|
|
34
|
+
<Option value="Two" />
|
|
35
|
+
<Option value="Three" />
|
|
36
|
+
</Combobox>
|
|
37
|
+
</Field>
|
|
35
38
|
</ThemeProvider>;
|
|
36
39
|
```
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
41
|
+
Beyond this basic example, Garden's `Combobox` offers a comprehensive set of
|
|
42
|
+
WAI-ARIA compliant combobox features. Key capabilities include:
|
|
43
|
+
|
|
44
|
+
- **Controllable**: The `Combobox` functions in both [uncontrolled and
|
|
45
|
+
controlled](https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components)
|
|
46
|
+
modes. Controlled mode enables aspects, such as input value, selection value(s),
|
|
47
|
+
listbox expansion, and current option active index, to share and adapt to the
|
|
48
|
+
surrounding UI.
|
|
49
|
+
- **Autocomplete-able**: Denotes the `Combobox` with [list
|
|
50
|
+
autocomplete](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list/).
|
|
51
|
+
Filtering implementation is left to the API consumer.
|
|
52
|
+
- **Selectable**: The `Combobox` API ensures the selection of one or more
|
|
53
|
+
listbox option values, while also supporting the W3C [no autocomplete
|
|
54
|
+
example](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-none/)
|
|
55
|
+
for use cases like search.
|
|
56
|
+
- **Multi-selectable**: This feature enables the `Combobox` to provide WAI-ARIA
|
|
57
|
+
[multi-select
|
|
58
|
+
listbox](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/examples/listbox-rearrangeable/#ex2_label)
|
|
59
|
+
functionality with option-as-tag value rendering.
|
|
60
|
+
- **Non-editable**: The `Combobox` supports [select-only
|
|
61
|
+
mode](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/),
|
|
62
|
+
where the user cannot modify the `<input>`.
|
|
63
|
+
- **Filterable**: The `Combobox` offers various filtering methods for listbox
|
|
64
|
+
options. Details of the filtering implementation are left to the API consumer.
|
|
65
|
+
- **Markup-able**: The `Combobox` can convert input value text to rich HTML
|
|
66
|
+
markup on blur in single-selection mode.
|
|
67
|
+
- **Decorate-able**: The `Combobox` allows adding start and end media (SVG icons).
|
|
68
|
+
Certain features will replace end media with Garden's standard dropdown chevron
|
|
69
|
+
treatment.
|
|
70
|
+
- **Group-able**: The `Combobox` API utilizes fully accessible `<OptGroup>`
|
|
71
|
+
components for grouping, similar to the corresponding HTML element.
|
|
72
|
+
- **Compactible**: Like other form elements, the `Combobox` supports compact
|
|
73
|
+
sizing.
|
|
74
|
+
- **Field-able**: The `Combobox` builds on Garden’s Field API context to
|
|
75
|
+
establish accessible relationships with corresponding Label, Hint, and Message
|
|
76
|
+
components.
|
|
77
|
+
- **Validate-able**: The `Combobox` provides validation styling and
|
|
78
|
+
accessibility comparable to other Garden form components.
|
|
79
|
+
- **RTL theme-able**: Functionality displays and operates correctly for
|
|
80
|
+
left-to-right and right-to-left layouts.
|
|
81
|
+
|
|
82
|
+
### Menu
|
|
62
83
|
|
|
63
84
|
```jsx
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
<Item value="item-1">Item 1</Item>
|
|
67
|
-
<Item value="item-2">Item 2</Item>
|
|
68
|
-
<Item value="item-3">Item 3</Item>
|
|
69
|
-
</Menu>
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Dropdown State
|
|
73
|
-
|
|
74
|
-
We use the [Downshift](https://github.com/downshift-js/downshift) render-prop library to
|
|
75
|
-
handle our keyboard and accessibility logic.
|
|
76
|
-
|
|
77
|
-
The following states can be controlled directly from the `<Dropdown>` component:
|
|
78
|
-
|
|
79
|
-
- **isOpen** Whether the dropdown is currently open
|
|
80
|
-
- **highlightedIndex** Which index is currently highlighted
|
|
81
|
-
- **inputValue** The value of the input when it's used as an `Autocomplete`
|
|
82
|
-
- **selectedItem** The currently selected item
|
|
83
|
-
- **selectedItems** The currently selected items
|
|
84
|
-
|
|
85
|
-
All other customizations may be provided directly to the Downshift provider
|
|
86
|
-
via the `downshiftProps` prop.
|
|
87
|
-
|
|
88
|
-
Downshift provides several advanced customization features that can be very helpful when
|
|
89
|
-
customizing this component. The [stateReducer](https://github.com/downshift-js/downshift#statereducer)
|
|
90
|
-
pattern is a common customization strategy.
|
|
85
|
+
import { ThemeProvider } from '@zendeskgarden/react-theming';
|
|
86
|
+
import { Menu, Item } from '@zendeskgarden/react-dropdowns';
|
|
91
87
|
|
|
92
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Place a `ThemeProvider` at the root of your React application
|
|
90
|
+
*/
|
|
91
|
+
<ThemeProvider>
|
|
92
|
+
<Menu button="Choose an item">
|
|
93
|
+
<Item value="item-01" label="One" />
|
|
94
|
+
<Item value="item-02" label="Two" />
|
|
95
|
+
<Item value="item-03" label="Three" />
|
|
96
|
+
</Menu>
|
|
97
|
+
</ThemeProvider>;
|
|
98
|
+
```
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
This package re-exports the Downshift `resetIdCounter` utility. It allows resetting the internal id
|
|
96
|
-
counter which is used to generate unique ids for Downshift.
|
|
100
|
+
Visit [storybook](https://zendeskgarden.github.io/react-components) for live examples.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext } from 'react';
|
|
8
|
+
|
|
9
|
+
const ComboboxContext = createContext(undefined);
|
|
10
|
+
const useComboboxContext = () => {
|
|
11
|
+
const context = useContext(ComboboxContext);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error('Error: this component must be rendered within a <Combobox>.');
|
|
14
|
+
}
|
|
15
|
+
return context;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { ComboboxContext, useComboboxContext as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext } from 'react';
|
|
8
|
+
|
|
9
|
+
const FieldContext = createContext(undefined);
|
|
10
|
+
const useFieldContext = () => {
|
|
11
|
+
const context = useContext(FieldContext);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error('Error: this component must be rendered within a <Field>.');
|
|
14
|
+
}
|
|
15
|
+
return context;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { FieldContext, useFieldContext as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext } from 'react';
|
|
8
|
+
|
|
9
|
+
const ItemContext = createContext(undefined);
|
|
10
|
+
const useItemContext = () => {
|
|
11
|
+
const context = useContext(ItemContext);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error('Error: this component must be rendered within an <Item>.');
|
|
14
|
+
}
|
|
15
|
+
return context;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { ItemContext, useItemContext as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext } from 'react';
|
|
8
|
+
|
|
9
|
+
const ItemGroupContext = createContext({});
|
|
10
|
+
const useItemGroupContext = () => {
|
|
11
|
+
return useContext(ItemGroupContext);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export { ItemGroupContext, useItemGroupContext as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext } from 'react';
|
|
8
|
+
|
|
9
|
+
const MenuContext = createContext(undefined);
|
|
10
|
+
const useMenuContext = () => {
|
|
11
|
+
const context = useContext(MenuContext);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error('Error: this component must be rendered within a <Menu>.');
|
|
14
|
+
}
|
|
15
|
+
return context;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { MenuContext, useMenuContext as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext } from 'react';
|
|
8
|
+
|
|
9
|
+
const OptionContext = createContext(undefined);
|
|
10
|
+
const useOptionContext = () => {
|
|
11
|
+
const context = useContext(OptionContext);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new Error('Error: this component must be rendered within an <Option>.');
|
|
14
|
+
}
|
|
15
|
+
return context;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { OptionContext, useOptionContext as default };
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React__default, { forwardRef, useState, useMemo, useRef, useContext, useEffect } from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { ThemeContext } from 'styled-components';
|
|
10
|
+
import { useCombobox } from '@zendeskgarden/container-combobox';
|
|
11
|
+
import { DEFAULT_THEME, useWindow, useText } from '@zendeskgarden/react-theming';
|
|
12
|
+
import { VALIDATION } from '@zendeskgarden/react-forms';
|
|
13
|
+
import SvgChevronDownStroke from '../../node_modules/@zendeskgarden/svg-icons/src/16/chevron-down-stroke.svg.js';
|
|
14
|
+
import { ComboboxContext } from '../../context/useComboboxContext.js';
|
|
15
|
+
import useFieldContext from '../../context/useFieldContext.js';
|
|
16
|
+
import { StyledCombobox } from '../../views/combobox/StyledCombobox.js';
|
|
17
|
+
import { StyledContainer } from '../../views/combobox/StyledContainer.js';
|
|
18
|
+
import '../../views/combobox/StyledField.js';
|
|
19
|
+
import '../../views/combobox/StyledFloatingListbox.js';
|
|
20
|
+
import '../../views/combobox/StyledHint.js';
|
|
21
|
+
import { StyledInput } from '../../views/combobox/StyledInput.js';
|
|
22
|
+
import { StyledInputGroup } from '../../views/combobox/StyledInputGroup.js';
|
|
23
|
+
import { StyledInputIcon } from '../../views/combobox/StyledInputIcon.js';
|
|
24
|
+
import '../../views/combobox/StyledLabel.js';
|
|
25
|
+
import '../../views/combobox/StyledListbox.js';
|
|
26
|
+
import '../../views/combobox/StyledListboxSeparator.js';
|
|
27
|
+
import '../../views/combobox/StyledMessage.js';
|
|
28
|
+
import '../../views/combobox/StyledOptGroup.js';
|
|
29
|
+
import '../../views/combobox/StyledOption.js';
|
|
30
|
+
import '../../views/combobox/StyledOptionContent.js';
|
|
31
|
+
import '../../views/combobox/StyledOptionIcon.js';
|
|
32
|
+
import '../../views/combobox/StyledOptionMeta.js';
|
|
33
|
+
import '../../views/combobox/StyledOptionTypeIcon.js';
|
|
34
|
+
import '../../views/combobox/StyledTag.js';
|
|
35
|
+
import { StyledTagsButton } from '../../views/combobox/StyledTagsButton.js';
|
|
36
|
+
import { StyledTrigger } from '../../views/combobox/StyledTrigger.js';
|
|
37
|
+
import { StyledValue } from '../../views/combobox/StyledValue.js';
|
|
38
|
+
import '../../views/menu/StyledMenu.js';
|
|
39
|
+
import '../../views/menu/StyledFloatingMenu.js';
|
|
40
|
+
import '../../views/menu/StyledItem.js';
|
|
41
|
+
import '../../views/menu/StyledItemContent.js';
|
|
42
|
+
import '../../views/menu/StyledItemGroup.js';
|
|
43
|
+
import '../../views/menu/StyledItemIcon.js';
|
|
44
|
+
import '../../views/menu/StyledItemMeta.js';
|
|
45
|
+
import '../../views/menu/StyledItemTypeIcon.js';
|
|
46
|
+
import '../../views/menu/StyledButton.js';
|
|
47
|
+
import '../../views/menu/StyledSeparator.js';
|
|
48
|
+
import { Listbox } from './Listbox.js';
|
|
49
|
+
import { TagGroup } from './TagGroup.js';
|
|
50
|
+
import { toOptions } from './utils.js';
|
|
51
|
+
|
|
52
|
+
const MAX_TAGS = 4;
|
|
53
|
+
const Combobox = forwardRef((_ref, ref) => {
|
|
54
|
+
let {
|
|
55
|
+
children,
|
|
56
|
+
activeIndex,
|
|
57
|
+
defaultActiveIndex,
|
|
58
|
+
defaultExpanded,
|
|
59
|
+
endIcon,
|
|
60
|
+
focusInset,
|
|
61
|
+
inputProps: _inputProps,
|
|
62
|
+
inputValue: _inputValue,
|
|
63
|
+
isAutocomplete,
|
|
64
|
+
isBare,
|
|
65
|
+
isCompact,
|
|
66
|
+
isDisabled,
|
|
67
|
+
isEditable,
|
|
68
|
+
isExpanded: _isExpanded,
|
|
69
|
+
isMultiselectable,
|
|
70
|
+
listboxAppendToNode,
|
|
71
|
+
listboxAriaLabel,
|
|
72
|
+
listboxMaxHeight,
|
|
73
|
+
listboxMinHeight,
|
|
74
|
+
listboxZIndex,
|
|
75
|
+
maxHeight,
|
|
76
|
+
maxTags = MAX_TAGS,
|
|
77
|
+
onChange,
|
|
78
|
+
placeholder,
|
|
79
|
+
renderExpandTags,
|
|
80
|
+
renderValue,
|
|
81
|
+
selectionValue,
|
|
82
|
+
startIcon,
|
|
83
|
+
validation,
|
|
84
|
+
...props
|
|
85
|
+
} = _ref;
|
|
86
|
+
const {
|
|
87
|
+
hasHint,
|
|
88
|
+
hasMessage,
|
|
89
|
+
labelProps,
|
|
90
|
+
setLabelProps,
|
|
91
|
+
hintProps,
|
|
92
|
+
setHintProps,
|
|
93
|
+
messageProps,
|
|
94
|
+
setMessageProps
|
|
95
|
+
} = useFieldContext();
|
|
96
|
+
const [isInputHidden, setIsInputHidden] = useState(true);
|
|
97
|
+
const [isLabelHovered, setIsLabelHovered] = useState(false);
|
|
98
|
+
const [isTagGroupExpanded, setIsTagGroupExpanded] = useState(false);
|
|
99
|
+
const [optionTagProps, setOptionTagProps] = useState({});
|
|
100
|
+
const options = useMemo(() => {
|
|
101
|
+
const tagProps = {};
|
|
102
|
+
const retVal = toOptions(children, tagProps);
|
|
103
|
+
if (isMultiselectable) {
|
|
104
|
+
setOptionTagProps(value => ({
|
|
105
|
+
...value,
|
|
106
|
+
...tagProps
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
return retVal;
|
|
110
|
+
}, [children, isMultiselectable]);
|
|
111
|
+
const triggerRef = useRef(null);
|
|
112
|
+
const inputRef = useRef(null);
|
|
113
|
+
const listboxRef = useRef(null);
|
|
114
|
+
const theme = useContext(ThemeContext) || DEFAULT_THEME;
|
|
115
|
+
const environment = useWindow(theme);
|
|
116
|
+
const {
|
|
117
|
+
activeValue,
|
|
118
|
+
inputValue,
|
|
119
|
+
isExpanded,
|
|
120
|
+
getTriggerProps,
|
|
121
|
+
getHintProps,
|
|
122
|
+
getInputProps,
|
|
123
|
+
getLabelProps,
|
|
124
|
+
getListboxProps,
|
|
125
|
+
getMessageProps,
|
|
126
|
+
getOptionProps,
|
|
127
|
+
getOptGroupProps,
|
|
128
|
+
getTagProps,
|
|
129
|
+
removeSelection,
|
|
130
|
+
selection
|
|
131
|
+
} = useCombobox({
|
|
132
|
+
idPrefix: props.id,
|
|
133
|
+
triggerRef,
|
|
134
|
+
inputRef,
|
|
135
|
+
listboxRef,
|
|
136
|
+
options,
|
|
137
|
+
environment,
|
|
138
|
+
hasHint,
|
|
139
|
+
hasMessage,
|
|
140
|
+
isAutocomplete,
|
|
141
|
+
isEditable,
|
|
142
|
+
isMultiselectable,
|
|
143
|
+
disabled: isDisabled,
|
|
144
|
+
inputValue: _inputValue,
|
|
145
|
+
selectionValue,
|
|
146
|
+
isExpanded: _isExpanded,
|
|
147
|
+
defaultExpanded,
|
|
148
|
+
activeIndex,
|
|
149
|
+
defaultActiveIndex,
|
|
150
|
+
onChange
|
|
151
|
+
});
|
|
152
|
+
const contextValue = useMemo(() => ({
|
|
153
|
+
activeValue,
|
|
154
|
+
getOptionProps,
|
|
155
|
+
getOptGroupProps,
|
|
156
|
+
getTagProps,
|
|
157
|
+
isCompact,
|
|
158
|
+
removeSelection
|
|
159
|
+
}), [activeValue, getOptionProps, getOptGroupProps, getTagProps, isCompact, removeSelection]);
|
|
160
|
+
const hasChevron = useMemo(() => !isBare && (isAutocomplete || !isEditable), [isAutocomplete, isBare, isEditable]);
|
|
161
|
+
const expandTags = useText(Combobox, {
|
|
162
|
+
renderExpandTags
|
|
163
|
+
}, 'renderExpandTags', '+ {{value}} more', isMultiselectable || false);
|
|
164
|
+
const _listboxAriaLabel = useText(Combobox, {
|
|
165
|
+
listboxAriaLabel
|
|
166
|
+
}, 'listboxAriaLabel', 'Options');
|
|
167
|
+
const triggerProps = {
|
|
168
|
+
isAutocomplete,
|
|
169
|
+
isBare,
|
|
170
|
+
isCompact,
|
|
171
|
+
isEditable,
|
|
172
|
+
isLabelHovered,
|
|
173
|
+
isMultiselectable,
|
|
174
|
+
maxHeight,
|
|
175
|
+
focusInset,
|
|
176
|
+
validation,
|
|
177
|
+
...getTriggerProps({
|
|
178
|
+
onFocus: () => {
|
|
179
|
+
if (!isDisabled) {
|
|
180
|
+
if (isEditable) {
|
|
181
|
+
setIsInputHidden(false);
|
|
182
|
+
}
|
|
183
|
+
if (isMultiselectable) {
|
|
184
|
+
setIsTagGroupExpanded(true);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
onBlur: event => {
|
|
189
|
+
if (event.relatedTarget === null || !triggerRef.current?.contains(event.relatedTarget)) {
|
|
190
|
+
if (isEditable) {
|
|
191
|
+
setIsInputHidden(true);
|
|
192
|
+
}
|
|
193
|
+
if (isMultiselectable) {
|
|
194
|
+
setIsTagGroupExpanded(false);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
};
|
|
200
|
+
const inputProps = {
|
|
201
|
+
'aria-invalid': validation === 'error' || validation === 'warning',
|
|
202
|
+
hidden: isInputHidden,
|
|
203
|
+
isBare,
|
|
204
|
+
isCompact,
|
|
205
|
+
isEditable,
|
|
206
|
+
isMultiselectable,
|
|
207
|
+
placeholder,
|
|
208
|
+
...getInputProps({
|
|
209
|
+
..._inputProps
|
|
210
|
+
})
|
|
211
|
+
};
|
|
212
|
+
const listboxProps = getListboxProps({
|
|
213
|
+
'aria-label': _listboxAriaLabel
|
|
214
|
+
});
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
if (!labelProps) {
|
|
217
|
+
const _labelProps = getLabelProps({
|
|
218
|
+
onMouseEnter: () => setIsLabelHovered(true),
|
|
219
|
+
onMouseLeave: () => setIsLabelHovered(false)
|
|
220
|
+
});
|
|
221
|
+
setLabelProps(_labelProps);
|
|
222
|
+
}
|
|
223
|
+
return () => labelProps && setLabelProps(undefined);
|
|
224
|
+
}, [getLabelProps, labelProps, setLabelProps]);
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
if (!hintProps) {
|
|
227
|
+
const _hintProps = getHintProps();
|
|
228
|
+
setHintProps(_hintProps);
|
|
229
|
+
}
|
|
230
|
+
return () => hintProps && setHintProps(undefined);
|
|
231
|
+
}, [getHintProps, hintProps, setHintProps]);
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
if (!messageProps) {
|
|
234
|
+
const _messageProps = getMessageProps();
|
|
235
|
+
setMessageProps(_messageProps);
|
|
236
|
+
}
|
|
237
|
+
return () => messageProps && setMessageProps(undefined);
|
|
238
|
+
}, [getMessageProps, messageProps, setMessageProps]);
|
|
239
|
+
return React__default.createElement(ComboboxContext.Provider, {
|
|
240
|
+
value: contextValue
|
|
241
|
+
}, React__default.createElement(StyledCombobox, Object.assign({
|
|
242
|
+
isCompact: isCompact,
|
|
243
|
+
tabIndex: -1
|
|
244
|
+
}, props, {
|
|
245
|
+
ref: ref
|
|
246
|
+
}), React__default.createElement(StyledTrigger, triggerProps, React__default.createElement(StyledContainer, null, startIcon && React__default.createElement(StyledInputIcon, {
|
|
247
|
+
$isLabelHovered: isLabelHovered,
|
|
248
|
+
$isCompact: isCompact
|
|
249
|
+
}, startIcon), React__default.createElement(StyledInputGroup, null, isMultiselectable && Array.isArray(selection) && React__default.createElement(TagGroup, {
|
|
250
|
+
isDisabled: isDisabled,
|
|
251
|
+
isExpanded: isTagGroupExpanded,
|
|
252
|
+
maxTags: maxTags,
|
|
253
|
+
optionTagProps: optionTagProps,
|
|
254
|
+
selection: selection
|
|
255
|
+
}, selection.length > maxTags && React__default.createElement(StyledTagsButton, {
|
|
256
|
+
disabled: isDisabled,
|
|
257
|
+
hidden: isTagGroupExpanded,
|
|
258
|
+
isCompact: isCompact,
|
|
259
|
+
tabIndex: -1,
|
|
260
|
+
type: "button"
|
|
261
|
+
}, (() => {
|
|
262
|
+
const value = selection.length - maxTags;
|
|
263
|
+
return renderExpandTags ? renderExpandTags(value) : expandTags?.replace('{{value}}', value.toString());
|
|
264
|
+
})())), React__default.createElement(StyledValue, {
|
|
265
|
+
hidden: !isInputHidden,
|
|
266
|
+
isAutocomplete: isAutocomplete,
|
|
267
|
+
isBare: isBare,
|
|
268
|
+
isCompact: isCompact,
|
|
269
|
+
isDisabled: isDisabled,
|
|
270
|
+
isEditable: isEditable,
|
|
271
|
+
isMultiselectable: isMultiselectable,
|
|
272
|
+
isPlaceholder: !(inputValue || renderValue)
|
|
273
|
+
}, renderValue ? renderValue({
|
|
274
|
+
selection,
|
|
275
|
+
inputValue
|
|
276
|
+
}) : inputValue || placeholder), React__default.createElement(StyledInput, inputProps)), (hasChevron || endIcon) && React__default.createElement(StyledInputIcon, {
|
|
277
|
+
$isCompact: isCompact,
|
|
278
|
+
$isEnd: true,
|
|
279
|
+
$isLabelHovered: isLabelHovered,
|
|
280
|
+
$isRotated: hasChevron && isExpanded
|
|
281
|
+
}, hasChevron ? React__default.createElement(SvgChevronDownStroke, null) : endIcon))), React__default.createElement(Listbox, Object.assign({
|
|
282
|
+
appendToNode: listboxAppendToNode,
|
|
283
|
+
isCompact: isCompact,
|
|
284
|
+
isExpanded: isExpanded,
|
|
285
|
+
maxHeight: listboxMaxHeight,
|
|
286
|
+
minHeight: listboxMinHeight,
|
|
287
|
+
triggerRef: triggerRef,
|
|
288
|
+
zIndex: listboxZIndex
|
|
289
|
+
}, listboxProps), children)));
|
|
290
|
+
});
|
|
291
|
+
Combobox.displayName = 'Combobox';
|
|
292
|
+
Combobox.propTypes = {
|
|
293
|
+
activeIndex: PropTypes.number,
|
|
294
|
+
defaultActiveIndex: PropTypes.number,
|
|
295
|
+
defaultExpanded: PropTypes.bool,
|
|
296
|
+
endIcon: PropTypes.any,
|
|
297
|
+
focusInset: PropTypes.bool,
|
|
298
|
+
id: PropTypes.string,
|
|
299
|
+
inputProps: PropTypes.object,
|
|
300
|
+
inputValue: PropTypes.string,
|
|
301
|
+
isAutocomplete: PropTypes.bool,
|
|
302
|
+
isBare: PropTypes.bool,
|
|
303
|
+
isCompact: PropTypes.bool,
|
|
304
|
+
isDisabled: PropTypes.bool,
|
|
305
|
+
isEditable: PropTypes.bool,
|
|
306
|
+
isExpanded: PropTypes.bool,
|
|
307
|
+
isMultiselectable: PropTypes.bool,
|
|
308
|
+
listboxAppendToNode: PropTypes.any,
|
|
309
|
+
listboxAriaLabel: PropTypes.string,
|
|
310
|
+
listboxMaxHeight: PropTypes.string,
|
|
311
|
+
listboxMinHeight: PropTypes.string,
|
|
312
|
+
listboxZIndex: PropTypes.number,
|
|
313
|
+
maxHeight: PropTypes.string,
|
|
314
|
+
maxTags: PropTypes.number,
|
|
315
|
+
onChange: PropTypes.func,
|
|
316
|
+
placeholder: PropTypes.string,
|
|
317
|
+
renderExpandTags: PropTypes.func,
|
|
318
|
+
renderValue: PropTypes.func,
|
|
319
|
+
selectionValue: PropTypes.any,
|
|
320
|
+
startIcon: PropTypes.any,
|
|
321
|
+
validation: PropTypes.oneOf(VALIDATION)
|
|
322
|
+
};
|
|
323
|
+
Combobox.defaultProps = {
|
|
324
|
+
isEditable: true,
|
|
325
|
+
listboxMaxHeight: '400px',
|
|
326
|
+
listboxZIndex: 1000,
|
|
327
|
+
maxTags: MAX_TAGS
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
export { Combobox };
|