@wordpress/components 19.0.3 → 19.1.1

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 (116) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/build/circular-option-picker/index.js +2 -2
  3. package/build/circular-option-picker/index.js.map +1 -1
  4. package/build/color-palette/index.js +1 -0
  5. package/build/color-palette/index.js.map +1 -1
  6. package/build/date-time/time.js +17 -3
  7. package/build/date-time/time.js.map +1 -1
  8. package/build/duotone-picker/duotone-picker.js +2 -1
  9. package/build/duotone-picker/duotone-picker.js.map +1 -1
  10. package/build/font-size-picker/index.js +2 -1
  11. package/build/font-size-picker/index.js.map +1 -1
  12. package/build/index.js +7 -7
  13. package/build/index.js.map +1 -1
  14. package/build/mobile/global-styles-context/utils.native.js +3 -3
  15. package/build/mobile/global-styles-context/utils.native.js.map +1 -1
  16. package/build/navigation/item/index.js +6 -3
  17. package/build/navigation/item/index.js.map +1 -1
  18. package/build/navigation/styles/navigation-styles.js +37 -30
  19. package/build/navigation/styles/navigation-styles.js.map +1 -1
  20. package/build/palette-edit/index.js +303 -0
  21. package/build/palette-edit/index.js.map +1 -0
  22. package/build/palette-edit/styles.js +112 -0
  23. package/build/palette-edit/styles.js.map +1 -0
  24. package/build/popover/index.js +1 -1
  25. package/build/popover/index.js.map +1 -1
  26. package/build/toggle-group-control/toggle-group-control-option/component.js +30 -4
  27. package/build/toggle-group-control/toggle-group-control-option/component.js.map +1 -1
  28. package/build/tooltip/index.js +4 -4
  29. package/build/tooltip/index.js.map +1 -1
  30. package/build-module/circular-option-picker/index.js +2 -2
  31. package/build-module/circular-option-picker/index.js.map +1 -1
  32. package/build-module/color-palette/index.js +1 -0
  33. package/build-module/color-palette/index.js.map +1 -1
  34. package/build-module/date-time/time.js +17 -3
  35. package/build-module/date-time/time.js.map +1 -1
  36. package/build-module/duotone-picker/duotone-picker.js +2 -1
  37. package/build-module/duotone-picker/duotone-picker.js.map +1 -1
  38. package/build-module/font-size-picker/index.js +2 -1
  39. package/build-module/font-size-picker/index.js.map +1 -1
  40. package/build-module/index.js +1 -1
  41. package/build-module/index.js.map +1 -1
  42. package/build-module/mobile/global-styles-context/utils.native.js +3 -3
  43. package/build-module/mobile/global-styles-context/utils.native.js.map +1 -1
  44. package/build-module/navigation/item/index.js +7 -4
  45. package/build-module/navigation/item/index.js.map +1 -1
  46. package/build-module/navigation/styles/navigation-styles.js +34 -28
  47. package/build-module/navigation/styles/navigation-styles.js.map +1 -1
  48. package/build-module/palette-edit/index.js +276 -0
  49. package/build-module/palette-edit/index.js.map +1 -0
  50. package/build-module/palette-edit/styles.js +90 -0
  51. package/build-module/palette-edit/styles.js.map +1 -0
  52. package/build-module/popover/index.js +1 -1
  53. package/build-module/popover/index.js.map +1 -1
  54. package/build-module/toggle-group-control/toggle-group-control-option/component.js +26 -5
  55. package/build-module/toggle-group-control/toggle-group-control-option/component.js.map +1 -1
  56. package/build-module/tooltip/index.js +4 -4
  57. package/build-module/tooltip/index.js.map +1 -1
  58. package/build-style/style-rtl.css +21 -1
  59. package/build-style/style.css +21 -1
  60. package/build-types/confirm-dialog/component.d.ts +34 -0
  61. package/build-types/confirm-dialog/component.d.ts.map +1 -0
  62. package/build-types/confirm-dialog/index.d.ts +6 -0
  63. package/build-types/confirm-dialog/index.d.ts.map +1 -0
  64. package/build-types/confirm-dialog/types.d.ts +20 -0
  65. package/build-types/confirm-dialog/types.d.ts.map +1 -0
  66. package/build-types/higher-order/with-focus-outside/index.d.ts +3 -0
  67. package/build-types/higher-order/with-focus-outside/index.d.ts.map +1 -0
  68. package/build-types/modal/aria-helper.d.ts +27 -0
  69. package/build-types/modal/aria-helper.d.ts.map +1 -0
  70. package/build-types/modal/index.d.ts +3 -0
  71. package/build-types/modal/index.d.ts.map +1 -0
  72. package/build-types/popover/index.d.ts.map +1 -1
  73. package/build-types/style-provider/index.d.ts +5 -0
  74. package/build-types/style-provider/index.d.ts.map +1 -0
  75. package/build-types/toggle-group-control/toggle-group-control-option/component.d.ts.map +1 -1
  76. package/build-types/toggle-group-control/types.d.ts +23 -0
  77. package/build-types/toggle-group-control/types.d.ts.map +1 -1
  78. package/build-types/tooltip/index.d.ts +1 -7
  79. package/build-types/tooltip/index.d.ts.map +1 -1
  80. package/package.json +2 -2
  81. package/src/circular-option-picker/index.js +7 -5
  82. package/src/color-palette/index.js +1 -0
  83. package/src/color-palette/style.scss +9 -0
  84. package/src/color-palette/test/__snapshots__/index.js.snap +2 -0
  85. package/src/date-time/test/time.js +32 -2
  86. package/src/date-time/time.js +14 -6
  87. package/src/duotone-picker/duotone-picker.js +8 -5
  88. package/src/font-size-picker/index.js +1 -0
  89. package/src/index.js +1 -1
  90. package/src/mobile/global-styles-context/test/fixtures/theme.native.js +4 -4
  91. package/src/mobile/global-styles-context/utils.native.js +3 -3
  92. package/src/navigation/item/index.js +10 -3
  93. package/src/navigation/stories/more-examples.js +2 -1
  94. package/src/navigation/styles/navigation-styles.js +5 -0
  95. package/src/palette-edit/index.js +392 -0
  96. package/src/palette-edit/style.scss +19 -0
  97. package/src/{color-edit → palette-edit}/styles.js +15 -18
  98. package/src/popover/index.js +5 -1
  99. package/src/style.scss +1 -1
  100. package/src/toggle-group-control/stories/index.js +15 -0
  101. package/src/toggle-group-control/test/index.js +57 -0
  102. package/src/toggle-group-control/toggle-group-control-option/README.md +8 -1
  103. package/src/toggle-group-control/toggle-group-control-option/component.tsx +40 -17
  104. package/src/toggle-group-control/types.ts +24 -0
  105. package/src/tooltip/index.js +2 -7
  106. package/tsconfig.tsbuildinfo +1 -1
  107. package/build/color-edit/index.js +0 -251
  108. package/build/color-edit/index.js.map +0 -1
  109. package/build/color-edit/styles.js +0 -112
  110. package/build/color-edit/styles.js.map +0 -1
  111. package/build-module/color-edit/index.js +0 -227
  112. package/build-module/color-edit/index.js.map +0 -1
  113. package/build-module/color-edit/styles.js +0 -90
  114. package/build-module/color-edit/styles.js.map +0 -1
  115. package/src/color-edit/index.js +0 -300
  116. package/src/color-edit/style.scss +0 -6
