@react-spectrum/actiongroup 3.11.7 → 3.12.0

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 (205) hide show
  1. package/dist/import.mjs +3 -3
  2. package/dist/main.js +4 -4
  3. package/dist/main.js.map +1 -1
  4. package/dist/module.js +3 -3
  5. package/dist/module.js.map +1 -1
  6. package/dist/types/src/index.d.ts +3 -0
  7. package/package.json +14 -41
  8. package/src/index.ts +4 -3
  9. package/dist/ActionGroup.main.js +0 -398
  10. package/dist/ActionGroup.main.js.map +0 -1
  11. package/dist/ActionGroup.mjs +0 -393
  12. package/dist/ActionGroup.module.js +0 -393
  13. package/dist/ActionGroup.module.js.map +0 -1
  14. package/dist/actiongroup.bb161279.css +0 -1669
  15. package/dist/actiongroup.bb161279.css.map +0 -1
  16. package/dist/actiongroup.c0b1ee3f.css +0 -254
  17. package/dist/actiongroup.c0b1ee3f.css.map +0 -1
  18. package/dist/actiongroup_vars_css.main.js +0 -56
  19. package/dist/actiongroup_vars_css.main.js.map +0 -1
  20. package/dist/actiongroup_vars_css.mjs +0 -58
  21. package/dist/actiongroup_vars_css.module.js +0 -58
  22. package/dist/actiongroup_vars_css.module.js.map +0 -1
  23. package/dist/ar-AE.main.js +0 -6
  24. package/dist/ar-AE.main.js.map +0 -1
  25. package/dist/ar-AE.mjs +0 -8
  26. package/dist/ar-AE.module.js +0 -8
  27. package/dist/ar-AE.module.js.map +0 -1
  28. package/dist/bg-BG.main.js +0 -6
  29. package/dist/bg-BG.main.js.map +0 -1
  30. package/dist/bg-BG.mjs +0 -8
  31. package/dist/bg-BG.module.js +0 -8
  32. package/dist/bg-BG.module.js.map +0 -1
  33. package/dist/button_vars_css.main.js +0 -125
  34. package/dist/button_vars_css.main.js.map +0 -1
  35. package/dist/button_vars_css.mjs +0 -127
  36. package/dist/button_vars_css.module.js +0 -127
  37. package/dist/button_vars_css.module.js.map +0 -1
  38. package/dist/cs-CZ.main.js +0 -6
  39. package/dist/cs-CZ.main.js.map +0 -1
  40. package/dist/cs-CZ.mjs +0 -8
  41. package/dist/cs-CZ.module.js +0 -8
  42. package/dist/cs-CZ.module.js.map +0 -1
  43. package/dist/da-DK.main.js +0 -6
  44. package/dist/da-DK.main.js.map +0 -1
  45. package/dist/da-DK.mjs +0 -8
  46. package/dist/da-DK.module.js +0 -8
  47. package/dist/da-DK.module.js.map +0 -1
  48. package/dist/de-DE.main.js +0 -6
  49. package/dist/de-DE.main.js.map +0 -1
  50. package/dist/de-DE.mjs +0 -8
  51. package/dist/de-DE.module.js +0 -8
  52. package/dist/de-DE.module.js.map +0 -1
  53. package/dist/el-GR.main.js +0 -6
  54. package/dist/el-GR.main.js.map +0 -1
  55. package/dist/el-GR.mjs +0 -8
  56. package/dist/el-GR.module.js +0 -8
  57. package/dist/el-GR.module.js.map +0 -1
  58. package/dist/en-US.main.js +0 -6
  59. package/dist/en-US.main.js.map +0 -1
  60. package/dist/en-US.mjs +0 -8
  61. package/dist/en-US.module.js +0 -8
  62. package/dist/en-US.module.js.map +0 -1
  63. package/dist/es-ES.main.js +0 -6
  64. package/dist/es-ES.main.js.map +0 -1
  65. package/dist/es-ES.mjs +0 -8
  66. package/dist/es-ES.module.js +0 -8
  67. package/dist/es-ES.module.js.map +0 -1
  68. package/dist/et-EE.main.js +0 -6
  69. package/dist/et-EE.main.js.map +0 -1
  70. package/dist/et-EE.mjs +0 -8
  71. package/dist/et-EE.module.js +0 -8
  72. package/dist/et-EE.module.js.map +0 -1
  73. package/dist/fi-FI.main.js +0 -6
  74. package/dist/fi-FI.main.js.map +0 -1
  75. package/dist/fi-FI.mjs +0 -8
  76. package/dist/fi-FI.module.js +0 -8
  77. package/dist/fi-FI.module.js.map +0 -1
  78. package/dist/fr-FR.main.js +0 -6
  79. package/dist/fr-FR.main.js.map +0 -1
  80. package/dist/fr-FR.mjs +0 -8
  81. package/dist/fr-FR.module.js +0 -8
  82. package/dist/fr-FR.module.js.map +0 -1
  83. package/dist/he-IL.main.js +0 -6
  84. package/dist/he-IL.main.js.map +0 -1
  85. package/dist/he-IL.mjs +0 -8
  86. package/dist/he-IL.module.js +0 -8
  87. package/dist/he-IL.module.js.map +0 -1
  88. package/dist/hr-HR.main.js +0 -6
  89. package/dist/hr-HR.main.js.map +0 -1
  90. package/dist/hr-HR.mjs +0 -8
  91. package/dist/hr-HR.module.js +0 -8
  92. package/dist/hr-HR.module.js.map +0 -1
  93. package/dist/hu-HU.main.js +0 -6
  94. package/dist/hu-HU.main.js.map +0 -1
  95. package/dist/hu-HU.mjs +0 -8
  96. package/dist/hu-HU.module.js +0 -8
  97. package/dist/hu-HU.module.js.map +0 -1
  98. package/dist/intlStrings.main.js +0 -108
  99. package/dist/intlStrings.main.js.map +0 -1
  100. package/dist/intlStrings.mjs +0 -110
  101. package/dist/intlStrings.module.js +0 -110
  102. package/dist/intlStrings.module.js.map +0 -1
  103. package/dist/it-IT.main.js +0 -6
  104. package/dist/it-IT.main.js.map +0 -1
  105. package/dist/it-IT.mjs +0 -8
  106. package/dist/it-IT.module.js +0 -8
  107. package/dist/it-IT.module.js.map +0 -1
  108. package/dist/ja-JP.main.js +0 -6
  109. package/dist/ja-JP.main.js.map +0 -1
  110. package/dist/ja-JP.mjs +0 -8
  111. package/dist/ja-JP.module.js +0 -8
  112. package/dist/ja-JP.module.js.map +0 -1
  113. package/dist/ko-KR.main.js +0 -6
  114. package/dist/ko-KR.main.js.map +0 -1
  115. package/dist/ko-KR.mjs +0 -8
  116. package/dist/ko-KR.module.js +0 -8
  117. package/dist/ko-KR.module.js.map +0 -1
  118. package/dist/lt-LT.main.js +0 -6
  119. package/dist/lt-LT.main.js.map +0 -1
  120. package/dist/lt-LT.mjs +0 -8
  121. package/dist/lt-LT.module.js +0 -8
  122. package/dist/lt-LT.module.js.map +0 -1
  123. package/dist/lv-LV.main.js +0 -6
  124. package/dist/lv-LV.main.js.map +0 -1
  125. package/dist/lv-LV.mjs +0 -8
  126. package/dist/lv-LV.module.js +0 -8
  127. package/dist/lv-LV.module.js.map +0 -1
  128. package/dist/nb-NO.main.js +0 -6
  129. package/dist/nb-NO.main.js.map +0 -1
  130. package/dist/nb-NO.mjs +0 -8
  131. package/dist/nb-NO.module.js +0 -8
  132. package/dist/nb-NO.module.js.map +0 -1
  133. package/dist/nl-NL.main.js +0 -6
  134. package/dist/nl-NL.main.js.map +0 -1
  135. package/dist/nl-NL.mjs +0 -8
  136. package/dist/nl-NL.module.js +0 -8
  137. package/dist/nl-NL.module.js.map +0 -1
  138. package/dist/pl-PL.main.js +0 -6
  139. package/dist/pl-PL.main.js.map +0 -1
  140. package/dist/pl-PL.mjs +0 -8
  141. package/dist/pl-PL.module.js +0 -8
  142. package/dist/pl-PL.module.js.map +0 -1
  143. package/dist/pt-BR.main.js +0 -6
  144. package/dist/pt-BR.main.js.map +0 -1
  145. package/dist/pt-BR.mjs +0 -8
  146. package/dist/pt-BR.module.js +0 -8
  147. package/dist/pt-BR.module.js.map +0 -1
  148. package/dist/pt-PT.main.js +0 -6
  149. package/dist/pt-PT.main.js.map +0 -1
  150. package/dist/pt-PT.mjs +0 -8
  151. package/dist/pt-PT.module.js +0 -8
  152. package/dist/pt-PT.module.js.map +0 -1
  153. package/dist/ro-RO.main.js +0 -6
  154. package/dist/ro-RO.main.js.map +0 -1
  155. package/dist/ro-RO.mjs +0 -8
  156. package/dist/ro-RO.module.js +0 -8
  157. package/dist/ro-RO.module.js.map +0 -1
  158. package/dist/ru-RU.main.js +0 -6
  159. package/dist/ru-RU.main.js.map +0 -1
  160. package/dist/ru-RU.mjs +0 -8
  161. package/dist/ru-RU.module.js +0 -8
  162. package/dist/ru-RU.module.js.map +0 -1
  163. package/dist/sk-SK.main.js +0 -6
  164. package/dist/sk-SK.main.js.map +0 -1
  165. package/dist/sk-SK.mjs +0 -8
  166. package/dist/sk-SK.module.js +0 -8
  167. package/dist/sk-SK.module.js.map +0 -1
  168. package/dist/sl-SI.main.js +0 -6
  169. package/dist/sl-SI.main.js.map +0 -1
  170. package/dist/sl-SI.mjs +0 -8
  171. package/dist/sl-SI.module.js +0 -8
  172. package/dist/sl-SI.module.js.map +0 -1
  173. package/dist/sr-SP.main.js +0 -6
  174. package/dist/sr-SP.main.js.map +0 -1
  175. package/dist/sr-SP.mjs +0 -8
  176. package/dist/sr-SP.module.js +0 -8
  177. package/dist/sr-SP.module.js.map +0 -1
  178. package/dist/sv-SE.main.js +0 -6
  179. package/dist/sv-SE.main.js.map +0 -1
  180. package/dist/sv-SE.mjs +0 -8
  181. package/dist/sv-SE.module.js +0 -8
  182. package/dist/sv-SE.module.js.map +0 -1
  183. package/dist/tr-TR.main.js +0 -6
  184. package/dist/tr-TR.main.js.map +0 -1
  185. package/dist/tr-TR.mjs +0 -8
  186. package/dist/tr-TR.module.js +0 -8
  187. package/dist/tr-TR.module.js.map +0 -1
  188. package/dist/types.d.ts +0 -13
  189. package/dist/types.d.ts.map +0 -1
  190. package/dist/uk-UA.main.js +0 -6
  191. package/dist/uk-UA.main.js.map +0 -1
  192. package/dist/uk-UA.mjs +0 -8
  193. package/dist/uk-UA.module.js +0 -8
  194. package/dist/uk-UA.module.js.map +0 -1
  195. package/dist/zh-CN.main.js +0 -6
  196. package/dist/zh-CN.main.js.map +0 -1
  197. package/dist/zh-CN.mjs +0 -8
  198. package/dist/zh-CN.module.js +0 -8
  199. package/dist/zh-CN.module.js.map +0 -1
  200. package/dist/zh-TW.main.js +0 -6
  201. package/dist/zh-TW.main.js.map +0 -1
  202. package/dist/zh-TW.mjs +0 -8
  203. package/dist/zh-TW.module.js +0 -8
  204. package/dist/zh-TW.module.js.map +0 -1
  205. package/src/ActionGroup.tsx +0 -500
