@hyphen/hyphen-components 8.0.1 → 9.0.0-beta.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/dist/css/utilities.css +1 -1
- package/dist/css/utilities.css.map +1 -1
- package/dist/hyphen-components.cjs.development.js +342 -311
- package/dist/hyphen-components.cjs.development.js.map +1 -1
- package/dist/hyphen-components.cjs.production.min.js +2 -2
- package/dist/hyphen-components.cjs.production.min.js.map +1 -1
- package/dist/hyphen-components.esm.js +346 -312
- package/dist/hyphen-components.esm.js.map +1 -1
- package/dist/index.d.ts +212 -202
- package/package.json +6 -5
- package/src/components/Alert/Alert.tsx +5 -6
- package/src/components/Badge/Badge.test.tsx +12 -0
- package/src/components/Badge/Badge.tsx +52 -20
- package/src/components/Box/Box.mdx +1 -1
- package/src/components/Box/Box.stories.tsx +1 -1
- package/src/components/Box/Box.test.tsx +24 -1
- package/src/components/Box/Box.tsx +108 -82
- package/src/components/Card/Card.tsx +5 -1
- package/src/components/Card/components/CardFooter/CardFooter.tsx +0 -4
- package/src/components/Card/components/CardHeader/CardHeader.tsx +4 -1
- package/src/components/Card/components/CardSection/CardSection.tsx +4 -5
- package/src/components/CheckboxInput/CheckboxInput.test.tsx +17 -0
- package/src/components/CheckboxInput/CheckboxInput.tsx +15 -4
- package/src/components/CheckboxInput/components/Checkbox.test.tsx +36 -0
- package/src/components/CheckboxInput/components/Checkbox.tsx +8 -2
- package/src/components/Details/Details.test.tsx +8 -0
- package/src/components/Details/Details.tsx +5 -2
- package/src/components/Details/DetailsSummary.tsx +4 -1
- package/src/components/Drawer/Drawer.test.tsx +8 -0
- package/src/components/Drawer/Drawer.tsx +1 -1
- package/src/components/FormLabel/FormLabel.tsx +6 -3
- package/src/components/Formik/FormikCheckboxInput/FormikCheckboxInput.test.tsx +9 -0
- package/src/components/Formik/FormikCheckboxInput/FormikCheckboxInput.tsx +1 -0
- package/src/components/Formik/FormikSelectInput/FormikSelectInput.tsx +21 -11
- package/src/components/Formik/FormikSelectInputNative/FormikSelectInputNative.tsx +1 -1
- package/src/components/Formik/FormikTimePicker/FormikTimePicker.tsx +1 -1
- package/src/components/Heading/Heading.tsx +5 -6
- package/src/components/Icon/Icon.test.tsx +8 -0
- package/src/components/Icon/Icon.tsx +6 -7
- package/src/components/Modal/Modal.test.tsx +31 -1
- package/src/components/Modal/Modal.tsx +13 -7
- package/src/components/Popover/Popover.test.tsx +3 -4
- package/src/components/RadioGroup/RadioGroup.tsx +11 -6
- package/src/components/RadioGroup/RadioInput/RadioInputIcon.tsx +0 -4
- package/src/components/SelectInput/SelectInput.test.tsx +18 -0
- package/src/components/SelectInput/SelectInput.tsx +47 -27
- package/src/components/SelectInputInset/SelectInputInset.tsx +8 -9
- package/src/components/SelectInputNative/SelectInputNative.test.tsx +24 -0
- package/src/components/SelectInputNative/SelectInputNative.tsx +79 -14
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Table/Table.mdx +1 -1
- package/src/components/Table/Table.stories.tsx +5 -1
- package/src/components/Table/common/TableRow/TableRow.test.tsx +16 -0
- package/src/components/Table/common/TableRow/TableRow.tsx +19 -1
- package/src/components/TextInput/TextInput.tsx +10 -8
- package/src/components/TextInputInset/TextInputInset.tsx +5 -6
- package/src/components/TextareaInput/TextareaInput.tsx +4 -5
- package/src/components/TextareaInputInset/TextareaInputInset.tsx +10 -17
- package/src/components/Toast/Toast.stories.tsx +5 -1
- package/src/types/index.ts +2 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyphen/hyphen-components",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0-beta.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "@hyphen"
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"react-select": "^5.10.0",
|
|
57
57
|
"react-select-event": "^5.5.1",
|
|
58
58
|
"uuid": "^11.1.1",
|
|
59
|
-
"@hyphen/hyphen-design-tokens": "^
|
|
59
|
+
"@hyphen/hyphen-design-tokens": "^9.0.0-beta.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@babel/core": "^7.27.4",
|
|
@@ -129,12 +129,13 @@
|
|
|
129
129
|
"build-storybook": "storybook build",
|
|
130
130
|
"build-storybook-docs": "storybook build --docs",
|
|
131
131
|
"storybook-docs": "storybook dev --docs",
|
|
132
|
-
"lint": "eslint src --ext .ts,.tsx",
|
|
133
|
-
"lint-fix": "eslint src --ext .ts,.tsx --fix",
|
|
132
|
+
"lint": "eslint src type-tests --ext .ts,.tsx",
|
|
133
|
+
"lint-fix": "eslint src type-tests --ext .ts,.tsx --fix",
|
|
134
134
|
"size": "size-limit",
|
|
135
135
|
"start": "tsup --watch",
|
|
136
136
|
"storybook": "storybook dev -p 6006",
|
|
137
|
-
"test": "jest --passWithNoTests",
|
|
137
|
+
"test": "pnpm test:types && jest --passWithNoTests",
|
|
138
|
+
"test:types": "tsc --project tsconfig.type-tests.json",
|
|
138
139
|
"test-watch": "jest --coverage --watch",
|
|
139
140
|
"chromatic": "chromatic --only-changed"
|
|
140
141
|
}
|
|
@@ -8,13 +8,13 @@ import React, {
|
|
|
8
8
|
memo,
|
|
9
9
|
} from 'react';
|
|
10
10
|
import classNames from 'classnames';
|
|
11
|
-
import { Box } from '../Box/Box';
|
|
11
|
+
import { Box, BoxProps } from '../Box/Box';
|
|
12
12
|
import { Icon } from '../Icon/Icon';
|
|
13
13
|
import styles from './Alert.module.scss';
|
|
14
14
|
import { AlertVariant } from './Alert.types';
|
|
15
15
|
import { ALERT_ICONS_MAP } from './Alert.constants';
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
interface AlertOwnProps {
|
|
18
18
|
/**
|
|
19
19
|
* The alert's contents.
|
|
20
20
|
*/
|
|
@@ -50,12 +50,11 @@ export interface AlertProps {
|
|
|
50
50
|
* The type/color of the alert to show.
|
|
51
51
|
*/
|
|
52
52
|
variant?: AlertVariant;
|
|
53
|
-
/**
|
|
54
|
-
* Additional props to be spread to rendered element
|
|
55
|
-
*/
|
|
56
|
-
[x: string]: any; // eslint-disable-line
|
|
57
53
|
}
|
|
58
54
|
|
|
55
|
+
export type AlertProps = AlertOwnProps &
|
|
56
|
+
Omit<BoxProps<'div'>, keyof AlertOwnProps | 'as'>;
|
|
57
|
+
|
|
59
58
|
const AlertComponent: FC<AlertProps> = ({
|
|
60
59
|
children,
|
|
61
60
|
className = '',
|
|
@@ -48,6 +48,18 @@ const getBadge = (text: string): HTMLElement =>
|
|
|
48
48
|
screen.getByText(text).closest('.badge') as HTMLElement;
|
|
49
49
|
|
|
50
50
|
describe('Badge', () => {
|
|
51
|
+
test('accepts attributes and refs for the element selected by as', () => {
|
|
52
|
+
const buttonRef = React.createRef<HTMLButtonElement>();
|
|
53
|
+
|
|
54
|
+
render(
|
|
55
|
+
<Badge as="button" type="button" disabled ref={buttonRef}>
|
|
56
|
+
Action
|
|
57
|
+
</Badge>
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(buttonRef.current).toBeDisabled();
|
|
61
|
+
});
|
|
62
|
+
|
|
51
63
|
test('Badge correctly renders with base props', () => {
|
|
52
64
|
render(<Badge>hello</Badge>);
|
|
53
65
|
const badge = getBadge('hello');
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
Children,
|
|
3
|
+
ReactElement,
|
|
4
|
+
ReactNode,
|
|
5
|
+
forwardRef,
|
|
6
|
+
} from 'react';
|
|
2
7
|
import classNames from 'classnames';
|
|
3
8
|
import { ResponsiveProp } from '../../types';
|
|
4
9
|
import { generateResponsiveClasses } from '../../lib/generateResponsiveClasses';
|
|
5
10
|
import styles from './Badge.module.scss';
|
|
6
|
-
import { Box, BoxProps } from '../Box/Box';
|
|
11
|
+
import { Box, BoxElement, BoxProps, BoxRef } from '../Box/Box';
|
|
7
12
|
|
|
8
13
|
export type BadgeSize = 'sm' | 'md' | 'lg';
|
|
9
14
|
|
|
@@ -50,7 +55,7 @@ const renderBadgeChildren = (children: ReactNode) =>
|
|
|
50
55
|
)
|
|
51
56
|
);
|
|
52
57
|
|
|
53
|
-
|
|
58
|
+
interface BadgeOwnProps {
|
|
54
59
|
/**
|
|
55
60
|
* The color of the badge. Accepts a hue, or one of the semantic names
|
|
56
61
|
* (`danger`, `success`, `warning`, `info`) which map onto `red`, `green`, `yellow` and `blue`.
|
|
@@ -70,9 +75,22 @@ export interface BadgeProps extends Omit<BoxProps, 'color' | 'radius'> {
|
|
|
70
75
|
variant?: BadgeVariant;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
export
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
export type BadgeProps<T extends BoxElement = 'div'> = BadgeOwnProps &
|
|
79
|
+
Omit<BoxProps<T>, keyof BadgeOwnProps>;
|
|
80
|
+
|
|
81
|
+
type BadgeComponent = {
|
|
82
|
+
<T extends BoxElement>(
|
|
83
|
+
props: BadgeProps<T> & { as: T; ref?: BoxRef<T> }
|
|
84
|
+
): ReactElement | null;
|
|
85
|
+
(props: BadgeProps<'div'> & { ref?: BoxRef<'div'> }): ReactElement | null;
|
|
86
|
+
displayName?: string;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const BadgeBaseComponent = <T extends BoxElement = 'div'>(
|
|
90
|
+
props: BadgeProps<T>,
|
|
91
|
+
ref: BoxRef<T>
|
|
92
|
+
) => {
|
|
93
|
+
const {
|
|
76
94
|
className = '',
|
|
77
95
|
color = 'grey',
|
|
78
96
|
radius = 'full',
|
|
@@ -80,9 +98,7 @@ export const Badge = forwardRef<HTMLDivElement, BadgeProps>(
|
|
|
80
98
|
size = 'md',
|
|
81
99
|
children,
|
|
82
100
|
...restProps
|
|
83
|
-
}
|
|
84
|
-
ref
|
|
85
|
-
) => {
|
|
101
|
+
} = props as BadgeOwnProps & Omit<BoxProps<T>, keyof BadgeOwnProps>;
|
|
86
102
|
const responsiveClasses = generateResponsiveClasses('size', size).map(
|
|
87
103
|
(c) => styles[c]
|
|
88
104
|
);
|
|
@@ -98,19 +114,35 @@ export const Badge = forwardRef<HTMLDivElement, BadgeProps>(
|
|
|
98
114
|
styles[`radius-${radius}`]
|
|
99
115
|
);
|
|
100
116
|
|
|
117
|
+
const boxProps = {
|
|
118
|
+
className: badgeClasses,
|
|
119
|
+
display: 'inline-flex',
|
|
120
|
+
alignItems: 'center',
|
|
121
|
+
direction: 'row',
|
|
122
|
+
...restProps,
|
|
123
|
+
} as BoxProps<T>;
|
|
124
|
+
|
|
125
|
+
const badgeChildren = renderBadgeChildren(children);
|
|
126
|
+
|
|
127
|
+
if (boxProps.as) {
|
|
128
|
+
const boxPropsWithAs = boxProps as BoxProps<T> & { as: T };
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<Box<T> ref={ref} {...boxPropsWithAs}>
|
|
132
|
+
{badgeChildren}
|
|
133
|
+
</Box>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
101
137
|
return (
|
|
102
|
-
<Box
|
|
103
|
-
|
|
104
|
-
className={badgeClasses}
|
|
105
|
-
display="inline-flex"
|
|
106
|
-
alignItems="center"
|
|
107
|
-
direction="row"
|
|
108
|
-
{...restProps}
|
|
109
|
-
>
|
|
110
|
-
{renderBadgeChildren(children)}
|
|
138
|
+
<Box ref={ref as BoxRef<'div'>} {...(boxProps as BoxProps<'div'>)}>
|
|
139
|
+
{badgeChildren}
|
|
111
140
|
</Box>
|
|
112
141
|
);
|
|
113
|
-
|
|
114
|
-
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// React.forwardRef cannot preserve a generic `as` parameter, so restore the
|
|
145
|
+
// polymorphic call signature after wrapping the implementation.
|
|
146
|
+
export const Badge = forwardRef(BadgeBaseComponent as never) as BadgeComponent;
|
|
115
147
|
|
|
116
148
|
Badge.displayName = 'Badge';
|
|
@@ -9,7 +9,7 @@ import * as Stories from './Box.stories';
|
|
|
9
9
|
A `<Box>` is a layout component to build UIs with consistent padding and spacing between elements.
|
|
10
10
|
|
|
11
11
|
- Its content is arranged in a specified `direction`, with 'column' being the default
|
|
12
|
-
- Renders a `<div />` element by default, but can be changed using `as`
|
|
12
|
+
- Renders a `<div />` element by default, but can be changed using `as`. The element is never inferred from other props, so links must set `as="a"` alongside `href`
|
|
13
13
|
- Allows you to specify the spacing between child elements using `gap`
|
|
14
14
|
- Many props accept `ResponsiveProp` that take an object with keys that correspond to [breakpoint tokens](?path=/docs/foundation-design-tokens--docs#breakpoints).
|
|
15
15
|
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
CssOverflowValue,
|
|
5
5
|
ResponsiveProp,
|
|
6
6
|
} from '../../types';
|
|
7
|
-
import { Box } from './Box';
|
|
7
|
+
import { Box, boxPropsKeys } from './Box';
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { fireEvent, render } from '@testing-library/react';
|
|
10
10
|
import {
|
|
@@ -20,6 +20,18 @@ import {
|
|
|
20
20
|
describe('Box', () => {
|
|
21
21
|
const renderBox = (props = {}) => render(<Box {...props}>Test Box</Box>);
|
|
22
22
|
|
|
23
|
+
test('accepts attributes for the element selected by as', () => {
|
|
24
|
+
const buttonRef = React.createRef<HTMLButtonElement>();
|
|
25
|
+
|
|
26
|
+
render(
|
|
27
|
+
<Box as="button" type="button" disabled ref={buttonRef}>
|
|
28
|
+
Action
|
|
29
|
+
</Box>
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
expect(buttonRef.current).toBeDisabled();
|
|
33
|
+
});
|
|
34
|
+
|
|
23
35
|
describe('aria attributes', () => {
|
|
24
36
|
test('aria-label is applied if set', () => {
|
|
25
37
|
const { getByLabelText } = renderBox({ 'aria-label': 'test label' });
|
|
@@ -54,6 +66,17 @@ describe('Box', () => {
|
|
|
54
66
|
expect(getByText('Test Box')).toHaveClass('hover:background-color-primary');
|
|
55
67
|
});
|
|
56
68
|
|
|
69
|
+
test('renders hover classes that are not supported by focus', () => {
|
|
70
|
+
const { getByText } = renderBox({ hover: { fontSize: 'lg' } });
|
|
71
|
+
expect(getByText('Test Box')).toHaveClass('hover:font-size-lg');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('lists all text wrapping props as Box props', () => {
|
|
75
|
+
expect(boxPropsKeys).toEqual(
|
|
76
|
+
expect.arrayContaining(['whiteSpace', 'wordBreak'])
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
57
80
|
test('renders with proper focus classes', () => {
|
|
58
81
|
const { getByText } = renderBox({ focus: { borderColor: 'primary' } });
|
|
59
82
|
expect(getByText('Test Box')).toHaveClass('focus:border-color-primary');
|
|
@@ -31,9 +31,11 @@ import {
|
|
|
31
31
|
TextTransform,
|
|
32
32
|
} from '../../types';
|
|
33
33
|
import {
|
|
34
|
+
ComponentPropsWithoutRef,
|
|
35
|
+
ComponentPropsWithRef,
|
|
34
36
|
CSSProperties,
|
|
35
37
|
Children,
|
|
36
|
-
|
|
38
|
+
ElementType,
|
|
37
39
|
ReactElement,
|
|
38
40
|
ReactNode,
|
|
39
41
|
cloneElement,
|
|
@@ -41,12 +43,10 @@ import {
|
|
|
41
43
|
forwardRef,
|
|
42
44
|
} from 'react';
|
|
43
45
|
|
|
44
|
-
import { KnownKeys } from '../../types/lib.types';
|
|
45
46
|
import classNames from 'classnames';
|
|
46
47
|
import { cssShorthandToClasses } from '../../lib/cssShorthandToClasses';
|
|
47
48
|
import { generateResponsiveClasses } from '../../lib/generateResponsiveClasses';
|
|
48
49
|
import { getDimensionCss } from '../../lib/getDimensionCss';
|
|
49
|
-
import { getElementType } from '../../lib/getElementType';
|
|
50
50
|
import styles from './Box.module.scss';
|
|
51
51
|
|
|
52
52
|
const AUTO_FONT_COLOR_BACKGROUNDS: BackgroundColor[] = [
|
|
@@ -61,11 +61,7 @@ export type HoverableBoxProperties =
|
|
|
61
61
|
| 'borderColor'
|
|
62
62
|
| 'shadow'
|
|
63
63
|
| 'background';
|
|
64
|
-
export interface
|
|
65
|
-
/**
|
|
66
|
-
* The element type to be rendered.
|
|
67
|
-
*/
|
|
68
|
-
as?: string;
|
|
64
|
+
export interface BoxOwnProps {
|
|
69
65
|
/**
|
|
70
66
|
* How to align the contents along the cross axis.
|
|
71
67
|
*/
|
|
@@ -146,11 +142,11 @@ export interface BoxProps {
|
|
|
146
142
|
* `* shadow`
|
|
147
143
|
*/
|
|
148
144
|
focus?: {
|
|
149
|
-
background?:
|
|
150
|
-
borderColor?:
|
|
151
|
-
borderWidth?:
|
|
152
|
-
color?:
|
|
153
|
-
shadow?:
|
|
145
|
+
background?: BoxOwnProps['background'];
|
|
146
|
+
borderColor?: BoxOwnProps['borderColor'];
|
|
147
|
+
borderWidth?: BoxOwnProps['borderWidth'];
|
|
148
|
+
color?: BoxOwnProps['color'];
|
|
149
|
+
shadow?: BoxOwnProps['shadow'];
|
|
154
150
|
};
|
|
155
151
|
/**
|
|
156
152
|
* The [font family token](/?path=/docs/foundation-design-tokens--docs#font-family) identifier for the Box's text
|
|
@@ -179,12 +175,12 @@ export interface BoxProps {
|
|
|
179
175
|
* `* shadow`
|
|
180
176
|
*/
|
|
181
177
|
hover?: {
|
|
182
|
-
background?:
|
|
183
|
-
borderColor?:
|
|
184
|
-
borderWidth?:
|
|
185
|
-
color?:
|
|
186
|
-
fontSize?:
|
|
187
|
-
shadow?:
|
|
178
|
+
background?: BoxOwnProps['background'];
|
|
179
|
+
borderColor?: BoxOwnProps['borderColor'];
|
|
180
|
+
borderWidth?: BoxOwnProps['borderWidth'];
|
|
181
|
+
color?: BoxOwnProps['color'];
|
|
182
|
+
fontSize?: BoxOwnProps['fontSize'];
|
|
183
|
+
shadow?: BoxOwnProps['shadow'];
|
|
188
184
|
};
|
|
189
185
|
/**
|
|
190
186
|
* Sets the gaps (gutters) between rows and columns.
|
|
@@ -294,20 +290,41 @@ export interface BoxProps {
|
|
|
294
290
|
* Can be responsive.
|
|
295
291
|
*/
|
|
296
292
|
zIndex?: ZIndexSize | ResponsiveProp<ZIndexSize>;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export type BoxElement = ElementType;
|
|
296
|
+
|
|
297
|
+
export type BoxProps<T extends BoxElement = 'div'> = BoxOwnProps & {
|
|
297
298
|
/**
|
|
298
|
-
*
|
|
299
|
+
* The element type to be rendered. Defaults to `div`.
|
|
300
|
+
*
|
|
301
|
+
* The element is no longer inferred from other props: passing `href` alone
|
|
302
|
+
* renders a `div` with an inert `href` attribute rather than an anchor, so
|
|
303
|
+
* links must set `as="a"` explicitly.
|
|
299
304
|
*/
|
|
300
|
-
|
|
301
|
-
}
|
|
305
|
+
as?: T;
|
|
306
|
+
} & Omit<ComponentPropsWithoutRef<T>, keyof BoxOwnProps | 'as'>;
|
|
307
|
+
|
|
308
|
+
export type BoxRef<T extends BoxElement> = ComponentPropsWithRef<T>['ref'];
|
|
309
|
+
|
|
310
|
+
type BoxComponent = {
|
|
311
|
+
<T extends BoxElement>(
|
|
312
|
+
props: BoxProps<T> & { as: T; ref?: BoxRef<T> }
|
|
313
|
+
): ReactElement | null;
|
|
314
|
+
(props: BoxProps<'div'> & { ref?: BoxRef<'div'> }): ReactElement | null;
|
|
315
|
+
displayName?: string;
|
|
316
|
+
};
|
|
302
317
|
|
|
303
318
|
/**
|
|
304
319
|
* A `<Box>` is a layout component to build UIs with consistent padding and spacing between
|
|
305
320
|
* elements.
|
|
306
321
|
*/
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
322
|
+
const BoxBaseComponent = <T extends BoxElement = 'div'>(
|
|
323
|
+
props: BoxProps<T>,
|
|
324
|
+
ref: BoxRef<T>
|
|
325
|
+
) => {
|
|
326
|
+
const {
|
|
327
|
+
as,
|
|
311
328
|
alignItems = undefined,
|
|
312
329
|
alignContent = undefined,
|
|
313
330
|
alignSelf = undefined,
|
|
@@ -352,9 +369,7 @@ export const Box: FC<BoxProps> = forwardRef(
|
|
|
352
369
|
wordBreak = undefined,
|
|
353
370
|
zIndex = undefined,
|
|
354
371
|
...restProps
|
|
355
|
-
}
|
|
356
|
-
ref
|
|
357
|
-
) => {
|
|
372
|
+
} = props as BoxOwnProps & { as?: T };
|
|
358
373
|
const heightCss = getDimensionCss('h', height);
|
|
359
374
|
const widthCss = getDimensionCss('w', width);
|
|
360
375
|
const maxHeightCss = getDimensionCss('mh', maxHeight);
|
|
@@ -369,7 +384,7 @@ export const Box: FC<BoxProps> = forwardRef(
|
|
|
369
384
|
color ??
|
|
370
385
|
(background === 'inverse'
|
|
371
386
|
? 'inverse'
|
|
372
|
-
: AUTO_FONT_COLOR_BACKGROUNDS.includes(background)
|
|
387
|
+
: background && AUTO_FONT_COLOR_BACKGROUNDS.includes(background)
|
|
373
388
|
? 'grey'
|
|
374
389
|
: undefined);
|
|
375
390
|
|
|
@@ -411,16 +426,13 @@ export const Box: FC<BoxProps> = forwardRef(
|
|
|
411
426
|
|
|
412
427
|
const getStatefulClasses = (
|
|
413
428
|
stateKey: 'hover' | 'focus',
|
|
414
|
-
values:
|
|
429
|
+
values: BoxOwnProps['hover' | 'focus']
|
|
415
430
|
) =>
|
|
416
431
|
values // eslint-disable-line
|
|
417
432
|
? Object.entries(values).map(
|
|
418
433
|
([key, value]) =>
|
|
419
434
|
cssPropertyMap[key].transformer(
|
|
420
|
-
`${stateKey}:${
|
|
421
|
-
cssPropertyMap[key as keyof BoxProps['focus' | 'hover']]
|
|
422
|
-
.classPrefix
|
|
423
|
-
}`,
|
|
435
|
+
`${stateKey}:${cssPropertyMap[key].classPrefix}`,
|
|
424
436
|
value
|
|
425
437
|
) // eslint-disable-line max-len
|
|
426
438
|
)
|
|
@@ -629,7 +641,7 @@ export const Box: FC<BoxProps> = forwardRef(
|
|
|
629
641
|
);
|
|
630
642
|
}
|
|
631
643
|
|
|
632
|
-
const element =
|
|
644
|
+
const element = as ?? 'div';
|
|
633
645
|
|
|
634
646
|
return createElement(
|
|
635
647
|
element,
|
|
@@ -641,52 +653,66 @@ export const Box: FC<BoxProps> = forwardRef(
|
|
|
641
653
|
},
|
|
642
654
|
children !== null && children !== undefined ? decoratedChildren : null
|
|
643
655
|
);
|
|
644
|
-
|
|
645
|
-
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
// React.forwardRef cannot preserve a generic `as` parameter, so restore the
|
|
659
|
+
// polymorphic call signature after wrapping the implementation.
|
|
660
|
+
export const Box = forwardRef(BoxBaseComponent as never) as BoxComponent;
|
|
646
661
|
|
|
647
662
|
Box.displayName = 'Box';
|
|
648
663
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
664
|
+
// `boxPropsKeys` drives runtime prop routing (see SelectInputNative), so a key
|
|
665
|
+
// missing from the list silently forwards a Box prop to the rendered element.
|
|
666
|
+
// `Record` requires an entry for every `BoxOwnProps` key, so omitting one here
|
|
667
|
+
// fails to compile.
|
|
668
|
+
const boxPropsKeyMap: Record<keyof BoxOwnProps | 'as', true> = {
|
|
669
|
+
as: true,
|
|
670
|
+
alignItems: true,
|
|
671
|
+
alignContent: true,
|
|
672
|
+
alignSelf: true,
|
|
673
|
+
background: true,
|
|
674
|
+
borderColor: true,
|
|
675
|
+
borderWidth: true,
|
|
676
|
+
className: true,
|
|
677
|
+
childGap: true,
|
|
678
|
+
children: true,
|
|
679
|
+
color: true,
|
|
680
|
+
columnGap: true,
|
|
681
|
+
cursor: true,
|
|
682
|
+
direction: true,
|
|
683
|
+
display: true,
|
|
684
|
+
flex: true,
|
|
685
|
+
focus: true,
|
|
686
|
+
fontFamily: true,
|
|
687
|
+
fontSize: true,
|
|
688
|
+
fontWeight: true,
|
|
689
|
+
gap: true,
|
|
690
|
+
height: true,
|
|
691
|
+
hover: true,
|
|
692
|
+
justifyContent: true,
|
|
693
|
+
margin: true,
|
|
694
|
+
maxHeight: true,
|
|
695
|
+
minHeight: true,
|
|
696
|
+
maxWidth: true,
|
|
697
|
+
minWidth: true,
|
|
698
|
+
overflow: true,
|
|
699
|
+
padding: true,
|
|
700
|
+
position: true,
|
|
701
|
+
radius: true,
|
|
702
|
+
rowGap: true,
|
|
703
|
+
shadow: true,
|
|
704
|
+
style: true,
|
|
705
|
+
textAlign: true,
|
|
706
|
+
textTransform: true,
|
|
707
|
+
textWrap: true,
|
|
708
|
+
whiteSpace: true,
|
|
709
|
+
wrap: true,
|
|
710
|
+
width: true,
|
|
711
|
+
wordBreak: true,
|
|
712
|
+
zIndex: true,
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
export const boxPropsKeys = Object.keys(boxPropsKeyMap) as (
|
|
716
|
+
| keyof BoxOwnProps
|
|
717
|
+
| 'as'
|
|
718
|
+
)[];
|
|
@@ -7,9 +7,13 @@ export interface CardProps extends BoxProps {
|
|
|
7
7
|
* The Card's contents.
|
|
8
8
|
*/
|
|
9
9
|
children?: ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Whether the card uses its subdued background.
|
|
12
|
+
*/
|
|
13
|
+
subdued?: boolean;
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
export const CardBaseComponent
|
|
16
|
+
export const CardBaseComponent = React.forwardRef<HTMLDivElement, CardProps>(
|
|
13
17
|
(
|
|
14
18
|
{
|
|
15
19
|
children,
|
|
@@ -5,10 +5,6 @@ export interface CardFooterProps extends BoxProps {
|
|
|
5
5
|
* Contents of the Footer.
|
|
6
6
|
*/
|
|
7
7
|
children?: ReactNode;
|
|
8
|
-
/**
|
|
9
|
-
* Additional props to be spread to rendered element
|
|
10
|
-
*/
|
|
11
|
-
[x: string]: any; // eslint-disable-line
|
|
12
8
|
}
|
|
13
9
|
|
|
14
10
|
export const CardFooter: FC<CardFooterProps> = ({
|
|
@@ -2,7 +2,7 @@ import React, { FC, ReactNode } from 'react';
|
|
|
2
2
|
import { Box, BoxProps } from '../../../Box/Box';
|
|
3
3
|
import { Heading } from '../../../Heading/Heading';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
interface CardHeaderOwnProps {
|
|
6
6
|
/**
|
|
7
7
|
* The title of the card
|
|
8
8
|
*/
|
|
@@ -13,6 +13,9 @@ export interface CardHeaderProps extends BoxProps {
|
|
|
13
13
|
description?: ReactNode;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export type CardHeaderProps = CardHeaderOwnProps &
|
|
17
|
+
Omit<BoxProps<'div'>, keyof CardHeaderOwnProps | 'as'>;
|
|
18
|
+
|
|
16
19
|
export const CardHeader: FC<CardHeaderProps> = ({
|
|
17
20
|
children,
|
|
18
21
|
title,
|
|
@@ -4,7 +4,7 @@ import React, { FC, ReactNode } from 'react';
|
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import styles from '../../Card.module.scss';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
interface CardSectionOwnProps {
|
|
8
8
|
/**
|
|
9
9
|
* Any valid background color token, or a `url()` for an image
|
|
10
10
|
*/
|
|
@@ -41,12 +41,11 @@ export interface CardSectionProps extends BoxProps {
|
|
|
41
41
|
* Title for the section.
|
|
42
42
|
*/
|
|
43
43
|
title?: ReactNode;
|
|
44
|
-
/**
|
|
45
|
-
* Additional props to be spread to rendered element
|
|
46
|
-
*/
|
|
47
|
-
[x: string]: any; // eslint-disable-line
|
|
48
44
|
}
|
|
49
45
|
|
|
46
|
+
export type CardSectionProps = CardSectionOwnProps &
|
|
47
|
+
Omit<BoxProps<'div'>, keyof CardSectionOwnProps | 'as'>;
|
|
48
|
+
|
|
50
49
|
export const CardSection: FC<CardSectionProps> = ({
|
|
51
50
|
background = undefined,
|
|
52
51
|
borderColor = undefined,
|
|
@@ -108,6 +108,23 @@ describe('CheckboxInput', () => {
|
|
|
108
108
|
expect(checkbox.checked).toEqual(false);
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
+
test.each([0, ''])('forwards the falsy value %p to the input', (value) => {
|
|
112
|
+
render(
|
|
113
|
+
<CheckboxInput
|
|
114
|
+
id="testCheckbox"
|
|
115
|
+
label="test checkbox"
|
|
116
|
+
isChecked={false}
|
|
117
|
+
onChange={() => null}
|
|
118
|
+
value={value}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
expect(screen.getByRole('checkbox')).toHaveAttribute(
|
|
123
|
+
'value',
|
|
124
|
+
String(value)
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
111
128
|
test('assigns the "aria-labelledby" attribute and calls FormLabel with expected props', () => {
|
|
112
129
|
const { getByLabelText } = render(
|
|
113
130
|
<CheckboxInput
|