@@ -0,0 +1,392 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { kebabCase } from 'lodash';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useState, useRef, useEffect } from '@wordpress/element';
10
+ import { __ } from '@wordpress/i18n';
11
+ import { lineSolid, moreVertical, plus } from '@wordpress/icons';
12
+ import { __experimentalUseFocusOutside as useFocusOutside } from '@wordpress/compose';
13
+
14
+ /**
15
+ * Internal dependencies
16
+ */
17
+ import Button from '../button';
18
+ import { ColorPicker } from '../color-picker';
19
+ import { FlexItem } from '../flex';
20
+ import { HStack } from '../h-stack';
21
+ import { ItemGroup } from '../item-group';
22
+ import { VStack } from '../v-stack';
23
+ import GradientPicker from '../gradient-picker';
24
+ import ColorPalette from '../color-palette';
25
+ import DropdownMenu from '../dropdown-menu';
26
+ import Popover from '../popover';
27
+ import {
28
+ PaletteActionsContainer,
29
+ PaletteEditStyles,
30
+ PaletteHeading,
31
+ PaletteHStackHeader,
32
+ IndicatorStyled,
33
+ PaletteItem,
34
+ NameContainer,
35
+ NameInputControl,
36
+ DoneButton,
37
+ RemoveButton,
38
+ } from './styles';
39
+ import { NavigableMenu } from '../navigable-container';
40
+ import { DEFAULT_GRADIENT } from '../custom-gradient-picker/constants';
41
+ import CustomGradientPicker from '../custom-gradient-picker';
42
+
43
+ function NameInput( { value, onChange, label } ) {
44
+ return (
45
+ <NameInputControl
46
+ label={ label }
47
+ hideLabelFromVision
48
+ value={ value }
49
+ onChange={ onChange }
50
+ />
51
+ );
52
+ }
53
+
54
+ function Option( {
55
+ canOnlyChangeValues,
56
+ element,
57
+ onChange,
58
+ isEditing,
59
+ onStartEditing,
60
+ onRemove,
61
+ onStopEditing,
62
+ slugPrefix,
63
+ isGradient,
64
+ } ) {
65
+ const focusOutsideProps = useFocusOutside( onStopEditing );
66
+ const value = isGradient ? element.gradient : element.color;
67
+ return (
68
+ <PaletteItem
69
+ as="div"
70
+ onClick={ onStartEditing }
71
+ { ...( isEditing ? focusOutsideProps : {} ) }
72
+ >
73
+ <HStack justify="flex-start">
74
+ <FlexItem>
75
+ <IndicatorStyled
76
+ style={ { background: value, color: 'transparent' } }
77
+ />
78
+ </FlexItem>
79
+ <FlexItem>
80
+ { isEditing && ! canOnlyChangeValues ? (
81
+ <NameInput
82
+ label={
83
+ isGradient
84
+ ? __( 'Gradient name' )
85
+ : __( 'Color name' )
86
+ }
87
+ value={ element.name }
88
+ onChange={ ( nextName ) =>
89
+ onChange( {
90
+ ...element,
91
+ name: nextName,
92
+ slug: slugPrefix + kebabCase( nextName ),
93
+ } )
94
+ }
95
+ />
96
+ ) : (
97
+ <NameContainer>{ element.name }</NameContainer>
98
+ ) }
99
+ </FlexItem>
100
+ { isEditing && ! canOnlyChangeValues && (
101
+ <FlexItem>
102
+ <RemoveButton
103
+ isSmall
104
+ icon={ lineSolid }
105
+ label={ __( 'Remove color' ) }
106
+ onClick={ onRemove }
107
+ />
108
+ </FlexItem>
109
+ ) }
110
+ </HStack>
111
+ { isEditing && (
112
+ <Popover
113
+ position="bottom left"
114
+ className="components-palette-edit__popover"
115
+ >
116
+ { ! isGradient && (
117
+ <ColorPicker
118
+ color={ value }
119
+ onChange={ ( newColor ) =>
120
+ onChange( {
121
+ ...element,
122
+ color: newColor,
123
+ } )
124
+ }
125
+ />
126
+ ) }
127
+ { isGradient && (
128
+ <CustomGradientPicker
129
+ value={ value }
130
+ onChange={ ( newGradient ) =>
131
+ onChange( {
132
+ ...element,
133
+ gradient: newGradient,
134
+ } )
135
+ }
136
+ />
137
+ ) }
138
+ </Popover>
139
+ ) }
140
+ </PaletteItem>
141
+ );
142
+ }
143
+
144
+ function PaletteEditListView( {
145
+ elements,
146
+ onChange,
147
+ editingElement,
148
+ setEditingElement,
149
+ canOnlyChangeValues,
150
+ slugPrefix,
151
+ isGradient,
152
+ } ) {
153
+ // When unmounting the component if there are empty elements (the user did not complete the insertion) clean them.
154
+ const elementsReference = useRef();
155
+ useEffect( () => {
156
+ elementsReference.current = elements;
157
+ }, [ elements ] );
158
+ useEffect( () => {
159
+ return () => {
160
+ if ( elementsReference.current.some( ( { slug } ) => ! slug ) ) {
161
+ const newElements = elementsReference.current.filter(
162
+ ( { slug } ) => slug
163
+ );
164
+ onChange( newElements.length ? newElements : undefined );
165
+ }
166
+ };
167
+ }, [] );
168
+ return (
169
+ <VStack spacing={ 3 }>
170
+ <ItemGroup isBordered isSeparated>
171
+ { elements.map( ( element, index ) => (
172
+ <Option
173
+ isGradient={ isGradient }
174
+ canOnlyChangeValues={ canOnlyChangeValues }
175
+ key={ index }
176
+ element={ element }
177
+ onStartEditing={ () => {
178
+ if ( editingElement !== index ) {
179
+ setEditingElement( index );
180
+ }
181
+ } }
182
+ onChange={ ( newElement ) => {
183
+ onChange(
184
+ elements.map(
185
+ ( currentElement, currentIndex ) => {
186
+ if ( currentIndex === index ) {
187
+ return newElement;
188
+ }
189
+ return currentElement;
190
+ }
191
+ )
192
+ );
193
+ } }
194
+ onRemove={ () => {
195
+ setEditingElement( null );
196
+ const newElements = elements.filter(
197
+ ( _currentElement, currentIndex ) => {
198
+ if ( currentIndex === index ) {
199
+ return false;
200
+ }
201
+ return true;
202
+ }
203
+ );
204
+ onChange(
205
+ newElements.length ? newElements : undefined
206
+ );
207
+ } }
208
+ isEditing={ index === editingElement }
209
+ onStopEditing={ () => {
210
+ if ( index === editingElement ) {
211
+ setEditingElement( null );
212
+ }
213
+ } }
214
+ slugPrefix={ slugPrefix }
215
+ />
216
+ ) ) }
217
+ </ItemGroup>
218
+ </VStack>
219
+ );
220
+ }
221
+
222
+ const EMPTY_ARRAY = [];
223
+
224
+ export default function PaletteEdit( {
225
+ gradients,
226
+ colors = EMPTY_ARRAY,
227
+ onChange,
228
+ paletteLabel,
229
+ emptyMessage,
230
+ canOnlyChangeValues,
231
+ canReset,
232
+ slugPrefix = '',
233
+ } ) {
234
+ const isGradient = !! gradients;
235
+ const elements = isGradient ? gradients : colors;
236
+ const [ isEditing, setIsEditing ] = useState( false );
237
+ const [ editingElement, setEditingElement ] = useState( null );
238
+ const isAdding =
239
+ isEditing &&
240
+ editingElement &&
241
+ elements[ editingElement ] &&
242
+ ! elements[ editingElement ].slug;
243
+
244
+ const hasElements = elements.length > 0;
245
+
246
+ return (
247
+ <PaletteEditStyles>
248
+ <PaletteHStackHeader>
249
+ <PaletteHeading>{ paletteLabel }</PaletteHeading>
250
+ <PaletteActionsContainer>
251
+ { isEditing && (
252
+ <DoneButton
253
+ isSmall
254
+ onClick={ () => {
255
+ setIsEditing( false );
256
+ setEditingElement( null );
257
+ } }
258
+ >
259
+ { __( 'Done' ) }
260
+ </DoneButton>
261
+ ) }
262
+ { ! canOnlyChangeValues && (
263
+ <Button
264
+ isSmall
265
+ isPressed={ isAdding }
266
+ icon={ plus }
267
+ label={
268
+ isGradient
269
+ ? __( 'Add gradient' )
270
+ : __( 'Add color' )
271
+ }
272
+ onClick={ () => {
273
+ onChange( [
274
+ ...elements,
275
+ {
276
+ ...( isGradient
277
+ ? { gradient: DEFAULT_GRADIENT }
278
+ : { color: '#000' } ),
279
+ name: '',
280
+ slug: '',
281
+ },
282
+ ] );
283
+ setIsEditing( true );
284
+ setEditingElement( elements.length );
285
+ } }
286
+ />
287
+ ) }
288
+ { ! isEditing && (
289
+ <Button
290
+ disabled={ ! hasElements }
291
+ isSmall
292
+ icon={ moreVertical }
293
+ label={
294
+ isGradient
295
+ ? __( 'Edit gradients' )
296
+ : __( 'Edit colors' )
297
+ }
298
+ onClick={ () => {
299
+ setIsEditing( true );
300
+ } }
301
+ />
302
+ ) }
303
+ { isEditing && ( canReset || ! canOnlyChangeValues ) && (
304
+ <DropdownMenu
305
+ icon={ moreVertical }
306
+ label={
307
+ isGradient
308
+ ? __( 'Gradient options' )
309
+ : __( 'Color options' )
310
+ }
311
+ toggleProps={ {
312
+ isSmall: true,
313
+ } }
314
+ >
315
+ { ( { onClose } ) => (
316
+ <>
317
+ <NavigableMenu role="menu">
318
+ { ! canOnlyChangeValues && (
319
+ <Button
320
+ variant="tertiary"
321
+ onClick={ () => {
322
+ setEditingElement( null );
323
+ setIsEditing( false );
324
+ onChange();
325
+ onClose();
326
+ } }
327
+ >
328
+ { isGradient
329
+ ? __(
330
+ 'Remove all gradients'
331
+ )
332
+ : __(
333
+ 'Remove all colors'
334
+ ) }
335
+ </Button>
336
+ ) }
337
+ { canReset && (
338
+ <Button
339
+ variant="tertiary"
340
+ onClick={ () => {
341
+ setEditingElement( null );
342
+ onChange();
343
+ onClose();
344
+ } }
345
+ >
346
+ { isGradient
347
+ ? __( 'Reset gradient' )
348
+ : __( 'Reset colors' ) }
349
+ </Button>
350
+ ) }
351
+ </NavigableMenu>
352
+ </>
353
+ ) }
354
+ </DropdownMenu>
355
+ ) }
356
+ </PaletteActionsContainer>
357
+ </PaletteHStackHeader>
358
+ { hasElements && (
359
+ <>
360
+ { isEditing && (
361
+ <PaletteEditListView
362
+ canOnlyChangeValues={ canOnlyChangeValues }
363
+ elements={ elements }
364
+ onChange={ onChange }
365
+ editingElement={ editingElement }
366
+ setEditingElement={ setEditingElement }
367
+ slugPrefix={ slugPrefix }
368
+ isGradient={ isGradient }
369
+ />
370
+ ) }
371
+ { ! isEditing &&
372
+ ( isGradient ? (
373
+ <GradientPicker
374
+ gradients={ gradients }
375
+ onChange={ () => {} }
376
+ clearable={ false }
377
+ disableCustomGradients={ true }
378
+ />
379
+ ) : (
380
+ <ColorPalette
381
+ colors={ colors }
382
+ onChange={ () => {} }
383
+ clearable={ false }
384
+ disableCustomColors={ true }
385
+ />
386
+ ) ) }
387
+ </>
388
+ ) }
389
+ { ! hasElements && emptyMessage }
390
+ </PaletteEditStyles>
391
+ );
392
+ }
@@ -0,0 +1,19 @@
1
+ @include break-medium() {
2
+ .components-palette-edit__popover.components-popover .components-popover__content.components-popover__content.components-popover__content {
3
+ margin-right: #{ math.div($sidebar-width, 2) + $grid-unit-20 };
4
+ margin-top: #{ -($grid-unit-60 + $border-width) };
5
+ }
6
+ }
7
+
8
+ .components-palette-edit__popover {
9
+ .components-custom-gradient-picker__gradient-bar {
10
+ margin-top: 0;
11
+ }
12
+ .components-custom-gradient-picker__ui-line {
13
+ margin-bottom: 0;
14
+ }
15
+ .components-custom-gradient-picker {
16
+ width: 280px;
17
+ padding: 8px;
18
+ }
19
+ }
@@ -12,7 +12,6 @@ import { HStack } from '../h-stack';
12
12
  import { space } from '../ui/utils/space';