@@ -1 +0,0 @@
1
- {"mappings":"AAAA,iBAAiB;IAAG,QAAQ,CAAC,gCAAI,CAAC;AAClC","sources":["packages/@react-spectrum/actiongroup/intl/zh-TW.json"],"sourcesContent":["{\n \"more\": \"更多項目\"\n}\n"],"names":[],"version":3,"file":"zh-TW.main.js.map"}
package/dist/zh-TW.mjs DELETED
@@ -1,8 +0,0 @@
1
- var $eb52a2117742078e$exports = {};
2
- $eb52a2117742078e$exports = {
3
- "more": `\u{66F4}\u{591A}\u{9805}\u{76EE}`
4
- };
5
-
6
-
7
- export {$eb52a2117742078e$exports as default};
8
- //# sourceMappingURL=zh-TW.module.js.map
@@ -1,8 +0,0 @@
1
- var $eb52a2117742078e$exports = {};
2
- $eb52a2117742078e$exports = {
3
- "more": `\u{66F4}\u{591A}\u{9805}\u{76EE}`
4
- };
5
-
6
-
7
- export {$eb52a2117742078e$exports as default};
8
- //# sourceMappingURL=zh-TW.module.js.map
@@ -1 +0,0 @@
1
- {"mappings":";AAAA,4BAAiB;IAAG,QAAQ,CAAC,gCAAI,CAAC;AAClC","sources":["packages/@react-spectrum/actiongroup/intl/zh-TW.json"],"sourcesContent":["{\n \"more\": \"更多項目\"\n}\n"],"names":[],"version":3,"file":"zh-TW.module.js.map"}
@@ -1,500 +0,0 @@
1
- /*
2
- * Copyright 2020 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- import {ActionButton} from '@react-spectrum/button';
14
- import {AriaLabelingProps, DOMProps, DOMRef, Key, Node, StyleProps} from '@react-types/shared';
15
- import buttonStyles from '@adobe/spectrum-css-temp/components/button/vars.css';
16
- import ChevronDownMedium from '@spectrum-icons/ui/ChevronDownMedium';
17
- import {
18
- classNames,
19
- ClearSlots,
20
- SlotProvider,
21
- useDOMRef,
22
- useSlotProps,
23
- useStyleProps
24
- } from '@react-spectrum/utils';
25
- import {filterDOMProps, mergeProps, useId, useLayoutEffect, useResizeObserver, useValueEffect} from '@react-aria/utils';
26
- import {FocusScope} from '@react-aria/focus';
27
- // @ts-ignore
28
- import intlMessages from '../intl/*.json';
29
- import {Item, Menu, MenuTrigger} from '@react-spectrum/menu';
30
- import {ListState, useListState} from '@react-stately/list';
31
- import More from '@spectrum-icons/workflow/More';
32
- import {PressResponder, useHover} from '@react-aria/interactions';
33
- import {Provider, useProviderProps} from '@react-spectrum/provider';
34
- import React, {forwardRef, ReactElement, ReactNode, useCallback, useMemo, useRef, useState} from 'react';
35
- import {SpectrumActionGroupProps} from '@react-types/actiongroup';
36
- import styles from '@adobe/spectrum-css-temp/components/actiongroup/vars.css';
37
- import {Text} from '@react-spectrum/text';
38
- import {Tooltip, TooltipTrigger} from '@react-spectrum/tooltip';
39
- import {useActionGroup, useActionGroupItem} from '@react-aria/actiongroup';
40
- import {useLocalizedStringFormatter} from '@react-aria/i18n';
41
-
42
-
43
- /**
44
- * An ActionGroup is a grouping of ActionButtons that are related to one another.
45
- */
46
- export const ActionGroup = forwardRef(function ActionGroup<T extends object>(props: SpectrumActionGroupProps<T>, ref: DOMRef<HTMLDivElement>) {
47
- props = useProviderProps(props);
48
- props = useSlotProps(props, 'actionGroup');
49
-
50
- let {
51
- isEmphasized,
52
- density,
53
- isJustified,
54
- isDisabled,
55
- orientation = 'horizontal',
56
- isQuiet,
57
- staticColor,
58
- overflowMode = 'wrap',
59
- onAction,
60
- buttonLabelBehavior,
61
- summaryIcon,
62
- ...otherProps
63
- } = props;
64
-
65
- let domRef = useDOMRef(ref);
66
- let wrapperRef = useRef<HTMLDivElement>(null);
67
- let state = useListState({...props, suppressTextValueWarning: true});
68
- let {actionGroupProps} = useActionGroup(props, state, domRef);
69
- let isVertical = orientation === 'vertical';
70
- let providerProps = {isEmphasized, isDisabled, isQuiet};
71
- let {styleProps} = useStyleProps(props);
72
-
73
- // Only hide button text if every item contains more than just plain text (we assume an icon).
74
- let isIconCollapsible = useMemo(() => [...state.collection].every(item => typeof item.rendered !== 'string'), [state.collection]);
75
- let [{visibleItems, hideButtonText, isMeasuring}, setVisibleItems] = useValueEffect({
76
- visibleItems: state.collection.size,
77
- hideButtonText: buttonLabelBehavior === 'hide' && isIconCollapsible,
78
- isMeasuring: false
79
- });
80
-
81
- let selectionMode = state.selectionManager.selectionMode;
82
- let updateOverflow = useCallback(() => {
83
- if (overflowMode === 'wrap') {
84
- return;
85
- }
86
-
87
- if (orientation === 'vertical' && selectionMode !== 'none') {
88
- // Collapsing vertical action groups with selection is currently unsupported by Spectrum.
89
- return;
90
- }
91
-
92
- let computeVisibleItems = (visibleItems: number) => {
93
- if (domRef.current && wrapperRef.current) {
94
- let listItems = Array.from(domRef.current.children) as HTMLLIElement[];
95
- let containerSize = orientation === 'horizontal' ? wrapperRef.current.getBoundingClientRect().width : wrapperRef.current.getBoundingClientRect().height;
96
-
97
- let isShowingMenu = visibleItems < state.collection.size;
98
- let calculatedSize = 0;
99
- let newVisibleItems = 0;
100
-
101
- if (isShowingMenu) {
102
- let item = listItems.pop();
103
- if (item) {
104
- calculatedSize += orientation === 'horizontal'
105
- ? outerWidth(item, false, true)
106
- : outerHeight(item, false, true);
107
- }
108
- }
109
-
110
- for (let [i, item] of listItems.entries()) {
111
- calculatedSize += orientation === 'horizontal'
112
- ? outerWidth(item, i === 0, i === listItems.length - 1)
113
- : outerHeight(item, i === 0, i === listItems.length - 1);
114
- if (Math.round(calculatedSize) <= Math.round(containerSize)) {
115
- newVisibleItems++;
116
- } else {
117
- break;
118
- }
119
- }
120
-
121
- // If selection is enabled, and not all of the items fit, collapse all of them into a dropdown
122
- // immediately rather than having some visible and some not.
123
- if (selectionMode !== 'none' && newVisibleItems < state.collection.size) {
124
- return 0;
125
- }
126
-
127
- return newVisibleItems;
128
- }
129
- return visibleItems;
130
- };
131
-
132
- setVisibleItems(function *() {
133
- let hideButtonText = buttonLabelBehavior === 'hide' && isIconCollapsible;
134
-
135
- // Update to show all items.
136
- yield {
137
- visibleItems: state.collection.size,
138
- hideButtonText,
139
- isMeasuring: true
140
- };
141
-
142
- // Measure, and update to show the items that fit.
143
- let newVisibleItems = computeVisibleItems(state.collection.size);
144
- let isMeasuring = newVisibleItems < state.collection.size && newVisibleItems > 0;
145
-
146
- // If not all of the buttons fit, and buttonLabelBehavior is 'collapse', then first try hiding
147
- // the button text and only showing icons. Only if that still doesn't fit collapse into a menu.
148
- if (newVisibleItems < state.collection.size && buttonLabelBehavior === 'collapse' && isIconCollapsible) {
149
- yield {
150
- visibleItems: state.collection.size,
151
- hideButtonText: true,
152
- isMeasuring: true
153
- };
154
-
155
- newVisibleItems = computeVisibleItems(state.collection.size);
156
- isMeasuring = newVisibleItems < state.collection.size && newVisibleItems > 0;
157
- hideButtonText = true;
158
- }
159
-
160
- yield {
161
- visibleItems: newVisibleItems,
162
- hideButtonText,
163
- isMeasuring
164
- };
165
-
166
- // If the number of items is less than the number of children,
167
- // then update again to ensure that the menu fits.
168
- if (isMeasuring) {
169
- yield {
170
- visibleItems: computeVisibleItems(newVisibleItems),
171
- hideButtonText,
172
- isMeasuring: false
173
- };
174
- }
175
- });
176
- }, [domRef, state.collection, setVisibleItems, overflowMode, selectionMode, buttonLabelBehavior, isIconCollapsible, orientation]);
177
-
178
- // Watch the parent element for size changes. Watching only the action group itself may not work
179
- // in all scenarios because it may not shrink when available space is reduced.
180
- let parentRef = useMemo(() => ({
181
- get current() {
182
- return wrapperRef.current?.parentElement;
183
- }
184
- }), [wrapperRef]);
185
- useResizeObserver({ref: overflowMode !== 'wrap' ? parentRef : undefined, onResize: updateOverflow});
186
- useLayoutEffect(updateOverflow, [updateOverflow, state.collection]);
187
-
188
- let children = [...state.collection];
189
- let menuItem: ReactElement | null = null;
190
- let menuProps = {};
191
-
192
- // If there are no visible items, don't apply any props to the action group container
193
- // and pass all aria labeling props through to the menu button.
194
- if (overflowMode === 'collapse' && visibleItems === 0) {
195
- menuProps = filterDOMProps(props, {labelable: true});
196
- actionGroupProps = {};
197
- }
198
-
199
- if (overflowMode === 'collapse' && visibleItems < state.collection.size) {
200
- let menuChildren = children.slice(visibleItems);
201
- children = children.slice(0, visibleItems);
202
- menuItem = (
203
- <ActionGroupMenu
204
- {...menuProps}
205
- items={menuChildren}
206
- onAction={onAction}
207
- isDisabled={isDisabled}
208
- isEmphasized={isEmphasized}
209
- staticColor={staticColor}
210
- state={state}
211
- summaryIcon={summaryIcon}
212
- hideButtonText={hideButtonText}
213
- isOnlyItem={visibleItems === 0}
214
- orientation={orientation} />
215
- );
216
- }
217
-
218
- let style = {
219
- ...styleProps.style,
220
- // While measuring, take up as much space as possible.
221
- flexBasis: isMeasuring ? '100%' : undefined
222
- };
223
-
224
- return (
225
- <FocusScope>
226
- <div {...styleProps} style={style} className={classNames(styles, 'flex-container', styleProps.className)} ref={wrapperRef}>
227
- <div
228
- {...actionGroupProps}
229
- ref={domRef}
230
- className={
231
- classNames(
232
- styles,
233
- 'flex-gap',
234
- 'spectrum-ActionGroup',
235
- {
236
- 'spectrum-ActionGroup--quiet': isQuiet,
237
- 'spectrum-ActionGroup--vertical': isVertical,
238
- 'spectrum-ActionGroup--compact': density === 'compact',
239
- 'spectrum-ActionGroup--justified': isJustified && !isMeasuring,
240
- 'spectrum-ActionGroup--overflowCollapse': overflowMode === 'collapse'
241
- },
242
- otherProps.UNSAFE_className
243
- )
244
- }>
245
- <Provider {...providerProps}>
246
- {children.map((item) => (
247
- <ActionGroupItem
248
- key={item.key}
249
- onAction={onAction}
250
- isDisabled={isDisabled}
251
- isEmphasized={isEmphasized}
252
- staticColor={staticColor}
253
- item={item}
254
- state={state}
255
- hideButtonText={hideButtonText}
256
- orientation={orientation} />
257
- ))}
258
- {menuItem}
259
- </Provider>
260
- </div>
261
- </div>
262
- </FocusScope>
263
- );
264
- }) as <T>(props: SpectrumActionGroupProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
265
-
266
- interface ActionGroupItemProps<T> extends DOMProps, StyleProps {
267
- item: Node<T>,
268
- state: ListState<T>,
269
- isDisabled?: boolean,
270
- isEmphasized?: boolean,
271
- staticColor?: 'white' | 'black',
272
- hideButtonText?: boolean,
273
- orientation?: 'horizontal' | 'vertical',
274
- onAction?: (key: Key) => void
275
- }
276
-
277
- function ActionGroupItem<T>({item, state, isDisabled, isEmphasized, staticColor, onAction, hideButtonText, orientation}: ActionGroupItemProps<T>) {
278
- let ref = useRef(null);
279
- let {buttonProps} = useActionGroupItem({key: item.key}, state);
280
- isDisabled = isDisabled || state.disabledKeys.has(item.key);
281
- let isSelected = state.selectionManager.isSelected(item.key);
282
- let {hoverProps, isHovered} = useHover({isDisabled});
283
- let domProps = filterDOMProps(item.props);
284
-
285
- if (onAction && !isDisabled) {
286
- buttonProps = mergeProps(buttonProps, {
287
- onPress: () => onAction(item.key)
288
- });
289
- }
290
-
291
- // If button text is hidden, we need to show it as a tooltip instead, so
292
- // go find the text element in the DOM after rendering.
293
- let textId = useId();
294
- let [textContent, setTextContent] = useState<string | null | undefined>('');
295
- useLayoutEffect(() => {
296
- if (hideButtonText) {
297
- setTextContent(document.getElementById(textId)?.textContent);
298
- }
299
- }, [hideButtonText, item.rendered, textId]);
300
-
301
- let button = (
302
- // Use a PressResponder to send DOM props through.
303
- // ActionButton doesn't allow overriding the role by default.
304
- <PressResponder {...mergeProps(buttonProps, hoverProps, domProps)}>
305
- <ClearSlots>
306
- <SlotProvider
307
- slots={{
308
- text: {
309
- id: hideButtonText ? textId : null,
310
- isHidden: hideButtonText
311
- }
312
- }}>
313
- <ActionButton
314
- ref={ref}
315
- // @ts-ignore (private)
316
- hideButtonText={hideButtonText}
317
- UNSAFE_className={
318
- classNames(
319
- styles,
320
- 'spectrum-ActionGroup-item',
321
- {
322
- 'is-selected': isSelected,
323
- 'is-hovered': isHovered,
324
- 'spectrum-ActionGroup-item--iconOnly': hideButtonText,
325
- 'spectrum-ActionGroup-item--isDisabled': isDisabled
326
- },
327
- classNames(
328
- buttonStyles,
329
- {
330
- 'spectrum-ActionButton--emphasized': isEmphasized,
331
- 'is-selected': isSelected
332
- }
333
- )
334
- )
335
- }
336
- isDisabled={isDisabled}
337
- staticColor={staticColor}
338
- aria-label={item['aria-label']}
339
- aria-labelledby={item['aria-label'] == null && hideButtonText ? textId : undefined}>
340
- {item.rendered}
341
- </ActionButton>
342
- </SlotProvider>
343
- </ClearSlots>
344
- </PressResponder>
345
- );
346
-
347
- if (hideButtonText && textContent) {
348
- button = (
349
- <TooltipTrigger placement={orientation === 'vertical' ? 'end' : 'top'}>
350
- {button}
351
- <Tooltip>{textContent}</Tooltip>
352
- </TooltipTrigger>
353
- );
354
- }
355
-
356
- if (item.wrapper) {
357
- button = item.wrapper(button);
358
- }
359
-
360
- return button;
361
- }
362
-
363
- interface ActionGroupMenuProps<T> extends AriaLabelingProps {
364
- state: ListState<T>,
365
- isDisabled?: boolean,
366
- isEmphasized?: boolean,
367
- staticColor?: 'white' | 'black',
368
- items: Node<T>[],
369
- hideButtonText?: boolean,
370
- summaryIcon?: ReactNode,
371
- isOnlyItem?: boolean,
372
- orientation?: 'horizontal' | 'vertical',
373
- onAction?: (key: Key) => void
374
- }
375
-
376
- function ActionGroupMenu<T>({state, isDisabled, isEmphasized, staticColor, items, onAction, summaryIcon, hideButtonText, isOnlyItem, orientation, ...otherProps}: ActionGroupMenuProps<T>) {
377
- // Use the key of the first item within the menu as the key of the button.
378
- // The key must actually exist in the collection for focus to work correctly.
379
- let key = items[0].key;
380
- let {buttonProps} = useActionGroupItem({key}, state);
381
- let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/actiongroup');
382
-
383
- // The menu button shouldn't act like an actual action group item.
384
- delete buttonProps.onPress;
385
- delete buttonProps.role;
386
- delete buttonProps['aria-checked'];
387
-
388
- let {hoverProps, isHovered} = useHover({isDisabled});
389
-
390
- // If no aria-label or aria-labelledby is given, provide a default one.
391
- let ariaLabel = otherProps['aria-label'] || (otherProps['aria-labelledby'] ? undefined : stringFormatter.format('more'));
392
- let ariaLabelledby = otherProps['aria-labelledby'];
393
- let textId = useId();
394
- let id = useId();
395
-
396
- // Summary icon only applies when selection is enabled.
397
- if (state.selectionManager.selectionMode === 'none') {
398
- summaryIcon = null;
399
- }
400
-
401
- let iconOnly = false;
402
-
403
- // If there is a selection, show the selected state on the menu button.
404
- let isSelected = state.selectionManager.selectionMode !== 'none' && !state.selectionManager.isEmpty;
405
-
406
- // If single selection and empty selection is not allowed, swap the contents of the button to the selected item (like a Picker).
407
- if (!summaryIcon && state.selectionManager.selectionMode === 'single' && state.selectionManager.disallowEmptySelection && state.selectionManager.firstSelectedKey != null) {
408
- let selectedItem = state.collection.getItem(state.selectionManager.firstSelectedKey);
409
- if (selectedItem) {
410
- summaryIcon = selectedItem.rendered;
411
- if (typeof summaryIcon === 'string') {
412
- summaryIcon = <Text>{summaryIcon}</Text>;
413
- }
414
- iconOnly = !!hideButtonText;
415
- ariaLabelledby = `${ariaLabelledby ?? id} ${textId}`;
416
- }
417
- }
418
-
419
- if (summaryIcon) {
420
- // If there's a custom summary icon, also add a chevron.
421
- summaryIcon = (
422
- <>
423
- <ChevronDownMedium UNSAFE_className={classNames(styles, 'spectrum-ActionGroup-menu-chevron')} />
424
- <span className={classNames(styles, 'spectrum-ActionGroup-menu-contents', {'spectrum-ActionGroup-item--iconOnly': iconOnly})}>
425
- {summaryIcon}
426
- </span>
427
- </>
428
- );
429
- }
430
-
431
- return (
432
- // Use a PressResponder to send DOM props through.
433
- <MenuTrigger align={isOnlyItem ? 'start' : 'end'} direction={orientation === 'vertical' ? 'end' : 'bottom'}>
434
- <SlotProvider
435
- slots={{
436
- text: {
437
- id: hideButtonText ? textId : null,
438
- isHidden: hideButtonText,
439
- UNSAFE_className: classNames(styles, 'spectrum-ActionGroup-menu-text')
440
- }
441
- }}>
442
- <PressResponder {...mergeProps(buttonProps, hoverProps)}>
443
- <ActionButton
444
- {...otherProps}
445
- id={id}
446
- aria-label={ariaLabel}
447
- aria-labelledby={ariaLabelledby}
448
- UNSAFE_className={
449
- classNames(
450
- styles,
451
- 'spectrum-ActionGroup-item',
452
- 'spectrum-ActionGroup-menu',
453
- {
454
- 'is-hovered': isHovered,
455
- 'is-selected': isSelected
456
- },
457
- classNames(
458
- buttonStyles,
459
- {
460
- 'is-selected': isSelected,
461
- 'spectrum-ActionButton--emphasized': isEmphasized
462
- }
463
- )
464
- )
465
- }
466
- isDisabled={isDisabled}
467
- staticColor={staticColor}>
468
- {summaryIcon || <More />}
469
- </ActionButton>
470
- </PressResponder>
471
- </SlotProvider>
472
- <Menu
473
- items={items}
474
- disabledKeys={state.disabledKeys}
475
- selectionMode={state.selectionManager.selectionMode}
476
- selectedKeys={state.selectionManager.selectedKeys}
477
- disallowEmptySelection={state.selectionManager.disallowEmptySelection}
478
- onSelectionChange={(keys) => state.selectionManager.setSelectedKeys(keys)}
479
- onAction={onAction}>
480
- {node => <Item textValue={node.textValue} {...filterDOMProps(node.props)}>{node.rendered}</Item>}
481
- </Menu>
482
- </MenuTrigger>
483
- );
484
- }
485
-
486
- function outerWidth(element: HTMLElement, ignoreLeftMargin: boolean, ignoreRightMargin: boolean) {
487
- let style = window.getComputedStyle(element);
488
- return element.getBoundingClientRect().width + (ignoreLeftMargin ? 0 : toNumber(style.marginLeft)) + (ignoreRightMargin ? 0 : toNumber(style.marginRight));
489
- }
490
-
491
-
492
- function outerHeight(element: HTMLElement, ignoreTopMargin: boolean, ignoreBottomMargin: boolean) {
493
- let style = window.getComputedStyle(element);
494
- return element.getBoundingClientRect().height + (ignoreTopMargin ? 0 : toNumber(style.marginTop)) + (ignoreBottomMargin ? 0 : toNumber(style.marginBottom));
495
- }
496
-
497
- function toNumber(value: string) {
498
- let parsed = parseInt(value, 10);
499
- return isNaN(parsed) ? 0 : parsed;
500
- }