@lumx/react 3.11.4-alpha.0 → 3.12.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.
- package/index.d.ts +15 -3
- package/index.js +117 -150
- package/index.js.map +1 -1
- package/package.json +11 -11
- package/src/components/button/Button.test.tsx +2 -1
- package/src/components/button/Button.tsx +13 -3
- package/src/components/input-label/InputLabel.stories.tsx +9 -0
- package/src/components/input-label/InputLabel.test.tsx +8 -1
- package/src/components/input-label/InputLabel.tsx +11 -4
- package/src/components/link/Link.stories.tsx +54 -23
- package/src/components/link/Link.test.tsx +10 -8
- package/src/components/link/Link.tsx +41 -88
- package/src/components/text/Text.tsx +5 -11
- package/src/components/text-field/TextField.stories.tsx +15 -1
- package/src/components/user-block/UserBlock.stories.tsx +29 -2
- package/src/components/user-block/UserBlock.test.tsx +15 -3
- package/src/components/user-block/UserBlock.tsx +15 -4
- package/src/stories/controls/icons.ts +1 -0
- package/src/testing/utils/commonTestsSuiteRTL.tsx +5 -3
- package/src/utils/react/wrapChildrenIconWithSpaces.test.tsx +40 -0
- package/src/utils/react/wrapChildrenIconWithSpaces.tsx +22 -0
|
@@ -32,7 +32,7 @@ export interface UserBlockProps extends GenericProps, HasTheme {
|
|
|
32
32
|
/** Multiple action toolbar content. */
|
|
33
33
|
multipleActions?: ReactNode;
|
|
34
34
|
/** User name. */
|
|
35
|
-
name?:
|
|
35
|
+
name?: React.ReactNode;
|
|
36
36
|
/** Props to pass to the name block. */
|
|
37
37
|
nameProps?: GenericProps;
|
|
38
38
|
/** Orientation. */
|
|
@@ -47,6 +47,10 @@ export interface UserBlockProps extends GenericProps, HasTheme {
|
|
|
47
47
|
onMouseEnter?(): void;
|
|
48
48
|
/** On mouse leave callback. */
|
|
49
49
|
onMouseLeave?(): void;
|
|
50
|
+
/** Display additional fields below the original name and fields */
|
|
51
|
+
additionalFields?: React.ReactNode;
|
|
52
|
+
/** Display an additional element after the entire component. (to the right if orientation is horizontal, at the bottom if orientation is vertical) */
|
|
53
|
+
after?: React.ReactNode;
|
|
50
54
|
}
|
|
51
55
|
|
|
52
56
|
/**
|
|
@@ -92,6 +96,9 @@ export const UserBlock = forwardRef<UserBlockProps, HTMLDivElement>((props, ref)
|
|
|
92
96
|
simpleAction,
|
|
93
97
|
size,
|
|
94
98
|
theme = defaultTheme,
|
|
99
|
+
children,
|
|
100
|
+
additionalFields,
|
|
101
|
+
after,
|
|
95
102
|
...forwardedProps
|
|
96
103
|
} = props;
|
|
97
104
|
let componentSize = size;
|
|
@@ -131,7 +138,9 @@ export const UserBlock = forwardRef<UserBlockProps, HTMLDivElement>((props, ref)
|
|
|
131
138
|
return <NameComponent {...nProps}>{name}</NameComponent>;
|
|
132
139
|
}, [avatarProps, isClickable, linkAs, linkProps, name, nameProps, onClick]);
|
|
133
140
|
|
|
134
|
-
const
|
|
141
|
+
const shouldDisplayFields = componentSize !== Size.s && componentSize !== Size.xs;
|
|
142
|
+
|
|
143
|
+
const fieldsBlock: ReactNode = fields && shouldDisplayFields && (
|
|
135
144
|
<div className={`${CLASSNAME}__fields`}>
|
|
136
145
|
{fields.map((field: string, idx: number) => (
|
|
137
146
|
<span key={idx} className={`${CLASSNAME}__field`}>
|
|
@@ -164,16 +173,18 @@ export const UserBlock = forwardRef<UserBlockProps, HTMLDivElement>((props, ref)
|
|
|
164
173
|
theme={theme}
|
|
165
174
|
/>
|
|
166
175
|
)}
|
|
167
|
-
{(fields || name) && (
|
|
176
|
+
{(fields || name || children || additionalFields) && (
|
|
168
177
|
<div className={`${CLASSNAME}__wrapper`}>
|
|
169
|
-
{nameBlock}
|
|
178
|
+
{children || nameBlock}
|
|
170
179
|
{fieldsBlock}
|
|
180
|
+
{shouldDisplayFields ? additionalFields : null}
|
|
171
181
|
</div>
|
|
172
182
|
)}
|
|
173
183
|
{shouldDisplayActions && simpleAction && <div className={`${CLASSNAME}__action`}>{simpleAction}</div>}
|
|
174
184
|
{shouldDisplayActions && multipleActions && (
|
|
175
185
|
<div className={`${CLASSNAME}__actions`}>{multipleActions}</div>
|
|
176
186
|
)}
|
|
187
|
+
{after ? <div className={`${CLASSNAME}__after`}>{after}</div> : null}
|
|
177
188
|
</div>
|
|
178
189
|
);
|
|
179
190
|
});
|
|
@@ -30,6 +30,8 @@ interface Options<S extends CommonSetup> {
|
|
|
30
30
|
viaContext: boolean;
|
|
31
31
|
/** Apply a default theme if no prop or context was provided */
|
|
32
32
|
defaultTheme?: Theme;
|
|
33
|
+
/** Default props to apply when testing theme */
|
|
34
|
+
defaultProps?: S['props'];
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -128,7 +130,7 @@ export function commonTestsSuiteRTL<S extends CommonSetup>(setup: SetupFunction<
|
|
|
128
130
|
it.each(testElements)(
|
|
129
131
|
`should $apply default theme (${defaultTheme}) to \`$element\``,
|
|
130
132
|
async (affectedElement) => {
|
|
131
|
-
const wrappers = await setup();
|
|
133
|
+
const wrappers = await setup(applyTheme.defaultProps);
|
|
132
134
|
expectTheme(wrappers, affectedElement, defaultTheme);
|
|
133
135
|
},
|
|
134
136
|
);
|
|
@@ -140,7 +142,7 @@ export function commonTestsSuiteRTL<S extends CommonSetup>(setup: SetupFunction<
|
|
|
140
142
|
it.each(affectedElements)(
|
|
141
143
|
`should not apply default theme (${defaultTheme}) to \`$element\``,
|
|
142
144
|
async (affectedElement) => {
|
|
143
|
-
const wrappers = await setup();
|
|
145
|
+
const wrappers = await setup(applyTheme.defaultProps);
|
|
144
146
|
expectTheme(wrappers, affectedElement, Theme.light, { shouldHaveModifier: false });
|
|
145
147
|
expectTheme(wrappers, affectedElement, Theme.dark, { shouldHaveModifier: false });
|
|
146
148
|
},
|
|
@@ -152,7 +154,7 @@ export function commonTestsSuiteRTL<S extends CommonSetup>(setup: SetupFunction<
|
|
|
152
154
|
it.each(testElements)(
|
|
153
155
|
`should $apply prop theme=${theme} to \`$element\``,
|
|
154
156
|
async (affectedElement) => {
|
|
155
|
-
const wrappers = await setup({ theme });
|
|
157
|
+
const wrappers = await setup({ ...applyTheme.defaultProps, theme });
|
|
156
158
|
expectTheme(wrappers, affectedElement, theme);
|
|
157
159
|
},
|
|
158
160
|
);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Icon } from '@lumx/react';
|
|
4
|
+
import { mdiEarth, mdiFoodApple, mdiPencil } from '@lumx/icons';
|
|
5
|
+
import { wrapChildrenIconWithSpaces } from './wrapChildrenIconWithSpaces';
|
|
6
|
+
|
|
7
|
+
describe(wrapChildrenIconWithSpaces, () => {
|
|
8
|
+
it('should ignore null or undefined children', () => {
|
|
9
|
+
expect(wrapChildrenIconWithSpaces(undefined)).toBeUndefined();
|
|
10
|
+
expect(wrapChildrenIconWithSpaces(null)).toBeUndefined();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should wrap icons with spaces', () => {
|
|
14
|
+
expect(
|
|
15
|
+
wrapChildrenIconWithSpaces(
|
|
16
|
+
<>
|
|
17
|
+
<Icon icon={mdiEarth} />a string
|
|
18
|
+
<>
|
|
19
|
+
some more string with
|
|
20
|
+
<Icon icon={mdiFoodApple} />
|
|
21
|
+
</>
|
|
22
|
+
{['array with', <Icon key="custom-key" icon={mdiPencil} />]}
|
|
23
|
+
</>,
|
|
24
|
+
),
|
|
25
|
+
).toEqual([
|
|
26
|
+
' ',
|
|
27
|
+
<Icon key=".0" icon={mdiEarth} />,
|
|
28
|
+
' ',
|
|
29
|
+
'a string',
|
|
30
|
+
'some more string with',
|
|
31
|
+
' ',
|
|
32
|
+
<Icon key=".1" icon={mdiFoodApple} />,
|
|
33
|
+
' ',
|
|
34
|
+
'array with',
|
|
35
|
+
' ',
|
|
36
|
+
<Icon key=".3:$custom-key" icon={mdiPencil} />,
|
|
37
|
+
' ',
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { Children } from 'react';
|
|
2
|
+
import { isComponentType } from '@lumx/react/utils/type';
|
|
3
|
+
import { Icon } from '@lumx/react';
|
|
4
|
+
|
|
5
|
+
/** Force wrap spaces around icons to make sure they are never stuck against text. */
|
|
6
|
+
export function wrapChildrenIconWithSpaces(children: React.ReactNode): React.ReactNode {
|
|
7
|
+
if (children === null || children === undefined) return undefined;
|
|
8
|
+
return Children.toArray(children).flatMap((child) => {
|
|
9
|
+
if (!React.isValidElement(child)) {
|
|
10
|
+
return child;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (child.type === React.Fragment) {
|
|
14
|
+
return wrapChildrenIconWithSpaces(child.props.children);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (isComponentType(Icon)(child)) {
|
|
18
|
+
return [' ', child, ' '];
|
|
19
|
+
}
|
|
20
|
+
return child;
|
|
21
|
+
});
|
|
22
|
+
}
|