13
13
  import { COLORS, CONFIG } from '../utils';
14
14
  import { View } from '../view';
15
- import ColorIndicator from '../color-indicator';
16
15
  import InputControl from '../input-control';
17
16
  import Item from '../item-group/item';
18
17
  import {
@@ -20,20 +19,15 @@ import {
20
19
  Input,
21
20
  BackdropUI as InputBackdropUI,
22
21
  } from '../input-control/styles/input-control-styles';
22
+ import CircularOptionPicker from '../circular-option-picker';
23
23
 
24
- export const ColorIndicatorStyled = styled( ColorIndicator )`
25
- && {
26
- display: block;
27
- border-radius: 50%;
28
- border: 0;
29
- height: ${ space( 6 ) };
30
- width: ${ space( 6 ) };
31
- margin-left: 0;
32
- padding: 0;
33
- }
24
+ export const IndicatorStyled = styled( CircularOptionPicker.Option )`
25
+ width: ${ space( 6 ) };
26
+ height: ${ space( 6 ) };
27
+ pointer-events: none;
34
28
  `;
35
29
 
36
- export const ColorNameInputControl = styled( InputControl )`
30
+ export const NameInputControl = styled( InputControl )`
37
31
  ${ InputControlContainer } {
38
32
  background: ${ COLORS.gray[ 100 ] };
39
33
  border-radius: 2px;
@@ -47,17 +41,20 @@ export const ColorNameInputControl = styled( InputControl )`
47
41
  }
