@pushwoosh/dumb-components 2.3.0 → 2.4.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/Banner/Banner.d.ts +3 -0
- package/Banner/Banner.js +12 -3
- package/Banner/__tests__/Banner.test.d.ts +1 -0
- package/Banner/__tests__/Banner.test.js +57 -0
- package/Banner/styles.d.ts +1 -1
- package/Banner/styles.js +2 -2
- package/Banner/types.d.ts +13 -4
- package/Tooltip/styles.js +1 -1
- package/Tooltip/types.d.ts +1 -1
- package/package.json +3 -3
package/Banner/Banner.d.ts
CHANGED
|
@@ -3,8 +3,11 @@ import type { BannerPropsWithButton, RequiredBannerProps } from './types';
|
|
|
3
3
|
/**
|
|
4
4
|
* Prominent page-level message with severity styling, an optional action button,
|
|
5
5
|
* a loading state and a dismiss button. Hides itself once closed.
|
|
6
|
+
* Needs a non-empty `title`, body content (`children`), or both; with neither it renders nothing.
|
|
6
7
|
*
|
|
7
8
|
* @example
|
|
8
9
|
* <Banner type="success" title="Saved" canBeClosed action={{ buttonText: 'Undo', onClick: undo }} />
|
|
10
|
+
* @example
|
|
11
|
+
* <Banner type="warning" view="ghost">Only a description, no title</Banner>
|
|
9
12
|
*/
|
|
10
13
|
export declare function Banner(props: RequiredBannerProps | BannerPropsWithButton): ReactElement | null;
|
package/Banner/Banner.js
CHANGED
|
@@ -9,9 +9,12 @@ import { ActionButton, BannerContent, BannerSpinner, CloseButton, IconContainer
|
|
|
9
9
|
/**
|
|
10
10
|
* Prominent page-level message with severity styling, an optional action button,
|
|
11
11
|
* a loading state and a dismiss button. Hides itself once closed.
|
|
12
|
+
* Needs a non-empty `title`, body content (`children`), or both; with neither it renders nothing.
|
|
12
13
|
*
|
|
13
14
|
* @example
|
|
14
15
|
* <Banner type="success" title="Saved" canBeClosed action={{ buttonText: 'Undo', onClick: undo }} />
|
|
16
|
+
* @example
|
|
17
|
+
* <Banner type="warning" view="ghost">Only a description, no title</Banner>
|
|
15
18
|
*/
|
|
16
19
|
export function Banner(props) {
|
|
17
20
|
const [isOpen, setIsOpen] = useState(true);
|
|
@@ -48,6 +51,12 @@ export function Banner(props) {
|
|
|
48
51
|
console.error(`[Banner]: required prop type "${type}" is not set`);
|
|
49
52
|
return null;
|
|
50
53
|
}
|
|
54
|
+
const hasTitle = title !== undefined && title !== '';
|
|
55
|
+
const hasChildren = children !== undefined && children !== null && typeof children !== 'boolean';
|
|
56
|
+
if (!hasTitle && !hasChildren) {
|
|
57
|
+
console.error('[Banner]: neither title nor children is set');
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
51
60
|
const BannerBox = BannerPropsToBannerBoxMap[view];
|
|
52
61
|
if (!BannerBox) {
|
|
53
62
|
console.error(`[Banner]: cannot render with type "${type}" and view "${view}"`);
|
|
@@ -71,10 +80,10 @@ export function Banner(props) {
|
|
|
71
80
|
view: "filled"
|
|
72
81
|
})
|
|
73
82
|
}), _jsxs(BannerContent, {
|
|
74
|
-
"$
|
|
75
|
-
children: [_jsx(H4, {
|
|
83
|
+
"$hasTitleAndChildren": hasTitle && hasChildren,
|
|
84
|
+
children: [hasTitle && _jsx(H4, {
|
|
76
85
|
children: title
|
|
77
|
-
}),
|
|
86
|
+
}), hasChildren && _jsx("div", {
|
|
78
87
|
children: children
|
|
79
88
|
})]
|
|
80
89
|
}), action && _jsx(Vertical, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Banner } from '../Banner';
|
|
4
|
+
describe('Banner', () => {
|
|
5
|
+
let consoleError;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
8
|
+
});
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
consoleError.mockRestore();
|
|
11
|
+
});
|
|
12
|
+
it('renders a title without children', () => {
|
|
13
|
+
render(_jsx(Banner, {
|
|
14
|
+
type: "info",
|
|
15
|
+
title: "Heading"
|
|
16
|
+
}));
|
|
17
|
+
expect(screen.getByText('Heading')).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
it('renders children without a title', () => {
|
|
20
|
+
const {
|
|
21
|
+
container
|
|
22
|
+
} = render(_jsx(Banner, {
|
|
23
|
+
type: "info",
|
|
24
|
+
children: "Description"
|
|
25
|
+
}));
|
|
26
|
+
expect(screen.getByText('Description')).toBeInTheDocument();
|
|
27
|
+
expect(container.querySelector('h4')).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
it('renders numeric zero children', () => {
|
|
30
|
+
render(_jsx(Banner, {
|
|
31
|
+
type: "info",
|
|
32
|
+
children: 0
|
|
33
|
+
}));
|
|
34
|
+
expect(screen.getByText('0')).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
it('skips an empty title but keeps the children', () => {
|
|
37
|
+
const {
|
|
38
|
+
container
|
|
39
|
+
} = render(_jsx(Banner, {
|
|
40
|
+
type: "info",
|
|
41
|
+
title: "",
|
|
42
|
+
children: "Description"
|
|
43
|
+
}));
|
|
44
|
+
expect(screen.getByText('Description')).toBeInTheDocument();
|
|
45
|
+
expect(container.querySelector('h4')).toBeNull();
|
|
46
|
+
});
|
|
47
|
+
it('renders nothing and reports when there is neither title nor children', () => {
|
|
48
|
+
const {
|
|
49
|
+
container
|
|
50
|
+
} = render(_jsx(Banner, {
|
|
51
|
+
type: "info",
|
|
52
|
+
title: ""
|
|
53
|
+
}));
|
|
54
|
+
expect(container).toBeEmptyDOMElement();
|
|
55
|
+
expect(consoleError).toHaveBeenCalledWith('[Banner]: neither title nor children is set');
|
|
56
|
+
});
|
|
57
|
+
});
|
package/Banner/styles.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare const BannerBox: import("styled-components").StyledComponent<"div
|
|
|
12
12
|
$isLoading: boolean;
|
|
13
13
|
}, never>;
|
|
14
14
|
export declare const BannerContent: import("styled-components").StyledComponent<"div", any, {
|
|
15
|
-
$
|
|
15
|
+
$hasTitleAndChildren?: boolean;
|
|
16
16
|
}, never>;
|
|
17
17
|
export declare const IconContainer: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
18
18
|
export declare const BannerShape: import("styled-components").StyledComponent<"div", any, import("react").ClassAttributes<HTMLDivElement> & import("react").HTMLAttributes<HTMLDivElement> & {
|
package/Banner/styles.js
CHANGED
|
@@ -28,8 +28,8 @@ export const BannerContent = styled.div.withConfig({
|
|
|
28
28
|
displayName: "BannerContent",
|
|
29
29
|
componentId: "sc-9uu4ap-4"
|
|
30
30
|
})(["flex-grow:1;padding:", ";color:", ";"], ({
|
|
31
|
-
$
|
|
32
|
-
}) => $
|
|
31
|
+
$hasTitleAndChildren
|
|
32
|
+
}) => $hasTitleAndChildren ? '16px' : '8px 16px', colors.error.shape.base.color);
|
|
33
33
|
export const IconContainer = styled.div.withConfig({
|
|
34
34
|
displayName: "IconContainer",
|
|
35
35
|
componentId: "sc-9uu4ap-5"
|
package/Banner/types.d.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import type { ReactElement, ReactNode } from 'react';
|
|
2
2
|
/** Severity of a {@link Banner}, driving its icon and colors. */
|
|
3
3
|
export type BannerType = 'error' | 'warning' | 'info' | 'success';
|
|
4
|
-
|
|
5
|
-
export type RequiredBannerProps = {
|
|
4
|
+
type BannerBaseProps = {
|
|
6
5
|
/** Ref to the banner root element. */
|
|
7
6
|
readonly boxRef?: any;
|
|
8
7
|
/** Severity — sets the default icon and colors. */
|
|
9
8
|
readonly type: BannerType;
|
|
10
|
-
/** Banner heading. */
|
|
11
|
-
readonly title: string;
|
|
12
9
|
/** Surface style: `shape` (filled, default) or `ghost`. */
|
|
13
10
|
readonly view?: 'shape' | 'ghost';
|
|
14
11
|
/** Custom icon; falls back to the type's default icon. */
|
|
@@ -21,9 +18,20 @@ export type RequiredBannerProps = {
|
|
|
21
18
|
readonly canBeClosed?: boolean;
|
|
22
19
|
/** Fires when the close button is clicked. */
|
|
23
20
|
readonly onClose?: () => void;
|
|
21
|
+
};
|
|
22
|
+
type BannerContentProps = {
|
|
23
|
+
/** Banner heading; an empty string counts as no title. */
|
|
24
|
+
readonly title: string;
|
|
24
25
|
/** Body content under the title. */
|
|
25
26
|
readonly children?: ReactNode;
|
|
27
|
+
} | {
|
|
28
|
+
/** Banner heading; may be omitted when the body content is set. */
|
|
29
|
+
readonly title?: string;
|
|
30
|
+
/** Body content, shown alone when there is no title. */
|
|
31
|
+
readonly children: Exclude<ReactNode, null | undefined | boolean>;
|
|
26
32
|
};
|
|
33
|
+
/** Base props of {@link Banner}: a title, body content, or both. */
|
|
34
|
+
export type RequiredBannerProps = BannerBaseProps & BannerContentProps;
|
|
27
35
|
/** {@link Banner} props with an optional action button. */
|
|
28
36
|
export type BannerPropsWithButton = RequiredBannerProps & {
|
|
29
37
|
/** Action button shown on the right. */
|
|
@@ -34,3 +42,4 @@ export type BannerPropsWithButton = RequiredBannerProps & {
|
|
|
34
42
|
readonly buttonText: string;
|
|
35
43
|
};
|
|
36
44
|
};
|
|
45
|
+
export {};
|
package/Tooltip/styles.js
CHANGED
|
@@ -2,7 +2,7 @@ import styled, { css } from 'styled-components';
|
|
|
2
2
|
import { Color, FontSize, Shadow, ShapeRadius } from '@pushwoosh/kit-constants';
|
|
3
3
|
import { Horizontal } from '@pushwoosh/kit-helpers';
|
|
4
4
|
import { DEFAULT_MAX_WIDTH } from './constants';
|
|
5
|
-
const clearBox = css(["color:", ";background-color:", ";border:1px solid ", ";box-shadow:", ";"], Color.MAIN, Color.CLEAR, Color.FORM, Shadow.
|
|
5
|
+
const clearBox = css(["padding:16px;color:", ";background-color:", ";border:1px solid ", ";box-shadow:", ";"], Color.MAIN, Color.CLEAR, Color.FORM, Shadow.LARGE);
|
|
6
6
|
export const TooltipBox = styled.div.withConfig({
|
|
7
7
|
displayName: "TooltipBox",
|
|
8
8
|
componentId: "sc-1hariht-0"
|
package/Tooltip/types.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type TooltipColor = 'main' | 'clear';
|
|
|
7
7
|
export type TooltipProps = {
|
|
8
8
|
/** Tooltip content. */
|
|
9
9
|
readonly content: ReactNode;
|
|
10
|
-
/** Background color (default `main`); `clear` is a card on the page background,
|
|
10
|
+
/** Background color (default `main`); `clear` is a card on the page background: 16px padding, border and large shadow. */
|
|
11
11
|
readonly color?: TooltipColor;
|
|
12
12
|
/** Placement relative to the anchor (default `top-start`). */
|
|
13
13
|
readonly position?: TooltipPosition;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pushwoosh/dumb-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "React components to build Pushwoosh products",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.js",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@codemirror/view": "^6.43.11",
|
|
41
41
|
"@floating-ui/react-dom": "^2.1.2",
|
|
42
42
|
"@lezer/highlight": "^1.2.1",
|
|
43
|
-
"@pushwoosh/kit-constants": "^2.
|
|
44
|
-
"@pushwoosh/kit-helpers": "^4.12.
|
|
43
|
+
"@pushwoosh/kit-constants": "^2.1.0",
|
|
44
|
+
"@pushwoosh/kit-helpers": "^4.12.7",
|
|
45
45
|
"@pushwoosh/kit-icons": "^2.3.3",
|
|
46
46
|
"@pushwoosh/kit-typography": "^1.8.5",
|
|
47
47
|
"@tippyjs/react": "^4.2.6",
|