@lumx/react 3.1.5 → 3.2.1-alpha.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 (147) hide show
  1. package/_internal/types.d.ts +16 -5
  2. package/index.d.ts +45 -4
  3. package/index.js +632 -423
  4. package/index.js.map +1 -1
  5. package/package.json +3 -3
  6. package/src/components/alert-dialog/AlertDialog.stories.tsx +96 -165
  7. package/src/components/alert-dialog/AlertDialog.test.tsx +15 -23
  8. package/src/components/avatar/Avatar.stories.tsx +91 -62
  9. package/src/components/avatar/Avatar.test.tsx +9 -24
  10. package/src/components/badge/Badge.stories.tsx +63 -38
  11. package/src/components/button/Button.stories.tsx +147 -139
  12. package/src/components/button/IconButton.stories.tsx +45 -0
  13. package/src/components/checkbox/Checkbox.stories.tsx +37 -30
  14. package/src/components/chip/Chip.stories.tsx +77 -15
  15. package/src/components/comment-block/CommentBlock.stories.tsx +90 -25
  16. package/src/components/comment-block/CommentBlock.test.tsx +12 -17
  17. package/src/components/date-picker/DatePickerField.stories.tsx +52 -83
  18. package/src/components/dialog/Dialog.stories.tsx +131 -293
  19. package/src/components/dialog/Dialog.test.tsx +0 -32
  20. package/src/components/dropdown/Dropdown.stories.tsx +1 -186
  21. package/src/components/flag/Flag.stories.tsx +33 -18
  22. package/src/components/flag/Flag.test.tsx +1 -8
  23. package/src/components/flex-box/FlexBox.stories.tsx +151 -238
  24. package/src/components/flex-box/FlexBox.test.tsx +9 -49
  25. package/src/components/generic-block/GenericBlock.stories.jsx +1 -1
  26. package/src/components/grid-column/GridColumn.stories.tsx +46 -0
  27. package/src/components/heading/Heading.stories.tsx +57 -95
  28. package/src/components/icon/Icon.stories.tsx +67 -70
  29. package/src/components/image-block/ImageBlock.stories.tsx +103 -47
  30. package/src/components/image-block/ImageBlock.test.tsx +12 -17
  31. package/src/components/inline-list/InlineList.stories.tsx +45 -29
  32. package/src/components/input-helper/InputHelper.stories.tsx +31 -25
  33. package/src/components/input-label/InputLabel.stories.tsx +33 -10
  34. package/src/components/lightbox/Lightbox.stories.tsx +39 -77
  35. package/src/components/lightbox/Lightbox.test.tsx +12 -17
  36. package/src/components/link/Link.stories.tsx +98 -128
  37. package/src/components/link-preview/LinkPreview.stories.tsx +48 -75
  38. package/src/components/list/List.stories.tsx +59 -84
  39. package/src/components/list/List.test.tsx +8 -17
  40. package/src/components/list/ListDivider.stories.tsx +9 -4
  41. package/src/components/list/ListDivider.test.tsx +12 -17
  42. package/src/components/list/ListItem.stories.tsx +97 -59
  43. package/src/components/list/ListItem.test.tsx +12 -17
  44. package/src/components/list/ListSubheader.stories.tsx +8 -5
  45. package/src/components/list/ListSubheader.test.tsx +12 -18
  46. package/src/components/message/Message.stories.tsx +51 -22
  47. package/src/components/mosaic/Mosaic.stories.tsx +78 -74
  48. package/src/components/mosaic/Mosaic.test.tsx +0 -31
  49. package/src/components/navigation/Navigation.stories.tsx +67 -0
  50. package/src/components/navigation/Navigation.test.tsx +58 -0
  51. package/src/components/navigation/Navigation.tsx +62 -0
  52. package/src/components/navigation/NavigationItem.test.tsx +37 -0
  53. package/src/components/navigation/NavigationItem.tsx +89 -0
  54. package/src/components/navigation/NavigationSection.test.tsx +126 -0
  55. package/src/components/navigation/NavigationSection.tsx +109 -0
  56. package/src/components/navigation/context.tsx +6 -0
  57. package/src/components/navigation/index.ts +1 -0
  58. package/src/components/notification/Notifications.stories.tsx +52 -47
  59. package/src/components/popover/Popover.stories.tsx +68 -201
  60. package/src/components/popover/Popover.tsx +7 -9
  61. package/src/components/popover-dialog/PopoverDialog.stories.tsx +26 -65
  62. package/src/components/post-block/PostBlock.test.tsx +12 -17
  63. package/src/components/progress/ProgressCircular.stories.tsx +24 -12
  64. package/src/components/progress/ProgressLinear.stories.tsx +6 -2
  65. package/src/components/radio-button/RadioButton.stories.tsx +35 -24
  66. package/src/components/select/Select.stories.tsx +19 -23
  67. package/src/components/select/SelectMultiple.stories.tsx +105 -2
  68. package/src/components/select/WithSelectContext.tsx +10 -4
  69. package/src/components/skeleton/SkeletonCircle.stories.tsx +37 -21
  70. package/src/components/skeleton/SkeletonCircle.test.tsx +12 -17
  71. package/src/components/skeleton/SkeletonRectangle.stories.tsx +74 -99
  72. package/src/components/skeleton/SkeletonRectangle.test.tsx +12 -17
  73. package/src/components/skeleton/SkeletonTypography.test.tsx +12 -17
  74. package/src/components/slider/Slider.stories.tsx +41 -25
  75. package/src/components/slider/Slider.test.tsx +12 -18
  76. package/src/components/slideshow/Slideshow.stories.tsx +31 -61
  77. package/src/components/slideshow/Slideshow.test.tsx +15 -23
  78. package/src/components/slideshow/SlideshowControls.stories.tsx +4 -6
  79. package/src/components/switch/Switch.stories.tsx +35 -32
  80. package/src/components/table/Table.test.tsx +12 -17
  81. package/src/components/tabs/Tabs.stories.tsx +4 -3
  82. package/src/components/text/Text.stories.tsx +130 -0
  83. package/src/components/text-field/TextField.stories.tsx +114 -148
  84. package/src/components/thumbnail/Thumbnail.stories.tsx +106 -255
  85. package/src/components/thumbnail/Thumbnail.test.tsx +12 -35
  86. package/src/components/tooltip/Tooltip.stories.tsx +51 -136
  87. package/src/components/user-block/UserBlock.stories.tsx +67 -56
  88. package/src/components/user-block/UserBlock.test.tsx +1 -5
  89. package/src/hooks/useFocusTrap.ts +2 -2
  90. package/src/index.ts +1 -0
  91. package/src/stories/controls/color.ts +6 -0
  92. package/src/stories/controls/element.ts +6 -0
  93. package/src/stories/controls/focusPoint.ts +1 -0
  94. package/src/stories/controls/icons.ts +6 -0
  95. package/src/stories/{knobs → controls}/image.ts +6 -16
  96. package/src/stories/controls/selectArgType.ts +4 -0
  97. package/src/stories/controls/theme.ts +3 -0
  98. package/src/stories/controls/typography.ts +5 -0
  99. package/src/stories/controls/withUndefined.ts +1 -0
  100. package/src/stories/decorators/withChromaticForceScreenSize.tsx +8 -0
  101. package/src/stories/decorators/withCombinations.tsx +99 -0
  102. package/src/stories/decorators/withNestedProps.tsx +23 -0
  103. package/src/stories/{withResizableBox.tsx → decorators/withResizableBox.tsx} +6 -10
  104. package/src/stories/decorators/withValueOnChange.tsx +18 -0
  105. package/src/stories/decorators/withWrapper.tsx +19 -0
  106. package/src/stories/utils/CustomLink.tsx +8 -2
  107. package/src/stories/{knobs → utils}/lorem.ts +9 -9
  108. package/src/testing/utils/commonTestsSuiteRTL.ts +2 -3
  109. package/src/testing/utils/index.ts +0 -2
  110. package/src/untypped-modules.d.ts +0 -2
  111. package/src/utils/MaterialThemeSwitcher/MaterialThemeSwitcher.tsx +1 -1
  112. package/src/utils/ThemeContext.ts +4 -0
  113. package/src/utils/forwardRefPolymorphic.ts +9 -0
  114. package/src/utils/type.ts +28 -4
  115. package/src/components/alert-dialog/__snapshots__/AlertDialog.test.tsx.snap +0 -558
  116. package/src/components/avatar/__snapshots__/Avatar.test.tsx.snap +0 -681
  117. package/src/components/comment-block/__snapshots__/CommentBlock.test.tsx.snap +0 -92
  118. package/src/components/dialog/__snapshots__/Dialog.test.tsx.snap +0 -1133
  119. package/src/components/expansion-panel/ExpansionPanel.stories.tsx +0 -65
  120. package/src/components/flag/__snapshots__/Flag.test.tsx.snap +0 -133
  121. package/src/components/flex-box/__snapshots__/FlexBox.test.tsx.snap +0 -492
  122. package/src/components/grid-column/GridColumn.stories.jsx +0 -56
  123. package/src/components/image-block/__snapshots__/ImageBlock.test.tsx.snap +0 -64
  124. package/src/components/lightbox/__snapshots__/Lightbox.test.tsx.snap +0 -194
  125. package/src/components/list/__snapshots__/List.test.tsx.snap +0 -360
  126. package/src/components/list/__snapshots__/ListDivider.test.tsx.snap +0 -7
  127. package/src/components/list/__snapshots__/ListItem.test.tsx.snap +0 -160
  128. package/src/components/list/__snapshots__/ListSubheader.test.tsx.snap +0 -9
  129. package/src/components/mosaic/__snapshots__/Mosaic.test.tsx.snap +0 -357
  130. package/src/components/post-block/__snapshots__/PostBlock.test.tsx.snap +0 -139
  131. package/src/components/skeleton/__snapshots__/SkeletonCircle.test.tsx.snap +0 -54
  132. package/src/components/skeleton/__snapshots__/SkeletonRectangle.test.tsx.snap +0 -177
  133. package/src/components/skeleton/__snapshots__/SkeletonTypography.test.tsx.snap +0 -174
  134. package/src/components/slider/__snapshots__/Slider.test.tsx.snap +0 -122
  135. package/src/components/slideshow/__snapshots__/Slideshow.test.tsx.snap +0 -157
  136. package/src/components/table/__snapshots__/Table.test.tsx.snap +0 -263
  137. package/src/components/text/Text.stories.jsx +0 -75
  138. package/src/components/thumbnail/__snapshots__/Thumbnail.test.tsx.snap +0 -130
  139. package/src/components/user-block/__snapshots__/UserBlock.test.tsx.snap +0 -362
  140. package/src/stories/chromaticForceScreenSize.tsx +0 -7
  141. package/src/stories/knobs/buttonKnob.ts +0 -9
  142. package/src/stories/knobs/emphasisKnob.ts +0 -8
  143. package/src/stories/knobs/enumKnob.ts +0 -14
  144. package/src/stories/knobs/focusKnob.ts +0 -3
  145. package/src/stories/knobs/sizeKnob.ts +0 -5
  146. package/src/stories/knobs/thumbnailsKnob.ts +0 -9
  147. package/src/testing/utils/itShouldRenderStories.tsx +0 -103
