@zendeskgarden/react-dropdowns 9.0.0-next.1 → 9.0.0-next.11

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.
Files changed (159) hide show
  1. package/README.md +73 -69
  2. package/dist/esm/context/useComboboxContext.js +18 -0
  3. package/dist/esm/context/useFieldContext.js +18 -0
  4. package/dist/esm/context/useItemContext.js +18 -0
  5. package/dist/esm/context/useItemGroupContext.js +14 -0
  6. package/dist/esm/context/useMenuContext.js +18 -0
  7. package/dist/esm/context/useOptionContext.js +18 -0
  8. package/dist/esm/elements/combobox/Combobox.js +330 -0
  9. package/dist/esm/elements/combobox/Field.js +75 -0
  10. package/dist/esm/elements/combobox/Hint.js +57 -0
  11. package/dist/esm/elements/combobox/Label.js +68 -0
  12. package/dist/esm/elements/combobox/Listbox.js +155 -0
  13. package/dist/esm/elements/combobox/Message.js +63 -0
  14. package/dist/esm/elements/combobox/OptGroup.js +93 -0
  15. package/dist/esm/elements/combobox/Option.js +133 -0
  16. package/dist/esm/elements/combobox/OptionMeta.js +55 -0
  17. package/dist/esm/elements/combobox/Tag.js +98 -0
  18. package/dist/esm/elements/combobox/TagAvatar.js +13 -0
  19. package/dist/esm/elements/combobox/TagGroup.js +35 -0
  20. package/dist/esm/elements/combobox/utils.js +36 -0
  21. package/dist/esm/elements/menu/Item.js +140 -0
  22. package/dist/esm/elements/menu/ItemGroup.js +96 -0
  23. package/dist/esm/elements/menu/ItemMeta.js +55 -0
  24. package/dist/esm/elements/menu/Menu.js +157 -0
  25. package/dist/esm/elements/menu/MenuList.js +170 -0
  26. package/dist/esm/elements/menu/Separator.js +58 -0
  27. package/dist/esm/elements/menu/utils.js +55 -0
  28. package/dist/esm/index.js +19 -0
  29. package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/check-lg-stroke.svg.js +28 -0
  30. package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/chevron-down-stroke.svg.js +25 -0
  31. package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/chevron-left-stroke.svg.js +25 -0
  32. package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/chevron-right-stroke.svg.js +25 -0
  33. package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/plus-stroke.svg.js +26 -0
  34. package/dist/esm/types/index.js +12 -0
  35. package/dist/esm/views/combobox/StyledCombobox.js +30 -0
  36. package/dist/esm/views/combobox/StyledContainer.js +22 -0
  37. package/dist/esm/views/combobox/StyledField.js +22 -0
  38. package/dist/esm/views/combobox/StyledFloatingListbox.js +27 -0
  39. package/dist/esm/views/combobox/StyledHint.js +23 -0
  40. package/dist/esm/views/combobox/StyledInput.js +41 -0
  41. package/dist/esm/views/combobox/StyledInputGroup.js +26 -0
  42. package/dist/esm/views/combobox/StyledInputIcon.js +43 -0
  43. package/dist/esm/views/combobox/StyledLabel.js +23 -0
  44. package/dist/esm/views/combobox/StyledListbox.js +31 -0
  45. package/dist/esm/views/combobox/StyledListboxSeparator.js +31 -0
  46. package/dist/esm/views/combobox/StyledMessage.js +23 -0
  47. package/dist/esm/views/combobox/StyledOptGroup.js +22 -0
  48. package/dist/esm/views/combobox/StyledOption.js +48 -0
  49. package/dist/esm/views/combobox/StyledOptionContent.js +22 -0
  50. package/dist/esm/views/combobox/StyledOptionIcon.js +29 -0
  51. package/dist/esm/views/combobox/StyledOptionMeta.js +31 -0
  52. package/dist/esm/views/combobox/StyledOptionTypeIcon.js +48 -0
  53. package/dist/esm/views/combobox/StyledTag.js +24 -0
  54. package/dist/esm/views/combobox/StyledTagsButton.js +28 -0
  55. package/dist/esm/views/combobox/StyledTrigger.js +94 -0
  56. package/dist/esm/views/combobox/StyledValue.js +32 -0
  57. package/dist/esm/views/menu/StyledButton.js +23 -0
  58. package/dist/esm/views/menu/StyledFloatingMenu.js +23 -0
  59. package/dist/esm/views/menu/StyledItem.js +23 -0
  60. package/dist/esm/views/menu/StyledItemContent.js +23 -0
  61. package/dist/esm/views/menu/StyledItemGroup.js +23 -0
  62. package/dist/esm/views/menu/StyledItemIcon.js +23 -0
  63. package/dist/esm/views/menu/StyledItemMeta.js +23 -0
  64. package/dist/esm/views/menu/StyledItemTypeIcon.js +24 -0
  65. package/dist/esm/views/menu/StyledMenu.js +27 -0
  66. package/dist/esm/views/menu/StyledSeparator.js +23 -0
  67. package/dist/index.cjs.js +1620 -1736
  68. package/dist/typings/context/useComboboxContext.d.ts +25 -0
  69. package/dist/typings/context/useFieldContext.d.ts +32 -0
  70. package/dist/typings/context/useItemContext.d.ts +14 -0
  71. package/dist/typings/context/useItemGroupContext.d.ts +15 -0
  72. package/dist/typings/context/useMenuContext.d.ts +23 -0
  73. package/dist/typings/context/useOptionContext.d.ts +14 -0
  74. package/dist/typings/elements/{Combobox → combobox}/Combobox.d.ts +0 -2
  75. package/dist/typings/elements/{Fields → combobox}/Field.d.ts +8 -1
  76. package/dist/typings/elements/{Fields → combobox}/Hint.d.ts +2 -0
  77. package/dist/typings/elements/{Fields → combobox}/Label.d.ts +3 -1
  78. package/dist/typings/elements/{Menu/Items/MediaBody.d.ts → combobox/Listbox.d.ts} +2 -4
  79. package/dist/typings/elements/{Fields → combobox}/Message.d.ts +3 -1
  80. package/dist/typings/elements/{Menu/Items/HeaderItem.d.ts → combobox/OptGroup.d.ts} +2 -2
  81. package/dist/typings/elements/{Menu/Items/MediaItem.d.ts → combobox/Option.d.ts} +5 -2
  82. package/dist/typings/elements/{Menu/Items/HeaderIcon.d.ts → combobox/OptionMeta.d.ts} +1 -1
  83. package/dist/typings/elements/combobox/Tag.d.ts +15 -0
  84. package/dist/typings/elements/combobox/TagAvatar.d.ts +14 -0
  85. package/dist/typings/elements/combobox/TagGroup.d.ts +12 -0
  86. package/dist/typings/elements/combobox/utils.d.ts +30 -0
  87. package/dist/typings/elements/{Menu/Items → menu}/Item.d.ts +5 -2
  88. package/dist/typings/elements/{Menu/Items/AddItem.d.ts → menu/ItemGroup.d.ts} +2 -2
  89. package/dist/typings/elements/{Menu/Items → menu}/ItemMeta.d.ts +2 -2
  90. package/dist/typings/elements/{Menu → menu}/Menu.d.ts +0 -2
  91. package/dist/typings/elements/menu/MenuList.d.ts +12 -0
  92. package/dist/typings/elements/{Menu → menu}/Separator.d.ts +1 -1
  93. package/dist/typings/elements/menu/utils.d.ts +29 -0
  94. package/dist/typings/index.d.ts +18 -25
  95. package/dist/typings/types/index.d.ts +242 -121
  96. package/dist/typings/{styled/items/StyledItemIcon.d.ts → views/combobox/StyledCombobox.d.ts} +4 -6
  97. package/dist/typings/{styled/multiselect/StyledMultiselectItemWrapper.d.ts → views/combobox/StyledContainer.d.ts} +1 -1
  98. package/dist/typings/{styled/select/StyledSelect.d.ts → views/combobox/StyledField.d.ts} +1 -1
  99. package/dist/typings/views/combobox/StyledFloatingListbox.d.ts +18 -0
  100. package/dist/typings/views/combobox/StyledHint.d.ts +11 -0
  101. package/dist/typings/views/combobox/StyledInput.d.ts +20 -0
  102. package/dist/typings/{styled/items/StyledAddItem.d.ts → views/combobox/StyledInputGroup.d.ts} +2 -4
  103. package/dist/typings/views/combobox/StyledInputIcon.d.ts +20 -0
  104. package/dist/typings/views/combobox/StyledLabel.d.ts +11 -0
  105. package/dist/typings/views/combobox/StyledListbox.d.ts +17 -0
  106. package/dist/typings/{styled/items/StyledNextItem.d.ts → views/combobox/StyledListboxSeparator.d.ts} +2 -4
  107. package/dist/typings/views/combobox/StyledMessage.d.ts +11 -0
  108. package/dist/typings/views/combobox/StyledOptGroup.d.ts +14 -0
  109. package/dist/typings/views/combobox/StyledOption.d.ts +18 -0
  110. package/dist/typings/views/combobox/StyledOptionContent.d.ts +10 -0
  111. package/dist/typings/views/combobox/StyledOptionIcon.d.ts +12 -0
  112. package/dist/typings/views/combobox/StyledOptionMeta.d.ts +14 -0
  113. package/dist/typings/views/combobox/StyledOptionTypeIcon.d.ts +17 -0
  114. package/dist/typings/views/combobox/StyledTag.d.ts +17 -0
  115. package/dist/typings/views/combobox/StyledTagsButton.d.ts +16 -0
  116. package/dist/typings/views/combobox/StyledTrigger.d.ts +24 -0
  117. package/dist/typings/views/combobox/StyledValue.d.ts +21 -0
  118. package/dist/typings/views/index.d.ts +38 -0
  119. package/dist/typings/views/menu/StyledButton.d.ts +20 -0
  120. package/dist/typings/views/menu/StyledFloatingMenu.d.ts +13 -0
  121. package/dist/typings/{styled/items/StyledPreviousItem.d.ts → views/menu/StyledItem.d.ts} +4 -4
  122. package/dist/typings/views/menu/StyledItemContent.d.ts +13 -0
  123. package/dist/typings/views/menu/StyledItemGroup.d.ts +13 -0
  124. package/dist/typings/views/menu/StyledItemIcon.d.ts +14 -0
  125. package/dist/typings/{styled/items → views/menu}/StyledItemMeta.d.ts +5 -10
  126. package/dist/typings/views/menu/StyledItemTypeIcon.d.ts +14 -0
  127. package/dist/typings/views/menu/StyledMenu.d.ts +19 -0
  128. package/dist/typings/{styled → views}/menu/StyledSeparator.d.ts +7 -4
  129. package/package.json +19 -17
  130. package/dist/index.esm.js +0 -2032
  131. package/dist/typings/elements/Autocomplete/Autocomplete.d.ts +0 -14
  132. package/dist/typings/elements/Dropdown/Dropdown.d.ts +0 -26
  133. package/dist/typings/elements/Menu/Items/MediaFigure.d.ts +0 -11
  134. package/dist/typings/elements/Menu/Items/NextItem.d.ts +0 -12
  135. package/dist/typings/elements/Menu/Items/PreviousItem.d.ts +0 -12
  136. package/dist/typings/elements/Multiselect/Multiselect.d.ts +0 -14
  137. package/dist/typings/elements/Select/Select.d.ts +0 -14
  138. package/dist/typings/elements/Trigger/Trigger.d.ts +0 -24
  139. package/dist/typings/styled/index.d.ts +0 -29
  140. package/dist/typings/styled/items/StyledItem.d.ts +0 -20
  141. package/dist/typings/styled/items/StyledNextIcon.d.ts +0 -12
  142. package/dist/typings/styled/items/StyledPreviousIcon.d.ts +0 -12
  143. package/dist/typings/styled/items/header/StyledHeaderIcon.d.ts +0 -14
  144. package/dist/typings/styled/items/header/StyledHeaderItem.d.ts +0 -16
  145. package/dist/typings/styled/items/media/StyledMediaBody.d.ts +0 -17
  146. package/dist/typings/styled/items/media/StyledMediaFigure.d.ts +0 -287
  147. package/dist/typings/styled/items/media/StyledMediaItem.d.ts +0 -13
  148. package/dist/typings/styled/menu/StyledMenu.d.ts +0 -20
  149. package/dist/typings/styled/menu/StyledMenuWrapper.d.ts +0 -16
  150. package/dist/typings/styled/multiselect/StyledMultiselectInput.d.ts +0 -22
  151. package/dist/typings/styled/multiselect/StyledMultiselectItemsContainer.d.ts +0 -16
  152. package/dist/typings/styled/multiselect/StyledMultiselectMoreAnchor.d.ts +0 -15
  153. package/dist/typings/styled/select/StyledFauxInput.d.ts +0 -22
  154. package/dist/typings/styled/select/StyledInput.d.ts +0 -15
  155. package/dist/typings/utils/garden-placements.d.ts +0 -26
  156. package/dist/typings/utils/useDropdownContext.d.ts +0 -28
  157. package/dist/typings/utils/useFieldContext.d.ts +0 -17
  158. package/dist/typings/utils/useItemContext.d.ts +0 -16
  159. package/dist/typings/utils/useMenuContext.d.ts +0 -17
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
- # @zendeskgarden/react-dropdowns [![npm version](https://flat.badgen.net/npm/v/@zendeskgarden/react-dropdowns)](https://www.npmjs.com/package/@zendeskgarden/react-dropdowns)
1
+ # @zendeskgarden/react-dropdowns [![npm version][npm version badge]][npm version link]
2
2
 