48
42
  `;
49
43
 
50
- export const ColorItem = styled( Item )`
44
+ export const PaletteItem = styled( Item )`
51
45
  padding: 3px 0 3px ${ space( 3 ) };
52
46
  height: calc( 40px - ${ CONFIG.borderWidth } );
53
47
  `;
54
48
 
55
- export const ColorNameContainer = styled.span`
49
+ export const NameContainer = styled.div`
56
50
  line-height: ${ space( 8 ) };
57
51
  margin-left: ${ space( 2 ) };
52
+ margin-right: ${ space( 2 ) };
53
+ white-space: nowrap;
54
+ overflow: hidden;
58
55
  `;
59
56
 
60
- export const ColorHeading = styled( Heading )`
57
+ export const PaletteHeading = styled( Heading )`
61
58
  text-transform: uppercase;
62
59
  line-height: ${ space( 6 ) };
63
60
  font-weight: 500;
@@ -67,16 +64,16 @@ export const ColorHeading = styled( Heading )`
67
64
  }
68
65
  `;
69
66
 
70
- export const ColorActionsContainer = styled( View )`
67
+ export const PaletteActionsContainer = styled( View )`
71
68
  height: ${ space( 6 ) };
72
69
  display: flex;
73
70
  `;
74
71
 
75
- export const ColorHStackHeader = styled( HStack )`
72
+ export const PaletteHStackHeader = styled( HStack )`
76
73
  margin-bottom: ${ space( 2 ) };
