@lumx/react 3.10.1-alpha.7 → 3.10.1-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +86 -12
- package/index.js +318 -304
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/alert-dialog/AlertDialog.tsx +6 -3
- package/src/components/autocomplete/Autocomplete.stories.tsx +1 -2
- package/src/components/autocomplete/Autocomplete.tsx +3 -3
- package/src/components/autocomplete/AutocompleteMultiple.stories.tsx +2 -5
- package/src/components/autocomplete/AutocompleteMultiple.tsx +2 -2
- package/src/components/avatar/Avatar.tsx +3 -3
- package/src/components/badge/Badge.tsx +3 -3
- package/src/components/badge/BadgeWrapper.tsx +3 -2
- package/src/components/button/Button.tsx +9 -8
- package/src/components/button/ButtonGroup.tsx +9 -3
- package/src/components/button/ButtonRoot.tsx +6 -2
- package/src/components/button/IconButton.tsx +2 -2
- package/src/components/checkbox/Checkbox.tsx +4 -4
- package/src/components/chip/Chip.tsx +15 -9
- package/src/components/chip/ChipGroup.tsx +3 -2
- package/src/components/comment-block/CommentBlock.stories.tsx +4 -7
- package/src/components/comment-block/CommentBlock.tsx +3 -3
- package/src/components/date-picker/constants.ts +2 -2
- package/src/components/dialog/Dialog.tsx +9 -7
- package/src/components/divider/Divider.tsx +3 -3
- package/src/components/drag-handle/DragHandle.tsx +3 -3
- package/src/components/dropdown/Dropdown.tsx +4 -3
- package/src/components/expansion-panel/ExpansionPanel.tsx +26 -20
- package/src/components/flag/Flag.tsx +3 -3
- package/src/components/flex-box/FlexBox.tsx +4 -4
- package/src/components/generic-block/GenericBlock.tsx +10 -8
- package/src/components/generic-block/constants.ts +4 -9
- package/src/components/grid/Grid.tsx +5 -3
- package/src/components/grid/GridItem.tsx +5 -3
- package/src/components/grid-column/GridColumn.tsx +5 -3
- package/src/components/heading/Heading.tsx +7 -2
- package/src/components/icon/Icon.tsx +3 -3
- package/src/components/image-block/ImageBlock.tsx +3 -3
- package/src/components/image-lightbox/ImageLightbox.tsx +1 -1
- package/src/components/image-lightbox/constants.ts +2 -2
- package/src/components/image-lightbox/internal/ImageSlide.tsx +1 -1
- package/src/components/image-lightbox/internal/ImageSlideshow.tsx +9 -5
- package/src/components/image-lightbox/useImageLightbox.tsx +2 -1
- package/src/components/inline-list/InlineList.tsx +7 -3
- package/src/components/input-helper/InputHelper.tsx +3 -3
- package/src/components/input-label/InputLabel.tsx +3 -3
- package/src/components/lightbox/Lightbox.tsx +6 -4
- package/src/components/link/Link.tsx +11 -7
- package/src/components/link-preview/LinkPreview.tsx +3 -3
- package/src/components/list/List.tsx +4 -4
- package/src/components/list/ListDivider.tsx +3 -2
- package/src/components/list/ListItem.tsx +6 -5
- package/src/components/list/ListSubheader.tsx +3 -2
- package/src/components/list/useInteractiveList.tsx +7 -6
- package/src/components/message/Message.tsx +3 -3
- package/src/components/mosaic/Mosaic.test.tsx +3 -3
- package/src/components/mosaic/Mosaic.tsx +6 -5
- package/src/components/navigation/Navigation.stories.tsx +2 -2
- package/src/components/navigation/Navigation.tsx +3 -3
- package/src/components/navigation/NavigationItem.tsx +3 -9
- package/src/components/navigation/NavigationSection.tsx +3 -3
- package/src/components/notification/Notification.tsx +9 -5
- package/src/components/popover/Popover.stories.tsx +13 -15
- package/src/components/popover/Popover.test.tsx +6 -1
- package/src/components/popover/Popover.tsx +6 -6
- package/src/components/popover/usePopoverStyle.tsx +1 -3
- package/src/components/popover/useRestoreFocusOnClose.tsx +1 -1
- package/src/components/popover-dialog/PopoverDialog.tsx +3 -2
- package/src/components/post-block/PostBlock.tsx +11 -7
- package/src/components/progress/Progress.tsx +3 -3
- package/src/components/progress/ProgressCircular.tsx +3 -3
- package/src/components/progress/ProgressLinear.tsx +3 -3
- package/src/components/progress-tracker/ProgressTracker.stories.tsx +11 -11
- package/src/components/progress-tracker/ProgressTracker.tsx +4 -3
- package/src/components/progress-tracker/ProgressTrackerStep.tsx +3 -3
- package/src/components/progress-tracker/ProgressTrackerStepPanel.tsx +2 -0
- package/src/components/radio-button/RadioButton.tsx +3 -3
- package/src/components/radio-button/RadioGroup.stories.tsx +1 -4
- package/src/components/radio-button/RadioGroup.tsx +3 -2
- package/src/components/select/Select.stories.tsx +19 -38
- package/src/components/select/Select.tsx +5 -5
- package/src/components/select/SelectMultiple.stories.tsx +15 -30
- package/src/components/select/SelectMultiple.tsx +3 -4
- package/src/components/select/WithSelectContext.tsx +3 -4
- package/src/components/select/constants.ts +3 -1
- package/src/components/side-navigation/SideNavigation.stories.tsx +1 -1
- package/src/components/side-navigation/SideNavigation.tsx +4 -3
- package/src/components/side-navigation/SideNavigationItem.tsx +7 -7
- package/src/components/skeleton/SkeletonCircle.tsx +3 -3
- package/src/components/skeleton/SkeletonRectangle.tsx +3 -3
- package/src/components/skeleton/SkeletonTypography.stories.tsx +7 -12
- package/src/components/skeleton/SkeletonTypography.tsx +3 -3
- package/src/components/slider/Slider.tsx +4 -4
- package/src/components/slider/index.ts +1 -1
- package/src/components/slideshow/Slides.tsx +6 -4
- package/src/components/slideshow/Slideshow.stories.tsx +1 -3
- package/src/components/slideshow/Slideshow.tsx +3 -1
- package/src/components/slideshow/SlideshowControls.stories.tsx +1 -4
- package/src/components/slideshow/SlideshowControls.tsx +4 -4
- package/src/components/slideshow/SlideshowItem.tsx +5 -2
- package/src/components/slideshow/SlideshowItemGroup.tsx +5 -3
- package/src/components/switch/Switch.test.tsx +1 -1
- package/src/components/switch/Switch.tsx +7 -4
- package/src/components/table/Table.tsx +5 -3
- package/src/components/table/TableBody.tsx +7 -3
- package/src/components/table/TableCell.tsx +5 -3
- package/src/components/table/TableHeader.tsx +7 -3
- package/src/components/table/TableRow.tsx +5 -3
- package/src/components/tabs/TabList.tsx +1 -1
- package/src/components/tabs/TabPanel.tsx +2 -0
- package/src/components/tabs/Tabs.stories.tsx +12 -11
- package/src/components/text/Text.tsx +14 -5
- package/src/components/text-field/TextField.test.tsx +2 -2
- package/src/components/text-field/TextField.tsx +8 -7
- package/src/components/thumbnail/Thumbnail.tsx +4 -4
- package/src/components/toolbar/Toolbar.tsx +3 -3
- package/src/components/tooltip/Tooltip.tsx +4 -4
- package/src/components/tooltip/context.tsx +1 -1
- package/src/components/tooltip/useInjectTooltipRef.tsx +1 -1
- package/src/components/uploader/Uploader.tsx +3 -3
- package/src/components/user-block/UserBlock.tsx +12 -10
- package/src/hooks/useCallbackOnEscape.ts +1 -1
- package/src/hooks/useClickAway.tsx +2 -1
- package/src/hooks/useFocusTrap.ts +1 -1
- package/src/hooks/useInterval.tsx +4 -1
- package/src/hooks/useKeyboardListNavigation.tsx +4 -2
- package/src/hooks/useSizeOnWindowResize.ts +10 -14
- package/src/hooks/useStopPropagation.ts +2 -1
- package/src/stories/decorators/withCombinations.tsx +1 -1
- package/src/testing/utils/commonTestsSuiteRTL.tsx +2 -2
- package/src/utils/ClickAwayProvider/ClickAwayProvider.tsx +4 -0
- package/src/utils/className/getRootClassName.test.ts +11 -0
- package/src/utils/className/getRootClassName.ts +24 -0
- package/src/utils/className/index.ts +1 -0
- package/src/utils/date/getMonthCalendar.ts +4 -3
- package/src/utils/{makeListenerTowerContext.ts → function/makeListenerTowerContext.ts} +2 -2
- package/src/utils/{collection/partitionMulti.ts → partitionMulti.ts} +12 -13
- package/src/utils/{flattenChildren.ts → react/flattenChildren.ts} +3 -2
- package/src/utils/{renderButtonOrLink.tsx → react/renderButtonOrLink.tsx} +1 -1
- package/src/utils/{skipRender.tsx → react/skipRender.tsx} +1 -1
- package/src/utils/type/index.ts +18 -18
- package/src/utils/type/isComponent.ts +33 -0
- package/utils/index.d.ts +4 -0
- package/utils/index.js +96 -1
- package/utils/index.js.map +1 -1
- package/_internal/index.js +0 -99
- package/_internal/index.js.map +0 -1
- package/src/utils/className.test.js +0 -41
- package/src/utils/collection/castArray.test.ts +0 -15
- package/src/utils/collection/castArray.ts +0 -3
- package/src/utils/collection/chunk.test.ts +0 -15
- package/src/utils/collection/chunk.ts +0 -6
- package/src/utils/collection/isEmpty.test.js +0 -20
- package/src/utils/collection/isEmpty.ts +0 -4
- package/src/utils/collection/last.ts +0 -2
- package/src/utils/collection/partitionMulti.test.ts +0 -35
- package/src/utils/collection/pull.test.ts +0 -17
- package/src/utils/collection/pull.ts +0 -7
- package/src/utils/collection/range.test.js +0 -9
- package/src/utils/collection/range.ts +0 -2
- package/src/utils/function/memoize.test.ts +0 -36
- package/src/utils/function/memoize.ts +0 -13
- package/src/utils/type/ComponentClassName.ts +0 -7
- package/src/utils/type/KebabCase.ts +0 -6
- /package/src/utils/{clamp.ts → number/clamp.ts} +0 -0
- /package/src/utils/{OnBeforeUnmount.tsx → react/OnBeforeUnmount.tsx} +0 -0
- /package/src/utils/{mergeRefs.ts → react/mergeRefs.ts} +0 -0
- /package/src/utils/{renderLink.tsx → react/renderLink.tsx} +0 -0
|
@@ -6,6 +6,7 @@ import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
|
|
|
6
6
|
import { withNestedProps } from '@lumx/react/stories/decorators/withNestedProps';
|
|
7
7
|
import { toFlattenProps } from '@lumx/react/stories/utils/toFlattenProps';
|
|
8
8
|
import { withCategory } from '@lumx/react/stories/utils/withCategory';
|
|
9
|
+
import get from 'lodash/get';
|
|
9
10
|
import times from 'lodash/times';
|
|
10
11
|
import React, { useState } from 'react';
|
|
11
12
|
|
|
@@ -17,9 +18,9 @@ export default {
|
|
|
17
18
|
|
|
18
19
|
/** Default tab behavior with some controllable args */
|
|
19
20
|
export const Default = {
|
|
20
|
-
render: ({
|
|
21
|
+
render: ({ tabProviderProps, tabListProps, tabProps }: any) => (
|
|
21
22
|
<TabProvider {...tabProviderProps}>
|
|
22
|
-
<TabList
|
|
23
|
+
<TabList aria-label="Tab list" {...tabListProps}>
|
|
23
24
|
<Tab {...tabProps[0]} />
|
|
24
25
|
<Tab {...tabProps[1]} />
|
|
25
26
|
<Tab {...tabProps[2]} />
|
|
@@ -60,15 +61,15 @@ export const Default = {
|
|
|
60
61
|
|
|
61
62
|
/* Control active tab externally (with activate tab on focus). */
|
|
62
63
|
export const Controlled = {
|
|
63
|
-
render(
|
|
64
|
+
render() {
|
|
64
65
|
const [activeTab, setActiveTab] = useState(1);
|
|
65
|
-
const changeActiveTabIndex = (evt: any) => setActiveTab(parseInt(evt
|
|
66
|
+
const changeActiveTabIndex = (evt: any) => setActiveTab(parseInt(get(evt, 'target.value', '0'), 10));
|
|
66
67
|
|
|
67
68
|
const [isLazy, setIsLazy] = useState(true);
|
|
68
|
-
const changeIsLazy = (evt: any) => setIsLazy(evt
|
|
69
|
+
const changeIsLazy = (evt: any) => setIsLazy(get(evt, 'target.checked'));
|
|
69
70
|
|
|
70
71
|
const [shouldActivateOnFocus, setShouldActivateOnFocus] = useState(true);
|
|
71
|
-
const changeShouldActivateOnFocus = (evt: any) => setShouldActivateOnFocus(evt
|
|
72
|
+
const changeShouldActivateOnFocus = (evt: any) => setShouldActivateOnFocus(get(evt, 'target.checked'));
|
|
72
73
|
|
|
73
74
|
return (
|
|
74
75
|
<>
|
|
@@ -92,7 +93,7 @@ export const Controlled = {
|
|
|
92
93
|
isLazy={isLazy}
|
|
93
94
|
shouldActivateOnFocus={shouldActivateOnFocus}
|
|
94
95
|
>
|
|
95
|
-
<TabList
|
|
96
|
+
<TabList aria-label="Tab list">
|
|
96
97
|
<Tab label="Tab a" />
|
|
97
98
|
<Tab label="Tab b" />
|
|
98
99
|
<Tab label="Tab c" />
|
|
@@ -110,7 +111,7 @@ export const Controlled = {
|
|
|
110
111
|
|
|
111
112
|
/* Display tabs far from their tab panels. */
|
|
112
113
|
export const SplitTabListAndTabPanels = {
|
|
113
|
-
render(
|
|
114
|
+
render() {
|
|
114
115
|
const [isOpen, setOpen] = useState(true);
|
|
115
116
|
const [activeTabIndex, onChange] = useState(1);
|
|
116
117
|
|
|
@@ -130,7 +131,7 @@ export const SplitTabListAndTabPanels = {
|
|
|
130
131
|
<TabPanel className="lumx-spacing-padding-huge">Tab 3 content</TabPanel>
|
|
131
132
|
|
|
132
133
|
<footer>
|
|
133
|
-
<TabList
|
|
134
|
+
<TabList aria-label="Tab list">
|
|
134
135
|
<Tab label="Tab 1" />
|
|
135
136
|
<Tab label="Tab 2" />
|
|
136
137
|
<Tab label="Tab 3" />
|
|
@@ -145,10 +146,10 @@ export const SplitTabListAndTabPanels = {
|
|
|
145
146
|
|
|
146
147
|
/* Dynamically generate tabs. */
|
|
147
148
|
export const DynamicTabs = {
|
|
148
|
-
render({
|
|
149
|
+
render({ tabCount }: any) {
|
|
149
150
|
return (
|
|
150
151
|
<TabProvider>
|
|
151
|
-
<TabList
|
|
152
|
+
<TabList aria-label="Tab list">
|
|
152
153
|
{times(tabCount, (tabNumber) => (
|
|
153
154
|
<Tab key={tabNumber} label={`Tab ${tabNumber}`} />
|
|
154
155
|
))}
|
|
@@ -3,10 +3,15 @@ import React, { Children, Fragment } from 'react';
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
|
|
5
5
|
import { Icon, ColorPalette, ColorVariant, Typography, WhiteSpace } from '@lumx/react';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { GenericProps, TextElement, isComponent } from '@lumx/react/utils/type';
|
|
7
|
+
import {
|
|
8
|
+
getFontColorClassName,
|
|
9
|
+
getRootClassName,
|
|
10
|
+
handleBasicClasses,
|
|
11
|
+
getTypographyClassName,
|
|
12
|
+
} from '@lumx/react/utils/className';
|
|
8
13
|
import { useOverflowTooltipLabel } from '@lumx/react/hooks/useOverflowTooltipLabel';
|
|
9
|
-
import { useMergeRefs } from '@lumx/react/utils/mergeRefs';
|
|
14
|
+
import { useMergeRefs } from '@lumx/react/utils/react/mergeRefs';
|
|
10
15
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
11
16
|
|
|
12
17
|
/**
|
|
@@ -46,6 +51,10 @@ export interface TextProps extends GenericProps {
|
|
|
46
51
|
* Ignored when `truncate` is set to true or lines: 1
|
|
47
52
|
* */
|
|
48
53
|
whiteSpace?: WhiteSpace;
|
|
54
|
+
/**
|
|
55
|
+
* Children
|
|
56
|
+
*/
|
|
57
|
+
children?: React.ReactNode;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
/**
|
|
@@ -56,7 +65,7 @@ const COMPONENT_NAME = 'Text';
|
|
|
56
65
|
/**
|
|
57
66
|
* Component default class name and class prefix.
|
|
58
67
|
*/
|
|
59
|
-
const CLASSNAME
|
|
68
|
+
const CLASSNAME = getRootClassName(COMPONENT_NAME);
|
|
60
69
|
|
|
61
70
|
/**
|
|
62
71
|
* Component default props.
|
|
@@ -126,7 +135,7 @@ export const Text = forwardRef<TextProps>((props, ref) => {
|
|
|
126
135
|
{children &&
|
|
127
136
|
Children.toArray(children).map((child, index) => {
|
|
128
137
|
// Force wrap spaces around icons to make sure they are never stuck against text.
|
|
129
|
-
if (
|
|
138
|
+
if (isComponent(Icon)(child)) {
|
|
130
139
|
return <Fragment key={child.key || index}> {child} </Fragment>;
|
|
131
140
|
}
|
|
132
141
|
return child;
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
queryByClassName,
|
|
13
13
|
queryByTagName,
|
|
14
14
|
} from '@lumx/react/testing/utils/queries';
|
|
15
|
+
import partition from 'lodash/partition';
|
|
15
16
|
import userEvent from '@testing-library/user-event';
|
|
16
17
|
|
|
17
18
|
import { isFocusVisible } from '@lumx/react/utils/browser/isFocusVisible';
|
|
18
|
-
import { partitionMulti } from '@lumx/react/utils/collection/partitionMulti';
|
|
19
19
|
import { TextField, TextFieldProps } from './TextField';
|
|
20
20
|
|
|
21
21
|
const CLASSNAME = TextField.className as string;
|
|
@@ -34,7 +34,7 @@ const setup = (propsOverride: Partial<TextFieldProps> = {}, { wrapper }: SetupRe
|
|
|
34
34
|
| HTMLTextAreaElement
|
|
35
35
|
| HTMLInputElement;
|
|
36
36
|
const helpers = queryAllByClassName(container, 'lumx-text-field__helper');
|
|
37
|
-
const [[helper], [error]] =
|
|
37
|
+
const [[helper], [error]] = partition(helpers, (h) => !h.className.includes('lumx-input-helper--color-red'));
|
|
38
38
|
const clearButton = queryByClassName(container, 'lumx-text-field__input-clear');
|
|
39
39
|
|
|
40
40
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { ReactNode, Ref, RefObject, SyntheticEvent, useEffect, useRef, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
+
import get from 'lodash/get';
|
|
4
5
|
|
|
5
6
|
import { mdiAlertCircle, mdiCheckCircle, mdiCloseCircle } from '@lumx/icons';
|
|
6
7
|
import {
|
|
@@ -15,9 +16,9 @@ import {
|
|
|
15
16
|
Size,
|
|
16
17
|
Theme,
|
|
17
18
|
} from '@lumx/react';
|
|
18
|
-
import
|
|
19
|
-
import { handleBasicClasses } from '@lumx/react/utils/className';
|
|
20
|
-
import { mergeRefs } from '@lumx/react/utils/mergeRefs';
|
|
19
|
+
import { GenericProps, HasTheme } from '@lumx/react/utils/type';
|
|
20
|
+
import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
|
|
21
|
+
import { mergeRefs } from '@lumx/react/utils/react/mergeRefs';
|
|
21
22
|
import { useId } from '@lumx/react/hooks/useId';
|
|
22
23
|
import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
|
|
23
24
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
@@ -27,7 +28,7 @@ import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
|
27
28
|
*/
|
|
28
29
|
export interface TextFieldProps extends GenericProps, HasTheme {
|
|
29
30
|
/** Chip Group to be rendered before the main text input. */
|
|
30
|
-
chips?:
|
|
31
|
+
chips?: ReactNode;
|
|
31
32
|
/** Props to pass to the clear button (minus those already set by the TextField props). If not specified, the button won't be displayed. */
|
|
32
33
|
clearButtonProps?: Pick<IconButtonProps, 'label'> &
|
|
33
34
|
Omit<IconButtonProps, 'label' | 'onClick' | 'icon' | 'emphasis'>;
|
|
@@ -91,7 +92,7 @@ const COMPONENT_NAME = 'TextField';
|
|
|
91
92
|
/**
|
|
92
93
|
* Component default class name and class prefix.
|
|
93
94
|
*/
|
|
94
|
-
const CLASSNAME
|
|
95
|
+
const CLASSNAME = getRootClassName(COMPONENT_NAME);
|
|
95
96
|
|
|
96
97
|
/**
|
|
97
98
|
* Default minimum number of rows in the multiline mode.
|
|
@@ -216,8 +217,8 @@ const renderInputNative: React.FC<InputNativeProps> = (props) => {
|
|
|
216
217
|
setFocus(false);
|
|
217
218
|
};
|
|
218
219
|
|
|
219
|
-
const handleChange = (event: React.ChangeEvent
|
|
220
|
-
onChange(event
|
|
220
|
+
const handleChange = (event: React.ChangeEvent) => {
|
|
221
|
+
onChange(get(event, 'target.value'), name, event);
|
|
221
222
|
};
|
|
222
223
|
|
|
223
224
|
const Component = multiline ? 'textarea' : 'input';
|
|
@@ -12,10 +12,10 @@ import React, {
|
|
|
12
12
|
import classNames from 'classnames';
|
|
13
13
|
|
|
14
14
|
import { AspectRatio, HorizontalAlignment, Icon, Size, Theme, ThumbnailObjectFit } from '@lumx/react';
|
|
15
|
-
import
|
|
16
|
-
import { handleBasicClasses } from '@lumx/react/utils/className';
|
|
15
|
+
import { Falsy, GenericProps, HasTheme } from '@lumx/react/utils/type';
|
|
16
|
+
import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
|
|
17
17
|
import { mdiImageBroken } from '@lumx/icons';
|
|
18
|
-
import { useMergeRefs } from '@lumx/react/utils/mergeRefs';
|
|
18
|
+
import { useMergeRefs } from '@lumx/react/utils/react/mergeRefs';
|
|
19
19
|
import { useImageLoad } from '@lumx/react/components/thumbnail/useImageLoad';
|
|
20
20
|
import { useFocusPointStyle } from '@lumx/react/components/thumbnail/useFocusPointStyle';
|
|
21
21
|
import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
|
|
@@ -81,7 +81,7 @@ const COMPONENT_NAME = 'Thumbnail';
|
|
|
81
81
|
/**
|
|
82
82
|
* Component default class name and class prefix.
|
|
83
83
|
*/
|
|
84
|
-
const CLASSNAME
|
|
84
|
+
const CLASSNAME = getRootClassName(COMPONENT_NAME);
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
87
|
* Component default props.
|
|
@@ -2,8 +2,8 @@ import React, { ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
|
|
5
|
-
import { GenericProps
|
|
6
|
-
import { handleBasicClasses } from '@lumx/react/utils/className';
|
|
5
|
+
import { GenericProps } from '@lumx/react/utils/type';
|
|
6
|
+
import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
|
|
7
7
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -26,7 +26,7 @@ const COMPONENT_NAME = 'Toolbar';
|
|
|
26
26
|
/**
|
|
27
27
|
* Component default class name and class prefix.
|
|
28
28
|
*/
|
|
29
|
-
const CLASSNAME
|
|
29
|
+
const CLASSNAME = getRootClassName(COMPONENT_NAME);
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Component default props.
|
|
@@ -5,9 +5,9 @@ import { createPortal } from 'react-dom';
|
|
|
5
5
|
import classNames from 'classnames';
|
|
6
6
|
|
|
7
7
|
import { DOCUMENT, VISUALLY_HIDDEN } from '@lumx/react/constants';
|
|
8
|
-
import
|
|
9
|
-
import { handleBasicClasses } from '@lumx/react/utils/className';
|
|
10
|
-
import { useMergeRefs } from '@lumx/react/utils/mergeRefs';
|
|
8
|
+
import { GenericProps, HasCloseMode } from '@lumx/react/utils/type';
|
|
9
|
+
import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
|
|
10
|
+
import { useMergeRefs } from '@lumx/react/utils/react/mergeRefs';
|
|
11
11
|
import { Placement } from '@lumx/react/components/popover';
|
|
12
12
|
import { TooltipContextProvider } from '@lumx/react/components/tooltip/context';
|
|
13
13
|
import { useId } from '@lumx/react/hooks/useId';
|
|
@@ -47,7 +47,7 @@ const COMPONENT_NAME = 'Tooltip';
|
|
|
47
47
|
/**
|
|
48
48
|
* Component default class name and class prefix.
|
|
49
49
|
*/
|
|
50
|
-
const CLASSNAME
|
|
50
|
+
const CLASSNAME = getRootClassName(COMPONENT_NAME);
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Component default props.
|
|
@@ -10,7 +10,7 @@ const DEFAULT_VALUE = {};
|
|
|
10
10
|
*/
|
|
11
11
|
const TooltipContext = React.createContext<TooltipContextValue | undefined>(undefined);
|
|
12
12
|
|
|
13
|
-
export const TooltipContextProvider: React.FC = ({ children }) => (
|
|
13
|
+
export const TooltipContextProvider: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
|
|
14
14
|
<TooltipContext.Provider value={DEFAULT_VALUE}>{children}</TooltipContext.Provider>
|
|
15
15
|
);
|
|
16
16
|
|
|
@@ -3,8 +3,8 @@ import React, { MouseEventHandler } from 'react';
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
|
|
5
5
|
import { AspectRatio, Icon, Size, Theme } from '@lumx/react';
|
|
6
|
-
import
|
|
7
|
-
import { handleBasicClasses } from '@lumx/react/utils/className';
|
|
6
|
+
import { GenericProps, HasTheme, ValueOf } from '@lumx/react/utils/type';
|
|
7
|
+
import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
|
|
8
8
|
import { useBooleanState } from '@lumx/react/hooks/useBooleanState';
|
|
9
9
|
import { useId } from '@lumx/react/hooks/useId';
|
|
10
10
|
import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
|
|
@@ -60,7 +60,7 @@ const COMPONENT_NAME = 'Uploader';
|
|
|
60
60
|
/**
|
|
61
61
|
* Component default class name and class prefix.
|
|
62
62
|
*/
|
|
63
|
-
const CLASSNAME
|
|
63
|
+
const CLASSNAME = getRootClassName(COMPONENT_NAME);
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* Component default props.
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
|
+
|
|
2
3
|
import classNames from 'classnames';
|
|
4
|
+
import isEmpty from 'lodash/isEmpty';
|
|
5
|
+
import set from 'lodash/set';
|
|
3
6
|
|
|
4
7
|
import { Avatar, ColorPalette, Link, Orientation, Size, Theme } from '@lumx/react';
|
|
5
|
-
import
|
|
6
|
-
import { handleBasicClasses } from '@lumx/react/utils/className';
|
|
8
|
+
import { GenericProps, HasTheme } from '@lumx/react/utils/type';
|
|
9
|
+
import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
|
|
7
10
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
8
11
|
|
|
9
12
|
import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
|
|
@@ -54,7 +57,7 @@ const COMPONENT_NAME = 'UserBlock';
|
|
|
54
57
|
/**
|
|
55
58
|
* Component default class name and class prefix.
|
|
56
59
|
*/
|
|
57
|
-
const CLASSNAME
|
|
60
|
+
const CLASSNAME = getRootClassName(COMPONENT_NAME);
|
|
58
61
|
|
|
59
62
|
/**
|
|
60
63
|
* Component default props.
|
|
@@ -104,7 +107,7 @@ export const UserBlock = forwardRef<UserBlockProps, HTMLDivElement>((props, ref)
|
|
|
104
107
|
const isClickable = !!onClick || isLink;
|
|
105
108
|
|
|
106
109
|
const nameBlock: ReactNode = React.useMemo(() => {
|
|
107
|
-
if (
|
|
110
|
+
if (isEmpty(name)) {
|
|
108
111
|
return null;
|
|
109
112
|
}
|
|
110
113
|
let NameComponent: any = 'span';
|
|
@@ -121,8 +124,12 @@ export const UserBlock = forwardRef<UserBlockProps, HTMLDivElement>((props, ref)
|
|
|
121
124
|
color: ColorPalette.dark,
|
|
122
125
|
});
|
|
123
126
|
}
|
|
127
|
+
// Disable avatar focus since the name block is the same link / same button.
|
|
128
|
+
if (avatarProps) {
|
|
129
|
+
set(avatarProps, ['thumbnailProps', 'tabIndex'], -1);
|
|
130
|
+
}
|
|
124
131
|
return <NameComponent {...nProps}>{name}</NameComponent>;
|
|
125
|
-
}, [isClickable, linkAs, linkProps, name, nameProps, onClick]);
|
|
132
|
+
}, [avatarProps, isClickable, linkAs, linkProps, name, nameProps, onClick]);
|
|
126
133
|
|
|
127
134
|
const fieldsBlock: ReactNode = fields && componentSize !== Size.s && componentSize !== Size.xs && (
|
|
128
135
|
<div className={`${CLASSNAME}__fields`}>
|
|
@@ -155,11 +162,6 @@ export const UserBlock = forwardRef<UserBlockProps, HTMLDivElement>((props, ref)
|
|
|
155
162
|
size={componentSize}
|
|
156
163
|
onClick={onClick}
|
|
157
164
|
theme={theme}
|
|
158
|
-
thumbnailProps={{
|
|
159
|
-
...avatarProps?.thumbnailProps,
|
|
160
|
-
// Disable avatar focus since the name block is the same link / same button.
|
|
161
|
-
tabIndex: avatarProps ? -1 : undefined,
|
|
162
|
-
}}
|
|
163
165
|
/>
|
|
164
166
|
)}
|
|
165
167
|
{(fields || name) && (
|
|
@@ -2,7 +2,7 @@ import { DOCUMENT } from '@lumx/react/constants';
|
|
|
2
2
|
import { Callback } from '@lumx/react/utils/type';
|
|
3
3
|
import { onEscapePressed } from '@lumx/react/utils/browser/event';
|
|
4
4
|
import { useEffect } from 'react';
|
|
5
|
-
import { Listener, makeListenerTowerContext } from '@lumx/react/utils/makeListenerTowerContext';
|
|
5
|
+
import { Listener, makeListenerTowerContext } from '@lumx/react/utils/function/makeListenerTowerContext';
|
|
6
6
|
|
|
7
7
|
const LISTENERS = makeListenerTowerContext();
|
|
8
8
|
|
|
@@ -3,7 +3,7 @@ import { useEffect } from 'react';
|
|
|
3
3
|
import { DOCUMENT } from '@lumx/react/constants';
|
|
4
4
|
import { getFirstAndLastFocusable } from '@lumx/react/utils/browser/focus/getFirstAndLastFocusable';
|
|
5
5
|
import { Falsy } from '@lumx/react/utils/type';
|
|
6
|
-
import { Listener, makeListenerTowerContext } from '@lumx/react/utils/makeListenerTowerContext';
|
|
6
|
+
import { Listener, makeListenerTowerContext } from '@lumx/react/utils/function/makeListenerTowerContext';
|
|
7
7
|
|
|
8
8
|
const FOCUS_TRAPS = makeListenerTowerContext();
|
|
9
9
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react';
|
|
2
2
|
|
|
3
|
+
import isFunction from 'lodash/isFunction';
|
|
3
4
|
import { Callback } from '@lumx/react/utils/type';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -20,7 +21,9 @@ export function useInterval(callback: Callback, delay: number | null): void {
|
|
|
20
21
|
if (delay === null) return undefined;
|
|
21
22
|
|
|
22
23
|
function tick() {
|
|
23
|
-
savedCallback.current
|
|
24
|
+
if (isFunction(savedCallback.current)) {
|
|
25
|
+
savedCallback.current();
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
28
|
const id = setInterval(tick, delay);
|
|
26
29
|
return () => clearInterval(id);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { RefObject, SetStateAction, useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
|
+
import get from 'lodash/get';
|
|
4
|
+
|
|
3
5
|
type Listener = (evt: KeyboardEvent) => void;
|
|
4
6
|
|
|
5
7
|
interface UseKeyboardListNavigationType {
|
|
@@ -133,7 +135,7 @@ export const useKeyboardListNavigation: useKeyboardListNavigationType = (
|
|
|
133
135
|
onListItemSelected(selectedItem);
|
|
134
136
|
resetActiveIndex();
|
|
135
137
|
} else if (activeItemIndex === initialIndex && onEnterPressed) {
|
|
136
|
-
const value = (evt.
|
|
138
|
+
const value = get(evt, 'target.value');
|
|
137
139
|
onEnterPressed(value);
|
|
138
140
|
resetActiveIndex();
|
|
139
141
|
}
|
|
@@ -144,7 +146,7 @@ export const useKeyboardListNavigation: useKeyboardListNavigationType = (
|
|
|
144
146
|
* @param evt - key pressed event
|
|
145
147
|
*/
|
|
146
148
|
const onTabKeyPressed: Listener = (evt) => {
|
|
147
|
-
const value = (evt.
|
|
149
|
+
const value = get(evt, 'target.value');
|
|
148
150
|
|
|
149
151
|
if (preventTabOnEnteredValue && value && value.length > 0) {
|
|
150
152
|
preventDefaultAndStopPropagation(evt);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import throttle from 'lodash/throttle';
|
|
4
|
+
import { RectSize } from '@lumx/react/utils/type';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Observe element size (only works if it's size depends on the window size).
|
|
@@ -12,19 +13,14 @@ import type { RectSize } from '@lumx/react/utils/type';
|
|
|
12
13
|
*/
|
|
13
14
|
export function useSizeOnWindowResize(elementRef: React.RefObject<HTMLElement>): [RectSize | null, () => void] {
|
|
14
15
|
const [size, setSize] = React.useState<null | RectSize>(null);
|
|
15
|
-
const updateSize = React.useMemo(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (!prevTimeout) {
|
|
24
|
-
prevTimeout = setTimeout(update, 10);
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
}, [elementRef]);
|
|
16
|
+
const updateSize = React.useMemo(
|
|
17
|
+
() =>
|
|
18
|
+
throttle(() => {
|
|
19
|
+
const newSize = elementRef.current?.getBoundingClientRect();
|
|
20
|
+
if (newSize) setSize(newSize);
|
|
21
|
+
}, 10),
|
|
22
|
+
[elementRef],
|
|
23
|
+
);
|
|
28
24
|
React.useEffect(() => {
|
|
29
25
|
updateSize();
|
|
30
26
|
window.addEventListener('resize', updateSize);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import isFunction from 'lodash/isFunction';
|
|
1
2
|
import { MouseEventHandler, useCallback } from 'react';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -9,7 +10,7 @@ import { MouseEventHandler, useCallback } from 'react';
|
|
|
9
10
|
export function useStopPropagation(handler?: MouseEventHandler): MouseEventHandler {
|
|
10
11
|
return useCallback(
|
|
11
12
|
(evt) => {
|
|
12
|
-
if (!evt || !handler) {
|
|
13
|
+
if (!evt || !isFunction(handler)) {
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
15
16
|
handler(evt);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable react/display-name,jsx-a11y/control-has-associated-label,prefer-object-spread */
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import
|
|
3
|
+
import isEmpty from 'lodash/isEmpty';
|
|
4
4
|
import { Heading, HeadingLevelProvider } from '@lumx/react';
|
|
5
5
|
|
|
6
6
|
type PropEntry = [key: string, value: unknown];
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isEmpty from 'lodash/isEmpty';
|
|
2
2
|
|
|
3
3
|
import { GenericProps } from '@lumx/react/utils/type';
|
|
4
4
|
import { queryByClassName } from '@lumx/react/testing/utils/queries';
|
|
5
|
+
import React from 'react';
|
|
5
6
|
import { Theme } from '@lumx/react';
|
|
6
7
|
import { RenderOptions } from '@testing-library/react';
|
|
7
8
|
import { ThemeProvider } from '@lumx/react/utils/theme/ThemeContext';
|
|
8
9
|
import castArray from 'lodash/castArray';
|
|
9
10
|
import { invertTheme } from '@lumx/react/utils/theme/invertTheme';
|
|
10
|
-
import { isEmpty } from '@lumx/react/utils/collection/isEmpty';
|
|
11
11
|
|
|
12
12
|
interface CommonSetup {
|
|
13
13
|
props: GenericProps;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getRootClassName } from '@lumx/react/utils/className/getRootClassName';
|
|
2
|
+
|
|
3
|
+
describe(getRootClassName, () => {
|
|
4
|
+
it('should transform the component name into a lumx class', () => {
|
|
5
|
+
expect(getRootClassName('Table')).toBe('lumx-table');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should transform the sub component name into a lumx class', () => {
|
|
9
|
+
expect(getRootClassName('TableBody', true)).toBe('lumx-table__body');
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CSS_PREFIX } from '@lumx/core/js/constants';
|
|
2
|
+
import kebabCase from 'lodash/kebabCase';
|
|
3
|
+
|
|
4
|
+
// See https://regex101.com/r/YjS1uI/3
|
|
5
|
+
const LAST_PART_CLASSNAME = /^(.*)-(.+)$/gi;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get the name of the root CSS class of a component based on its name.
|
|
9
|
+
*
|
|
10
|
+
* @param componentName The name of the component. This name should contains the component prefix and be
|
|
11
|
+
* written in PascalCase.
|
|
12
|
+
* @param subComponent Whether the current component is a sub component, if true, define the class according
|
|
13
|
+
* to BEM standards.
|
|
14
|
+
* @return The name of the root CSS class. This classname include the CSS classname prefix and is written in
|
|
15
|
+
* lower-snake-case.
|
|
16
|
+
*/
|
|
17
|
+
export function getRootClassName(componentName: string, subComponent?: boolean): string {
|
|
18
|
+
const formattedClassName = `${CSS_PREFIX}-${kebabCase(componentName)}`;
|
|
19
|
+
|
|
20
|
+
if (subComponent) {
|
|
21
|
+
return formattedClassName.replace(LAST_PART_CLASSNAME, '$1__$2');
|
|
22
|
+
}
|
|
23
|
+
return formattedClassName;
|
|
24
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import last from 'lodash/last';
|
|
2
|
+
|
|
1
3
|
import { getWeekDays, WeekDayInfo } from '@lumx/react/utils/date/getWeekDays';
|
|
2
4
|
import { Locale } from '@lumx/react/utils/locale/types';
|
|
3
|
-
import { last } from '@lumx/react/utils/collection/last';
|
|
4
5
|
|
|
5
6
|
type AnnotatedDay = { date: Date; isOutOfRange?: boolean };
|
|
6
7
|
type AnnotatedWeek = Partial<Record<number, AnnotatedDay>>;
|
|
@@ -28,7 +29,7 @@ export const getMonthCalendar = (
|
|
|
28
29
|
iterDate.setDate(1);
|
|
29
30
|
|
|
30
31
|
const weekDays = getWeekDays(locale);
|
|
31
|
-
const lastDayOfWeek = last(weekDays);
|
|
32
|
+
const lastDayOfWeek = last(weekDays) as WeekDayInfo;
|
|
32
33
|
|
|
33
34
|
const weeks: Array<AnnotatedWeek> = [];
|
|
34
35
|
let week: AnnotatedWeek = {};
|
|
@@ -46,7 +47,7 @@ export const getMonthCalendar = (
|
|
|
46
47
|
week[weekDayNumber] = day;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
if (weekDayNumber === lastDayOfWeek
|
|
50
|
+
if (weekDayNumber === lastDayOfWeek.number) {
|
|
50
51
|
weeks.push(week);
|
|
51
52
|
rowCount += 1;
|
|
52
53
|
week = {};
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import concat from 'lodash/concat';
|
|
2
|
+
import dropRight from 'lodash/dropRight';
|
|
3
|
+
import last from 'lodash/last';
|
|
4
|
+
import partition from 'lodash/partition';
|
|
5
|
+
import reduce from 'lodash/reduce';
|
|
6
|
+
import { Predicate } from './type';
|
|
2
7
|
|
|
3
8
|
/**
|
|
4
9
|
* Similar to lodash `partition` function but working with multiple predicates.
|
|
@@ -14,16 +19,10 @@ import type { Predicate } from '../type';
|
|
|
14
19
|
* @return partitioned elements by the given predicates
|
|
15
20
|
*/
|
|
16
21
|
export function partitionMulti<T>(elements: T[], predicates: Array<Predicate<T>>): T[][] {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
groups[index].push(element);
|
|
24
|
-
} else {
|
|
25
|
-
others.push(element);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return [...groups, others];
|
|
22
|
+
return reduce(
|
|
23
|
+
predicates,
|
|
24
|
+
(partitioned: T[][], predicate: Predicate<T>) =>
|
|
25
|
+
concat(dropRight(partitioned), partition(last(partitioned), predicate)),
|
|
26
|
+
[elements],
|
|
27
|
+
);
|
|
29
28
|
}
|