@@ -1,28 +1,23 @@
1
1
  import React from 'react';
2
- import { mount, shallow } from 'enzyme';
3
- import 'jest-enzyme';
4
- import { commonTestsSuite, itShouldRenderStories } from '@lumx/react/testing/utils';
5
2
 
3
+ import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
4
+ import { render } from '@testing-library/react';
5
+ import { queryByClassName } from '@lumx/react/testing/utils/queries';
6
6
  import { PostBlock, PostBlockProps } from './PostBlock';
7
- import * as stories from '../../stories/generated/PostBlock/Demos.stories';
8
7
 
9
8
  const CLASSNAME = PostBlock.className as string;
10
9
 
11
- /**
12
- * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
13
- */
14
- const setup = (props: Partial<PostBlockProps> = {}, shallowRendering = true) => {
15
- const renderer: any = shallowRendering ? shallow : mount;
16
- const wrapper: any = renderer(<PostBlock {...(props as any)} />);
17
- return { props, wrapper };
10
+ const setup = (props: Partial<PostBlockProps> = {}) => {
11
+ render(<PostBlock {...(props as any)} />);
12
+ const postBlock = queryByClassName(document.body, CLASSNAME);
13
+ return { props, postBlock };
18
14
  };
19
15
 
20
16
  describe(`<${PostBlock.displayName}>`, () => {
21
- // 1. Test render via snapshot.
22
- describe('Snapshots and structure', () => {
23
- itShouldRenderStories(stories, PostBlock);
24
- });
25
-
26
17
  // Common tests suite.
27
- commonTestsSuite(setup, { className: 'wrapper', prop: 'wrapper' }, { className: CLASSNAME });
18
+ commonTestsSuiteRTL(setup, {
19
+ baseClassName: CLASSNAME,
20
+ forwardClassName: 'postBlock',
21
+ forwardAttributes: 'postBlock',
22
+ });
28
23
  });
@@ -1,18 +1,30 @@
1
- import { ProgressCircular } from '@lumx/react';
2
- import React, { Fragment } from 'react';
1
+ import { ProgressCircular, ProgressCircularSize, Size } from '@lumx/react';
2
+ import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
3
+ import { withCombinations } from '@lumx/react/stories/decorators/withCombinations';
4
+
5
+ const sizes: Array<ProgressCircularSize> = [Size.xxs, Size.xs, Size.s, Size.m];
3
6
 
4
7
  export default {
5
8
  title: 'LumX components/progress/ProgressCircular',
9
+ component: ProgressCircular,
10
+ args: ProgressCircular.defaultProps,
11
+ argTypes: {
12
+ size: getSelectArgType<ProgressCircularSize>(sizes),
13
+ },
6
14
  };
7
15
 
8
- const SIZES = ['xxs', 'xs', 's', 'm', undefined] as const;
9
-
10
- export const Default = ({ theme }: any) => <ProgressCircular theme={theme} />;
16
+ /**
17
+ * Default progress circular
18
+ */
19
+ export const Default = {};
11
20
 
12
- export const Sizes = ({ theme }: any) =>
13
- SIZES.map((size) => (
14
- <Fragment key={String(size)}>
15
- <span>{String(size)}</span>
16
- <ProgressCircular theme={theme} size={size} />
17
- </Fragment>
18
- ));
21
+ /**
22
+ * All sizes
23
+ */
24
+ export const AllSizes = {
25
+ decorators: [
26
+ withCombinations({
27
+ combinations: { cols: { key: 'size', options: sizes } },
28
+ }),
29
+ ],
30
+ };
@@ -1,8 +1,12 @@
1
1
  import { ProgressLinear } from '@lumx/react';
2
- import React from 'react';
3
2
 
4
3
  export default {
5
4
  title: 'LumX components/progress/ProgressLinear',
5
+ component: ProgressLinear,
6
+ args: ProgressLinear.defaultProps,
6
7
  };
7
8
 
8
- export const Default = ({ theme }: any) => <ProgressLinear theme={theme} />;
9
+ /**
10
+ * Default progress linear
11
+ */
12
+ export const Default = {};
@@ -1,28 +1,39 @@
1
1
  import { RadioButton } from '@lumx/react';
2
- import { text } from '@storybook/addon-knobs';
3
- import noop from 'lodash/noop';
4
- import React from 'react';
2
+ import { withValueOnChange } from '@lumx/react/stories/decorators/withValueOnChange';
3
+ import { loremIpsum } from '@lumx/react/stories/utils/lorem';
5
4
 
6
- export default { title: 'LumX components/radio-button/Radio button' };
5
+ export default {
6
+ title: 'LumX components/radio-button/Radio button',
7
+ component: RadioButton,
8
+ args: {
9
+ ...RadioButton.defaultProps,
10
+ name: 'radiobutton-html-name',
11
+ value: 'radiobutton-html-value',
12
+ },
13
+ argTypes: {
14
+ onChange: { action: true },
15
+ name: { control: false },
16
+ value: { control: false },
17
+ },
18
+ decorators: [
19
+ withValueOnChange({
20
+ valueProp: 'isChecked',
21
+ valueTransform: (value) => value === 'radiobutton-html-value',
22
+ }),
23
+ ],
24
+ };
7
25
 
8
- export const SimpleRadioButton = ({ theme }: any) => (
9
- <RadioButton
10
- isChecked={false}
11
- label={text('Label', 'Radio button')}
12
- name="test1"
13
- theme={theme}
14
- value="lorem"
15
- onChange={noop}
16
- />
17
- );
26
+ /**
27
+ * Default radio button
28
+ */
29
+ export const Default = {};
18
30
 
19
- export const SimpleCheckedRadioButton = ({ theme }: any) => (
20
- <RadioButton
21
- isChecked
22
- label={text('Label', 'Radio button')}
23
- name="test1"
24
- theme={theme}
25
- value="lorem"
26
- onChange={noop}
27
- />
28
- );
31
+ /**
32
+ * With label and helper
33
+ */
34
+ export const LabelAndHelper = {
35
+ args: {
36
+ label: 'Radio button label',
37
+ helper: loremIpsum('tiny'),
38
+ },
39
+ };
@@ -1,13 +1,15 @@
1
1
  import { mdiBullhornOutline } from '@lumx/icons/';
2
2
  import { List, ListItem, Select, Size, TextField } from '@lumx/react';
3
3
  import { useBooleanState } from '@lumx/react/hooks/useBooleanState';
4
- import { text } from '@storybook/addon-knobs';
5
4
  import noop from 'lodash/noop';
6
5
  import range from 'lodash/range';
7
6
  import React, { SyntheticEvent, useState } from 'react';
8
7
  import { SelectVariant } from './constants';
9
8
 
10
- export default { title: 'LumX components/select/Select' };
9
+ export default {
10
+ title: 'LumX components/select/Select',
11
+ component: Select,
12
+ };
11
13
 
12
14
  const CHOICES = ['First item', 'Second item', 'Third item'];
13
15
 
@@ -112,8 +114,8 @@ export const DisabledSelect = ({ theme }: any) => {
112
114
  <Select
113
115
  isOpen={false}
114
116
  value=""
115
- label={text('label', 'My select')}
116
- placeholder={text('placeholder', 'Placeholder')}
117
+ label="My select"
118
+ placeholder="Placeholder"
117
119
  theme={theme}
118
120
  onInputClick={noop}
119
121
  onDropdownClose={noop}
@@ -204,13 +206,7 @@ export const SelectWithAnotherField = ({ theme }: any) => {
204
206
 
205
207
  return (
206
208
  <>
207
- <TextField
208
- value={text('Value', 'myvalue')}
209
- label={text('Label', 'I am the label')}
210
- placeholder={text('Placeholder', 'ex: A value')}
211
- theme={theme}
212
- onChange={noop}
213
- />
209
+ <TextField value="myvalue" label="I am the label" placeholder="ex: A value" theme={theme} onChange={noop} />
214
210
  <Select
215
211
  style={{ width: '100%' }}
216
212
  isOpen={isOpen}
@@ -255,8 +251,8 @@ export const SelectWithNoData = ({ theme }: any) => {
255
251
  <Select
256
252
  isOpen={isOpen}
257
253
  value=""
258
- label={text('label', 'My select')}
259
- placeholder={text('placeholder', 'Placeholder')}
254
+ label="My select"
255
+ placeholder="Placeholder"
260
256
  theme={theme}
261
257
  onInputClick={toggleSelect}
262
258
  onDropdownClose={closeSelect}
@@ -277,10 +273,10 @@ export const SelectWithHelper = ({ theme }: any) => {
277
273
  <Select
278
274
  isOpen={isOpen}
279
275
  value=""
280
- label={text('label', 'Country')}
281
- placeholder={text('placeholder', 'Your country')}
276
+ label="Country"
277
+ placeholder="Your country"
282
278
  theme={theme}
283
- helper={text('helper', 'This is used in analytics')}
279
+ helper="This is used in analytics"
284
280
  onInputClick={toggleSelect}
285
281
  onDropdownClose={closeSelect}
286
282
  >
@@ -302,14 +298,14 @@ export const SelectWithError = ({ theme }: any) => {
302
298
  <Select
303
299
  isOpen={isOpen}
304
300
  value=""
305
- label={text('label', 'Country')}
306
- placeholder={text('placeholder', 'Your country')}
301
+ label="Country"
302
+ placeholder="Your country"
307
303
  theme={theme}
308
- helper={text('helper', 'This is used in analytics')}
304
+ helper="This is used in analytics"
309
305
  onInputClick={toggleSelect}
310
306
  onDropdownClose={closeSelect}
311
307
  hasError
312
- error={text('Error', 'Please select something :)')}
308
+ error="Please select something :)"
313
309
  >
314
310
  <List theme={theme} isClickable>
315
311
  {CHOICES.map((choice) => (
@@ -329,10 +325,10 @@ export const SelectSuccess = ({ theme }: any) => {
329
325
  <Select
330
326
  isOpen={isOpen}
331
327
  value=""
332
- label={text('label', 'Country')}
333
- placeholder={text('placeholder', 'Your country')}
328
+ label="Country"
329
+ placeholder="Your country"
334
330
  theme={theme}
335
- helper={text('helper', 'This is used in analytics')}
331
+ helper="This is used in analytics"
336
332
  onInputClick={toggleSelect}
337
333
  onDropdownClose={closeSelect}
338
334
  isValid
@@ -1,9 +1,20 @@
1
1
  /* istanbul ignore file */
2
2
  import { mdiTram } from '@lumx/icons/';
3
- import { Chip, List, ListItem, SelectMultiple, Size } from '@lumx/react';
3
+ import {
4
+ Chip,
5
+ Dialog,
6
+ List,
7
+ ListDivider,
8
+ ListItem,
9
+ ListSubheader,
10
+ SelectMultiple,
11
+ Size,
12
+ TextField,
13
+ Toolbar,
14
+ } from '@lumx/react';
4
15
  import { useBooleanState } from '@lumx/react/hooks/useBooleanState';
5
16
  import noop from 'lodash/noop';
6
- import React, { MouseEventHandler, SyntheticEvent, useState } from 'react';
17
+ import React, { MouseEventHandler, SyntheticEvent, useRef, useState } from 'react';
7
18
  import { SelectVariant } from './constants';
8
19
 
9
20
  export default { title: 'LumX components/select/Select Multiple' };
@@ -225,3 +236,95 @@ export const ChipsCustomSelectMultiple = ({ theme }: any) => {
225
236
  </SelectMultiple>
226
237
  );
227
238
  };
239
+
240
+ /**
241
+ * Test select focus trap (focus is contained inside the dialog then inside the select dropdown)
242
+ */
243
+ export const SelectWithinADialog = ({ theme }: any) => {
244
+ const searchFieldRef = useRef(null);
245
+
246
+ const [searchText, setSearchText] = useState<string>();
247
+ const [values, setValues] = useState<string[]>([]);
248
+ const [isOpen, closeSelect, , toggleSelect] = useBooleanState(false);
249
+
250
+ const clearSelected = (event: SyntheticEvent, value: string) => {
251
+ event.stopPropagation();
252
+ setValues(value ? values.filter((val) => val !== value) : []);
253
+ };
254
+
255
+ const selectItem = (item: string) => () => {
256
+ if (values.includes(item)) {
257
+ return;
258
+ }
259
+
260
+ closeSelect();
261
+ setValues([...values, item]);
262
+ };
263
+
264
+ const filteredChoices =
265
+ searchText && searchText.length > 0 ? CHOICES.filter((choice) => choice.includes(searchText)) : CHOICES;
266
+
267
+ return (
268
+ <>
269
+ <Dialog isOpen>
270
+ <header>
271
+ <Toolbar label={<span className="lumx-typography-title">Dialog header</span>} />
272
+ </header>
273
+ <div className="lumx-spacing-padding-horizontal-huge lumx-spacing-padding-bottom-huge">
274
+ {/* Testing hidden input do not count in th focus trap*/}
275
+ <input hidden type="file" />
276
+ <input type="hidden" />
277
+
278
+ <div className="lumx-spacing-margin-bottom-huge">The select should capture the focus on open.</div>
279
+
280
+ <SelectMultiple
281
+ isOpen={isOpen}
282
+ value={values}
283
+ onClear={clearSelected}
284
+ clearButtonProps={{ label: 'Clear' }}
285
+ label={LABEL}
286
+ placeholder={PLACEHOLDER}
287
+ theme={theme}
288
+ onInputClick={toggleSelect}
289
+ onDropdownClose={closeSelect}
290
+ icon={mdiTram}
291
+ focusElement={searchFieldRef}
292
+ >
293
+ <List isClickable>
294
+ <>
295
+ <ListSubheader>
296
+ <TextField
297
+ clearButtonProps={{ label: 'Clear' }}
298
+ placeholder="Search"
299
+ role="searchbox"
300
+ inputRef={searchFieldRef}
301
+ onChange={setSearchText}
302
+ value={searchText}
303
+ />
304
+ </ListSubheader>
305
+ <ListDivider role="presentation" />
306
+ </>
307
+
308
+ {filteredChoices.length > 0
309
+ ? filteredChoices.map((choice) => (
310
+ <ListItem
311
+ isSelected={values.includes(choice)}
312
+ key={choice}
313
+ onItemSelected={selectItem(choice)}
314
+ size={Size.tiny}
315
+ >
316
+ {choice}
317
+ </ListItem>
318
+ ))
319
+ : [
320
+ <ListItem key={0} size={Size.tiny}>
321
+ No data
322
+ </ListItem>,
323
+ ]}
324
+ </List>
325
+ </SelectMultiple>
326
+ </div>
327
+ </Dialog>
328
+ </>
329
+ );
330
+ };
@@ -1,15 +1,15 @@
1
- import React, { Ref, useCallback, useMemo, useRef } from 'react';
2
-
3
1
  import classNames from 'classnames';
2
+ import React, { Ref, useCallback, useMemo, useRef } from 'react';
4
3
  import { uid } from 'uid';
5
4
 
5
+ import { Placement } from '@lumx/react';
6
6
  import { Kind, Theme } from '@lumx/react/components';
7
7
  import { Dropdown } from '@lumx/react/components/dropdown/Dropdown';
8
8
  import { InputHelper } from '@lumx/react/components/input-helper/InputHelper';
9
+ import { useFocusTrap } from '@lumx/react/hooks/useFocusTrap';
10
+ import { useListenFocus } from '@lumx/react/hooks/useListenFocus';
9
11
  import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
10
12
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
11
- import { useListenFocus } from '@lumx/react/hooks/useListenFocus';
12
- import { Placement } from '@lumx/react';
13
13
 
14
14
  import { CoreSelectProps, SelectVariant } from './constants';
15
15
 
@@ -30,6 +30,7 @@ export const WithSelectContext = (
30
30
  {
31
31
  children,
32
32
  className,
33
+ focusElement,
33
34
  isMultiple,
34
35
  closeOnClick = !isMultiple,
35
36
  disabled,
@@ -58,6 +59,7 @@ export const WithSelectContext = (
58
59
  const selectId = useMemo(() => id || `select-${uid()}`, [id]);
59
60
  const anchorRef = useRef<HTMLElement>(null);
60
61
  const selectRef = useRef<HTMLDivElement>(null);
62
+ const dropdownRef = useRef<HTMLDivElement>(null);
61
63
  const isFocus = useListenFocus(anchorRef);
62
64
 
63
65
  const handleKeyboardNav = useCallback(
@@ -77,6 +79,9 @@ export const WithSelectContext = (
77
79
  anchorRef?.current?.blur();
78
80
  };
79
81
 
82
+ // Handle focus trap.
83
+ useFocusTrap(isOpen && dropdownRef.current, focusElement?.current);
84
+
80
85
  return (
81
86
  <div
82
87
  ref={mergeRefs(ref, selectRef)}
@@ -125,6 +130,7 @@ export const WithSelectContext = (
125
130
  placement={Placement.BOTTOM_START}
126
131
  onClose={onClose}
127
132
  onInfiniteScroll={onInfiniteScroll}
133
+ ref={dropdownRef}
128
134
  >
129
135
  {children}
130
136
  </Dropdown>
@@ -1,25 +1,41 @@
1
- import React from 'react';
1
+ import { Size, SkeletonCircle, SkeletonCircleProps } from '@lumx/react';
2
+ import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
3
+ import { ALL_COLORS, colorArgType } from '@lumx/react/stories/controls/color';
4
+ import { withCombinations } from '@lumx/react/stories/decorators/withCombinations';
2
5
 
3
- import { FlexBox, Orientation, Size, SkeletonCircle, ColorPalette } from '@lumx/react';
6
+ const sizes: SkeletonCircleProps['size'][] = [Size.xxs, Size.xs, Size.s, Size.m, Size.l, Size.xl, Size.xxl];
4
7
 
5
- export default { title: 'LumX components/skeleton/Skeleton Circle' };
8
+ export default {
9
+ title: 'LumX components/skeleton/Skeleton Circle',
10
+ component: SkeletonCircle,
11
+ args: SkeletonCircle.defaultProps,
12
+ argTypes: {
13
+ size: getSelectArgType(sizes),
14
+ color: colorArgType,
15
+ },
16
+ };
6
17
 
7
- const sizes = [Size.xxs, Size.xs, Size.s, Size.m, Size.l, Size.xl, Size.xxl] as const;
8
- const colors = Object.values(ColorPalette);
18
+ /**
19
+ * All sizes
20
+ */
21
+ export const AllSize = {
22
+ argTypes: { size: { control: false } },
23
+ decorators: [
24
+ withCombinations({
25
+ combinations: { cols: { key: 'size', options: sizes } },
26
+ }),
27
+ ],
28
+ };
9
29
 
10
- export const Circle = ({ theme }: any) => (
11
- <>
12
- Sizes:
13
- <FlexBox orientation={Orientation.horizontal}>
14
- {sizes.map((size) => (
15
- <SkeletonCircle theme={theme} key={size} size={size} className="lumx-spacing-margin" />
16
- ))}
17
- </FlexBox>
18
- Colors:
19
- <FlexBox orientation={Orientation.horizontal}>
20
- {colors.map((color) => (
21
- <SkeletonCircle theme={theme} size={Size.m} key={color} color={color} className="lumx-spacing-margin" />
22
- ))}
23
- </FlexBox>
24
- </>
25
- );
30
+ /**
31
+ * All colors
32
+ */
33
+ export const AllColor = {
34
+ args: { size: Size.m },
35
+ argTypes: { color: { control: false } },
36
+ decorators: [
37
+ withCombinations({
38
+ combinations: { cols: { key: 'color', options: ALL_COLORS } },
39
+ }),
40
+ ],
41
+ };
@@ -1,28 +1,23 @@
1
1
  import React from 'react';
2
- import { mount, shallow } from 'enzyme';
3
- import 'jest-enzyme';
4
- import { commonTestsSuite, itShouldRenderStories } from '@lumx/react/testing/utils';
5
2
 
3
+ import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
4
+ import { render } from '@testing-library/react';
5
+ import { queryByClassName } from '@lumx/react/testing/utils/queries';
6
6
  import { SkeletonCircle, SkeletonCircleProps } from './SkeletonCircle';
7
- import * as stories from './SkeletonCircle.stories';
8
7
 
9
8
  const CLASSNAME = SkeletonCircle.className as string;
10
9
 
11
- /**
12
- * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
13
- */
14
- const setup = (props: Partial<SkeletonCircleProps> = {}, shallowRendering = true) => {
15
- const renderer: any = shallowRendering ? shallow : mount;
16
- const wrapper: any = renderer(<SkeletonCircle {...(props as any)} />);
17
- return { props, wrapper };
10
+ const setup = (props: Partial<SkeletonCircleProps> = {}) => {
11
+ render(<SkeletonCircle {...(props as any)} />);
12
+ const skeletonCircle = queryByClassName(document.body, CLASSNAME);
13
+ return { props, skeletonCircle };
18
14
  };
19
15
 
20
16
  describe(`<${SkeletonCircle.displayName}>`, () => {
21
- // 1. Test render via snapshot.
22
- describe('Snapshots and structure', () => {
23
- itShouldRenderStories(stories, SkeletonCircle);
24
- });
25
-
26
17
  // Common tests suite.
27
- commonTestsSuite(setup, { className: 'wrapper', prop: 'wrapper' }, { className: CLASSNAME });
18
+ commonTestsSuiteRTL(setup, {
19
+ baseClassName: CLASSNAME,
20
+ forwardClassName: 'skeletonCircle',
21
+ forwardAttributes: 'skeletonCircle',
22
+ });
28
23
  });