77
74
  `;
78
75
 
79
- export const ColorEditStyles = styled( View )`
76
+ export const PaletteEditStyles = styled( View )`
80
77
  &&& {
81
78
  .components-button.has-icon {
82
79
  min-width: 0;
@@ -131,7 +131,11 @@ function computeAnchorRect(
131
131
  }
132
132
 
133
133
  const { parentNode } = anchorRefFallback.current;
134
- const rect = parentNode.getBoundingClientRect();
134
+ const rect = offsetIframe(
135
+ parentNode.getBoundingClientRect(),
136
+ parentNode.ownerDocument,
137
+ container
138
+ );
135
139
 
136
140
  if ( shouldAnchorIncludePadding ) {
137
141
  return rect;
package/src/style.scss CHANGED
@@ -4,7 +4,7 @@
4
4
  @import "./button/style.scss";
5
5
  @import "./checkbox-control/style.scss";
6
6
  @import "./circular-option-picker/style.scss";
7
- @import "./color-edit/style.scss";
7
+ @import "./palette-edit/style.scss";
8
8
  @import "./color-indicator/style.scss";
9
9
  @import "./combobox-control/style.scss";
10
10
  @import "./color-list-picker/style.scss";
@@ -71,6 +71,11 @@ const _default = ( { options } ) => {
71
71
  opt[ 'aria-label' ],
72
72
  `${ KNOBS_GROUPS.ToggleGroupControlOption }-${ index + 1 }`
73
73
  ) }
74
+ showTooltip={ boolean(
75
+ `${ KNOBS_GROUPS.ToggleGroupControlOption }: showTooltip`,
76
+ opt.showTooltip,
77
+ `${ KNOBS_GROUPS.ToggleGroupControlOption }-${ index + 1 }`
78
+ ) }
74
79
  />
75
80
  ) );
76
81
 
@@ -101,6 +106,16 @@ Default.args = {
101
106
  ],
102
107
  };
103
108
 
109
+ export const WithTooltip = _default.bind( {} );
110
+ WithTooltip.args = {
111
+ ...Default.args,
112
+ options: [
113
+ { value: 1, label: '1', showTooltip: true, 'aria-label': 'One' },
114
+ { value: 2, label: '2', showTooltip: true, 'aria-label': 'Two' },
115
+ { value: 3, label: '3', showTooltip: true, 'aria-label': 'Three' },
116
+ ],
117
+ };
118
+
104
119
  export const WithAriaLabel = _default.bind( {} );
105
120
  WithAriaLabel.args = {
106
121
  ...Default.args,
@@ -15,16 +15,35 @@ describe( 'ToggleGroupControl', () => {
15
15
  <ToggleGroupControlOption value="jack" label="J" />
16
16
  </>
17
17
  );
18
+ const optionsWithTooltip = (
19
+ <>
20
+ <ToggleGroupControlOption
21
+ value="gnocchi"
22
+ label="Delicious Gnocchi"
23
+ aria-label="Click for Delicious Gnocchi"
24
+ showTooltip={ true }
25
+ />
26
+ <ToggleGroupControlOption
27
+ value="caponata"
28
+ label="Sumptuous Caponata"
29
+ aria-label="Click for Sumptuous Caponata"
30
+ />
31
+ </>
32
+ );
33
+
18
34
  it( 'should render correctly', () => {
19
35
  const { container } = render(
20
36
  <ToggleGroupControl label="Test Toggle Group Control">
21
37
  { options }
22
38
  </ToggleGroupControl>
23
39
  );
40
+
24
41
  expect( container.firstChild ).toMatchSnapshot();
25
42
  } );
43
+
26
44
  it( 'should call onChange with proper value', () => {
27
45
  const mockOnChange = jest.fn();
46
+
28
47
  render(
29
48
  <ToggleGroupControl
30
49
  value="jack"
@@ -34,8 +53,46 @@ describe( 'ToggleGroupControl', () => {
34
53
  { options }
35
54
  </ToggleGroupControl>
36
55
  );
56
+
37
57
  const firstRadio = screen.getByRole( 'radio', { name: 'R' } );
58
+
38
59
  fireEvent.click( firstRadio );
60
+
39
61
  expect( mockOnChange ).toHaveBeenCalledWith( 'rigas' );
40
62
  } );
63
+ it( 'should render tooltip where `showTooltip` === `true`', () => {
64
+ render(
65
+ <ToggleGroupControl label="Test Toggle Group Control">
66
+ { optionsWithTooltip }
67
+ </ToggleGroupControl>
68
+ );
69
+
70
+ const firstRadio = screen.getByLabelText(
71
+ 'Click for Delicious Gnocchi'
72
+ );
73
+
74
+ fireEvent.focus( firstRadio );
75
+
76
+ expect(
77
+ screen.getByText( 'Click for Delicious Gnocchi' )
78
+ ).toBeInTheDocument();
79
+ } );
80
+
81
+ it( 'should not render tooltip', () => {
82
+ render(
83
+ <ToggleGroupControl label="Test Toggle Group Control">
84
+ { optionsWithTooltip }
85
+ </ToggleGroupControl>
86
+ );
87
+
88
+ const secondRadio = screen.getByLabelText(
89
+ 'Click for Sumptuous Caponata'
90
+ );
91
+
92
+ fireEvent.focus( secondRadio );
93
+
94
+ expect(
95
+ screen.queryByText( 'Click for Sumptuous Caponata' )
96
+ ).not.toBeInTheDocument();
97
+ } );
41
98
  } );
@@ -18,7 +18,7 @@ import {
18
18
  function Example() {
19
19
  return (
20
20
  <ToggleGroupControl label="my label" value="vertical" isBlock>
21
- <ToggleGroupControlOption value="horizontal" label="Horizontal" />
21
+ <ToggleGroupControlOption value="horizontal" label="Horizontal" showTooltip={ true } />
22
22
  <ToggleGroupControlOption value="vertical" label="Vertical" />
23
23
  </ToggleGroupControl>
24
24
  );
@@ -38,3 +38,10 @@ Label for the option. If needed, the `aria-label` prop can be used in addition t
38
38
  The value of the `ToggleGroupControlOption`.
39
39
 
40
40
  - Required: Yes
41
+
42
+ ### `showTooltip`: `boolean`
43
+
44
+ Whether to show a tooltip when hovering over the option. The tooltip will attempt to use the `aria-label` prop text first, then the `label` prop text if no `aria-label` prop is found.
45
+
46
+ - Required: No
47
+