3
- This package includes components relating to dropdowns in the
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
- ## Basic Example
18
+ ## Usage
19
+
20
+ ### Combobox
16
21
 
17
22
  ```jsx
18
23
  import { ThemeProvider } from '@zendeskgarden/react-theming';
19
- import { Dropdown, Menu, Item, Trigger } from '@zendeskgarden/react-dropdowns';
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
- <Dropdown onSelect={value => console.log(`Selected: ${value}`)}>
26
- <Trigger>
27
- <button>This triggers a menu</button>
28
- </Trigger>
29
- <Menu placement="end" hasArrow>
30
- <Item value="option-1">Option 1</Item>
31
- <Item value="option-2">Option 2</Item>
32
- <Item value="option-3">Option 3</Item>
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
- For all components within the `react-dropdowns` package, the menu layouts and
39
- implementations are interchangeable.
40
-
41
- Whether you're making a `Select`, `Autocomplete`, or a traditional `Menu` the `<Menu>` implementation
42
- will adapted to its consumer.
43
-
44
- ## Usage
45
-
46
- ### Overview
47
-
48
- The `react-dropdowns` package abstracts the common concepts of `Menus`, `Selects`, and `Autocompletes`
49
- into a common API. This includes consistent visuals, common keyboard interaction, and a fully accessible
50
- experience for sighted and non-sighted users.
51
-
52
- The customizations available within this can be broken into two groups: _placement / positioning_
53
- and _dropdown state_
54
-
55
- ### Placement / Positioning
56
-
57
- Internally, the `<Dropdown>` component uses [PopperJS](https://popper.js.org/popper-documentation.html)
58
- for its positioning calculations.
59
-
60
- The `<Menu>` component accepts all customizations regarding placement, boundaries, overflows,
61
- etc. via the `popperModifiers` prop.
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
- /** Customize default overflow settings to position against the `viewport` */
65
- <Menu popperModifiers={{ preventOverflow: { boundariesElement: 'viewport' } }}>
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
- ### Server Side Rendering
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
- If you are using server side rendering you may need to [configure specific Downshift settings](https://github.com/downshift-js/downshift#resetidcounter).
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 };