@primer/components 32.0.1-rc.44e3df9b → 32.1.0-rc.6f5d2b00

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/browser.esm.js +7 -1
  3. package/dist/browser.esm.js.map +1 -1
  4. package/dist/browser.umd.js +7 -1
  5. package/dist/browser.umd.js.map +1 -1
  6. package/docs/content/Checkbox.md +118 -0
  7. package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +2 -0
  8. package/lib/Checkbox.d.ts +29 -0
  9. package/lib/Checkbox.js +64 -0
  10. package/lib/Overlay.d.ts +5 -3
  11. package/lib/__tests__/Checkbox.test.d.ts +2 -0
  12. package/lib/__tests__/Checkbox.test.js +189 -0
  13. package/lib/__tests__/Overlay.types.test.d.ts +3 -0
  14. package/lib/__tests__/Overlay.types.test.js +38 -0
  15. package/lib/__tests__/SelectPanel.types.test.d.ts +3 -0
  16. package/lib/__tests__/SelectPanel.types.test.js +44 -0
  17. package/lib/index.d.ts +2 -0
  18. package/lib/index.js +8 -0
  19. package/lib/stories/Checkbox.stories.js +227 -0
  20. package/lib-esm/Checkbox.d.ts +29 -0
  21. package/lib-esm/Checkbox.js +44 -0
  22. package/lib-esm/Overlay.d.ts +5 -3
  23. package/lib-esm/__tests__/Checkbox.test.d.ts +2 -0
  24. package/lib-esm/__tests__/Checkbox.test.js +169 -0
  25. package/lib-esm/__tests__/Overlay.types.test.d.ts +3 -0
  26. package/lib-esm/__tests__/Overlay.types.test.js +29 -0
  27. package/lib-esm/__tests__/SelectPanel.types.test.d.ts +3 -0
  28. package/lib-esm/__tests__/SelectPanel.types.test.js +29 -0
  29. package/lib-esm/index.d.ts +2 -0
  30. package/lib-esm/index.js +1 -0
  31. package/lib-esm/stories/Checkbox.stories.js +197 -0
  32. package/package.json +1 -1
  33. package/src/Checkbox.tsx +75 -0
  34. package/src/Overlay.tsx +7 -4
  35. package/src/__tests__/Checkbox.test.tsx +155 -0
  36. package/src/__tests__/Overlay.types.test.tsx +15 -0
  37. package/src/__tests__/SelectPanel.types.test.tsx +31 -0
  38. package/src/__tests__/__snapshots__/Checkbox.test.tsx.snap +16 -0
  39. package/src/index.ts +3 -0
  40. package/src/stories/Checkbox.stories.tsx +164 -0
  41. package/stats.html +1 -1
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Indeterminate = exports.Uncontrolled = exports.Default = exports.default = void 0;
7
+
8
+ var _react = _interopRequireWildcard(require("react"));
9
+
10
+ var _styledComponents = _interopRequireDefault(require("styled-components"));
11
+
12
+ var _2 = require("..");
13
+
14
+ var _addonActions = require("@storybook/addon-actions");
15
+
16
+ var _constants = require("../constants");
17
+
18
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
+
20
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
21
+
22
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
23
+
24
+ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
25
+
26
+ var _default = {
27
+ title: 'Forms/Checkbox',
28
+ component: _2.Checkbox,
29
+ decorators: [Story => {
30
+ return /*#__PURE__*/_react.default.createElement(_2.ThemeProvider, null, /*#__PURE__*/_react.default.createElement(_2.BaseStyles, null, /*#__PURE__*/_react.default.createElement(_2.Box, {
31
+ paddingTop: 5
32
+ }, Story())));
33
+ }],
34
+ argTypes: {
35
+ sx: {
36
+ table: {
37
+ disable: true
38
+ }
39
+ },
40
+ disabled: {
41
+ name: 'Disabled',
42
+ defaultValue: false,
43
+ control: {
44
+ type: 'boolean'
45
+ }
46
+ }
47
+ }
48
+ };
49
+ exports.default = _default;
50
+
51
+ const StyledLabel = _styledComponents.default.label.withConfig({
52
+ displayName: "Checkboxstories__StyledLabel",
53
+ componentId: "sdupvr-0"
54
+ })(["user-select:none;font-weight:600;font-size:14px;line-height:18px;margin-left:16px;", ""], _constants.COMMON);
55
+
56
+ const StyledSubLabel = (0, _styledComponents.default)(_2.Text).withConfig({
57
+ displayName: "Checkboxstories__StyledSubLabel",
58
+ componentId: "sdupvr-1"
59
+ })(["color:", ";font-size:13px;", ""], (0, _constants.get)('colors.fg.muted'), _constants.COMMON);
60
+
61
+ const Default = args => {
62
+ const [isChecked, setChecked] = (0, _react.useState)(false);
63
+
64
+ const handleChange = event => {
65
+ setChecked(event.target.checked);
66
+ (0, _addonActions.action)('Change event triggered');
67
+ };
68
+
69
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_2.Box, {
70
+ as: "form",
71
+ sx: {
72
+ p: 3,
73
+ display: 'flex',
74
+ alignItems: 'flex-start'
75
+ }
76
+ }, /*#__PURE__*/_react.default.createElement(_2.Checkbox, _extends({
77
+ id: "controlled-checkbox",
78
+ onChange: handleChange,
79
+ checked: isChecked
80
+ }, args)), /*#__PURE__*/_react.default.createElement(StyledLabel, {
81
+ htmlFor: "controlled-checkbox"
82
+ }, /*#__PURE__*/_react.default.createElement(_2.Text, {
83
+ sx: {
84
+ display: 'block'
85
+ }
86
+ }, "Default checkbox"), /*#__PURE__*/_react.default.createElement(StyledSubLabel, null, "controlled"))), /*#__PURE__*/_react.default.createElement(_2.Box, {
87
+ as: "form",
88
+ sx: {
89
+ p: 3,
90
+ display: 'flex',
91
+ alignItems: 'flex-start'
92
+ }
93
+ }, /*#__PURE__*/_react.default.createElement(_2.Checkbox, _extends({
94
+ id: "always-checked-checkbox",
95
+ checked: true
96
+ }, args)), /*#__PURE__*/_react.default.createElement(StyledLabel, {
97
+ htmlFor: "always-checked-checkbox"
98
+ }, /*#__PURE__*/_react.default.createElement(_2.Text, {
99
+ sx: {
100
+ display: 'block'
101
+ }
102
+ }, "Always checked"), /*#__PURE__*/_react.default.createElement(StyledSubLabel, null, "checked=\"true\""))), /*#__PURE__*/_react.default.createElement(_2.Box, {
103
+ as: "form",
104
+ sx: {
105
+ p: 3,
106
+ display: 'flex',
107
+ alignItems: 'flex-start'
108
+ }
109
+ }, /*#__PURE__*/_react.default.createElement(_2.Checkbox, _extends({
110
+ id: "always-unchecked-checkbox",
111
+ checked: false
112
+ }, args)), /*#__PURE__*/_react.default.createElement(StyledLabel, {
113
+ htmlFor: "always-unchecked-checkbox"
114
+ }, /*#__PURE__*/_react.default.createElement(_2.Text, {
115
+ sx: {
116
+ display: 'block'
117
+ }
118
+ }, "Always unchecked"), /*#__PURE__*/_react.default.createElement(StyledSubLabel, null, "checked=\"false\""))), /*#__PURE__*/_react.default.createElement(_2.Box, {
119
+ as: "form",
120
+ sx: {
121
+ p: 3,
122
+ display: 'flex',
123
+ alignItems: 'flex-start'
124
+ }
125
+ }, /*#__PURE__*/_react.default.createElement(_2.Checkbox, {
126
+ id: "disabled-checkbox",
127
+ disabled: true,
128
+ checked: false
129
+ }), /*#__PURE__*/_react.default.createElement(StyledLabel, {
130
+ htmlFor: "disabled-checkbox"
131
+ }, /*#__PURE__*/_react.default.createElement(_2.Text, {
132
+ sx: {
133
+ display: 'block'
134
+ }
135
+ }, "Inactive"), /*#__PURE__*/_react.default.createElement(StyledSubLabel, null, "disabled=\"true\""))));
136
+ };
137
+
138
+ exports.Default = Default;
139
+
140
+ const Uncontrolled = args => {
141
+ const checkboxRef = (0, _react.useRef)(null);
142
+ (0, _react.useLayoutEffect)(() => {
143
+ if (checkboxRef.current) {
144
+ checkboxRef.current.checked = true;
145
+ }
146
+ }, []);
147
+ return /*#__PURE__*/_react.default.createElement(_2.Box, {
148
+ as: "form",
149
+ sx: {
150
+ p: 3,
151
+ display: 'flex',
152
+ alignItems: 'flex-start'
153
+ }
154
+ }, /*#__PURE__*/_react.default.createElement(_2.Checkbox, _extends({
155
+ id: "uncontrolled-checkbox",
156
+ ref: checkboxRef
157
+ }, args)), /*#__PURE__*/_react.default.createElement(StyledLabel, {
158
+ htmlFor: "uncontrolled-checkbox"
159
+ }, /*#__PURE__*/_react.default.createElement(_2.Text, {
160
+ sx: {
161
+ display: 'block'
162
+ }
163
+ }, "Uncontrolled checkbox"), /*#__PURE__*/_react.default.createElement(StyledSubLabel, null, "Checked by default")));
164
+ };
165
+
166
+ exports.Uncontrolled = Uncontrolled;
167
+ Uncontrolled.displayName = "Uncontrolled";
168
+
169
+ const Indeterminate = args => {
170
+ const [checkboxes, setCheckboxes] = (0, _react.useState)([false, false, false, false]);
171
+
172
+ const handleChange = (_, index) => {
173
+ const newCheckboxes = [...checkboxes];
174
+ newCheckboxes[index] = !checkboxes[index];
175
+ setCheckboxes(newCheckboxes);
176
+ };
177
+
178
+ const handleIndeterminateChange = () => {
179
+ if (checkboxes.every(checkbox => checkbox)) {
180
+ return setCheckboxes(checkboxes.map(() => false));
181
+ }
182
+
183
+ const newCheckboxes = checkboxes.map(() => true);
184
+ setCheckboxes(newCheckboxes);
185
+ };
186
+
187
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_2.Box, {
188
+ as: "form",
189
+ sx: {
190
+ p: 3,
191
+ display: 'flex',
192
+ alignItems: 'flex-start'
193
+ }
194
+ }, /*#__PURE__*/_react.default.createElement(_2.Checkbox, {
195
+ id: "indeterminate-checkbox",
196
+ checked: checkboxes.every(Boolean),
197
+ onChange: handleIndeterminateChange,
198
+ indeterminate: !checkboxes.every(Boolean)
199
+ }), /*#__PURE__*/_react.default.createElement(StyledLabel, {
200
+ htmlFor: "controlled-checkbox"
201
+ }, /*#__PURE__*/_react.default.createElement(_2.Text, {
202
+ sx: {
203
+ display: 'block'
204
+ }
205
+ }, "Default checkbox"), /*#__PURE__*/_react.default.createElement(StyledSubLabel, null, "controlled"))), checkboxes.map((field, index) => /*#__PURE__*/_react.default.createElement(_2.Box, {
206
+ key: `sub-checkbox-${index}`,
207
+ as: "form",
208
+ sx: {
209
+ p: 1,
210
+ pl: 7,
211
+ display: 'flex',
212
+ alignItems: 'flex-start'
213
+ }
214
+ }, /*#__PURE__*/_react.default.createElement(_2.Checkbox, _extends({
215
+ id: `sub-checkbox-${index}`,
216
+ checked: checkboxes[index],
217
+ onChange: event => handleChange(event, index)
218
+ }, args)), /*#__PURE__*/_react.default.createElement(StyledLabel, {
219
+ htmlFor: `sub-checkbox-${index}`
220
+ }, /*#__PURE__*/_react.default.createElement(_2.Text, {
221
+ sx: {
222
+ display: 'block'
223
+ }
224
+ }, "Checkbox ", index + 1)))));
225
+ };
226
+
227
+ exports.Indeterminate = Indeterminate;
@@ -0,0 +1,29 @@
1
+ import React, { InputHTMLAttributes } from 'react';
2
+ import { SxProp } from './sx';
3
+ export declare type CheckboxProps = {
4
+ /**
5
+ * Apply indeterminate visual appearance to the checkbox
6
+ */
7
+ indeterminate?: boolean;
8
+ /**
9
+ * Apply inactive visual appearance to the checkbox
10
+ */
11
+ disabled?: boolean;
12
+ /**
13
+ * Forward a ref to the underlying input element
14
+ */
15
+ ref?: React.RefObject<HTMLInputElement>;
16
+ /**
17
+ * Indicates whether the checkbox must be checked
18
+ */
19
+ required?: boolean;
20
+ /**
21
+ * Indicates whether the checkbox validation state
22
+ */
23
+ validationStatus?: 'error' | 'success';
24
+ } & InputHTMLAttributes<HTMLInputElement> & SxProp;
25
+ /**
26
+ * An accessible, native checkbox component
27
+ */
28
+ declare const Checkbox: React.ForwardRefExoticComponent<Pick<CheckboxProps, "sx" | keyof React.InputHTMLAttributes<HTMLInputElement> | "indeterminate" | "validationStatus"> & React.RefAttributes<HTMLInputElement>>;
29
+ export default Checkbox;
@@ -0,0 +1,44 @@
1
+ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
+
3
+ import styled from 'styled-components';
4
+ import { useProvidedRefOrCreate } from './hooks';
5
+ import React, { useLayoutEffect } from 'react';
6
+ import sx from './sx';
7
+ const StyledCheckbox = styled.input.withConfig({
8
+ displayName: "Checkbox__StyledCheckbox",
9
+ componentId: "i51804-0"
10
+ })(["cursor:pointer;", " ", ""], props => props.disabled && `cursor: not-allowed;`, sx);
11
+ /**
12
+ * An accessible, native checkbox component
13
+ */
14
+
15
+ const Checkbox = /*#__PURE__*/React.forwardRef(({
16
+ checked,
17
+ indeterminate,
18
+ disabled,
19
+ sx: sxProp,
20
+ required,
21
+ validationStatus,
22
+ ...rest
23
+ }, ref) => {
24
+ const checkboxRef = useProvidedRefOrCreate(ref);
25
+ useLayoutEffect(() => {
26
+ if (checkboxRef.current) {
27
+ checkboxRef.current.indeterminate = indeterminate || false;
28
+ }
29
+ }, [indeterminate, checked, checkboxRef]);
30
+ return /*#__PURE__*/React.createElement(StyledCheckbox, _extends({
31
+ type: "checkbox",
32
+ disabled: disabled,
33
+ "aria-disabled": disabled ? 'true' : 'false',
34
+ ref: ref || checkboxRef,
35
+ checked: indeterminate ? false : checked,
36
+ "aria-checked": indeterminate ? 'mixed' : checked ? 'true' : 'false',
37
+ sx: sxProp,
38
+ required: required,
39
+ "aria-required": required ? 'true' : 'false',
40
+ "aria-invalid": validationStatus === 'error' ? 'true' : 'false'
41
+ }, rest));
42
+ });
43
+ Checkbox.displayName = 'Checkbox';
44
+ export default Checkbox;
@@ -1,8 +1,9 @@
1
- import React from 'react';
1
+ import React, { ComponentPropsWithRef } from 'react';
2
2
  import { AriaRole, Merge } from './utils/types';
3
3
  import { TouchOrMouseEvent } from './hooks';
4
4
  import { SxProp } from './sx';
5
5
  import { AnchorSide } from './behaviors/anchoredPosition';
6
+ import { ForwardRefComponent as PolymorphicForwardRefComponent } from '@radix-ui/react-polymorphic';
6
7
  declare type StyledOverlayProps = {
7
8
  width?: keyof typeof widthMap;
8
9
  height?: keyof typeof heightMap;
@@ -42,7 +43,7 @@ declare type BaseOverlayProps = {
42
43
  role?: AriaRole;
43
44
  children?: React.ReactNode;
44
45
  };
45
- export declare type OverlayProps = Merge<StyledOverlayProps, BaseOverlayProps>;
46
+ declare type OwnOverlayProps = Merge<StyledOverlayProps, BaseOverlayProps>;
46
47
  /**
47
48
  * An `Overlay` is a flexible floating surface, used to display transient content such as menus,
48
49
  * selection options, dialogs, and more. Overlays use shadows to express elevation. The `Overlay`
@@ -60,5 +61,6 @@ export declare type OverlayProps = Merge<StyledOverlayProps, BaseOverlayProps>;
60
61
  * @param left Optional. Horizontal position of the overlay, relative to its closest positioned ancestor (often its `Portal`).
61
62
  * @param portalContainerName Optional. The name of the portal container to render the Overlay into.
62
63
  */
63
- declare const Overlay: React.ForwardRefExoticComponent<Omit<StyledOverlayProps, keyof BaseOverlayProps> & BaseOverlayProps & React.RefAttributes<HTMLDivElement>>;
64
+ declare const Overlay: PolymorphicForwardRefComponent<"div", OwnOverlayProps>;
65
+ export declare type OverlayProps = ComponentPropsWithRef<typeof Overlay>;
64
66
  export default Overlay;
@@ -0,0 +1,2 @@
1
+ import 'babel-polyfill';
2
+ import '@testing-library/jest-dom';
@@ -0,0 +1,169 @@
1
+ import React from 'react';
2
+ import { Checkbox } from '..';
3
+ import { behavesAsComponent, checkExports } from '../utils/testing';
4
+ import { render, cleanup } from '@testing-library/react';
5
+ import { toHaveNoViolations } from 'jest-axe';
6
+ import 'babel-polyfill';
7
+ import '@testing-library/jest-dom';
8
+ import userEvent from '@testing-library/user-event';
9
+ expect.extend(toHaveNoViolations);
10
+ describe('Checkbox', () => {
11
+ beforeEach(() => {
12
+ jest.resetAllMocks();
13
+ cleanup();
14
+ });
15
+ behavesAsComponent({
16
+ Component: Checkbox
17
+ });
18
+ checkExports('Checkbox', {
19
+ default: Checkbox
20
+ });
21
+ it('renders a valid checkbox input', () => {
22
+ const {
23
+ getByRole
24
+ } = render( /*#__PURE__*/React.createElement(Checkbox, null));
25
+ const checkbox = getByRole('checkbox');
26
+ expect(checkbox).toBeDefined();
27
+ });
28
+ it('renders an unchecked checkbox by default', () => {
29
+ const {
30
+ getByRole
31
+ } = render( /*#__PURE__*/React.createElement(Checkbox, null));
32
+ const checkbox = getByRole('checkbox');
33
+ expect(checkbox.checked).toEqual(false);
34
+ });
35
+ it('renders an active checkbox when checked attribute is passed', () => {
36
+ const handleChange = jest.fn();
37
+ const {
38
+ getByRole
39
+ } = render( /*#__PURE__*/React.createElement(Checkbox, {
40
+ checked: true,
41
+ onChange: handleChange
42
+ }));
43
+ const checkbox = getByRole('checkbox');
44
+ expect(checkbox.checked).toEqual(true);
45
+ });
46
+ it('accepts a change handler that can alter the checkbox state', () => {
47
+ const handleChange = jest.fn();
48
+ const {
49
+ getByRole
50
+ } = render( /*#__PURE__*/React.createElement(Checkbox, {
51
+ onChange: handleChange
52
+ }));
53
+ const checkbox = getByRole('checkbox');
54
+ expect(checkbox.checked).toEqual(false);
55
+ userEvent.click(checkbox);
56
+ expect(handleChange).toHaveBeenCalled();
57
+ expect(checkbox.checked).toEqual(true);
58
+ userEvent.click(checkbox);
59
+ expect(handleChange).toHaveBeenCalled();
60
+ expect(checkbox.checked).toEqual(false);
61
+ });
62
+ it('renders an indeterminate prop correctly', () => {
63
+ const handleChange = jest.fn();
64
+ const {
65
+ getByRole
66
+ } = render( /*#__PURE__*/React.createElement(Checkbox, {
67
+ indeterminate: true,
68
+ checked: true,
69
+ onChange: handleChange
70
+ }));
71
+ const checkbox = getByRole('checkbox');
72
+ expect(checkbox.indeterminate).toEqual(true);
73
+ expect(checkbox.checked).toEqual(false);
74
+ });
75
+ it('renders an inactive checkbox state correctly', () => {
76
+ const handleChange = jest.fn();
77
+ const {
78
+ getByRole,
79
+ rerender
80
+ } = render( /*#__PURE__*/React.createElement(Checkbox, {
81
+ disabled: true,
82
+ onChange: handleChange
83
+ }));
84
+ const checkbox = getByRole('checkbox');
85
+ expect(checkbox.disabled).toEqual(true);
86
+ expect(checkbox.checked).toEqual(false);
87
+ expect(checkbox).toHaveAttribute('aria-disabled', 'true');
88
+ userEvent.click(checkbox);
89
+ expect(checkbox.disabled).toEqual(true);
90
+ expect(checkbox.checked).toEqual(false);
91
+ expect(checkbox).toHaveAttribute('aria-disabled', 'true'); // remove disabled attribute and retest
92
+
93
+ rerender( /*#__PURE__*/React.createElement(Checkbox, {
94
+ onChange: handleChange
95
+ }));
96
+ expect(checkbox).toHaveAttribute('aria-disabled', 'false');
97
+ });
98
+ it('renders an uncontrolled component correctly', () => {
99
+ const {
100
+ getByRole
101
+ } = render( /*#__PURE__*/React.createElement(Checkbox, {
102
+ defaultChecked: true
103
+ }));
104
+ const checkbox = getByRole('checkbox');
105
+ expect(checkbox.checked).toEqual(true);
106
+ userEvent.click(checkbox);
107
+ expect(checkbox.checked).toEqual(false);
108
+ });
109
+ it('renders an aria-checked attribute correctly', () => {
110
+ const handleChange = jest.fn();
111
+ const {
112
+ getByRole,
113
+ rerender
114
+ } = render( /*#__PURE__*/React.createElement(Checkbox, {
115
+ checked: false,
116
+ onChange: handleChange
117
+ }));
118
+ const checkbox = getByRole('checkbox');
119
+ expect(checkbox).toHaveAttribute('aria-checked', 'false');
120
+ rerender( /*#__PURE__*/React.createElement(Checkbox, {
121
+ checked: true,
122
+ onChange: handleChange
123
+ }));
124
+ expect(checkbox).toHaveAttribute('aria-checked', 'true');
125
+ rerender( /*#__PURE__*/React.createElement(Checkbox, {
126
+ indeterminate: true,
127
+ checked: true,
128
+ onChange: handleChange
129
+ }));
130
+ expect(checkbox).toHaveAttribute('aria-checked', 'mixed');
131
+ });
132
+ it('renders an invalid aria state when validation prop indicates an error', () => {
133
+ const handleChange = jest.fn();
134
+ const {
135
+ getByRole,
136
+ rerender
137
+ } = render( /*#__PURE__*/React.createElement(Checkbox, {
138
+ onChange: handleChange
139
+ }));
140
+ const checkbox = getByRole('checkbox');
141
+ expect(checkbox).toHaveAttribute('aria-invalid', 'false');
142
+ rerender( /*#__PURE__*/React.createElement(Checkbox, {
143
+ onChange: handleChange,
144
+ validationStatus: "success"
145
+ }));
146
+ expect(checkbox).toHaveAttribute('aria-invalid', 'false');
147
+ rerender( /*#__PURE__*/React.createElement(Checkbox, {
148
+ onChange: handleChange,
149
+ validationStatus: "error"
150
+ }));
151
+ expect(checkbox).toHaveAttribute('aria-invalid', 'true');
152
+ });
153
+ it('renders an aria state indicating the field is required', () => {
154
+ const handleChange = jest.fn();
155
+ const {
156
+ getByRole,
157
+ rerender
158
+ } = render( /*#__PURE__*/React.createElement(Checkbox, {
159
+ onChange: handleChange
160
+ }));
161
+ const checkbox = getByRole('checkbox');
162
+ expect(checkbox).toHaveAttribute('aria-required', 'false');
163
+ rerender( /*#__PURE__*/React.createElement(Checkbox, {
164
+ onChange: handleChange,
165
+ required: true
166
+ }));
167
+ expect(checkbox).toHaveAttribute('aria-required', 'true');
168
+ });
169
+ });
@@ -1,3 +1,6 @@
1
1
  import React from 'react';
2
2
  export declare function shouldAcceptCallWithNoProps(ref: React.RefObject<HTMLElement>): JSX.Element;
3
+ export declare function shouldAcceptCallWithDOMProps(ref: React.RefObject<HTMLElement>): JSX.Element;
4
+ export declare function shouldNotAcceptCallWithDOMPropsThatDontMatchElement(ref: React.RefObject<HTMLElement>): JSX.Element;
5
+ export declare function shouldAcceptCallWithAsAndDOMProps(ref: React.RefObject<HTMLElement>): JSX.Element;
3
6
  export declare function shouldNotAcceptSystemProps(ref: React.RefObject<HTMLElement>): JSX.Element;
@@ -8,6 +8,35 @@ export function shouldAcceptCallWithNoProps(ref) {
8
8
  });
9
9
  }
10
10
  shouldAcceptCallWithNoProps.displayName = "shouldAcceptCallWithNoProps";
11
+ export function shouldAcceptCallWithDOMProps(ref) {
12
+ return /*#__PURE__*/React.createElement(Overlay, {
13
+ returnFocusRef: ref,
14
+ onClickOutside: () => null,
15
+ onEscape: () => null,
16
+ onMouseDown: () => null
17
+ });
18
+ }
19
+ shouldAcceptCallWithDOMProps.displayName = "shouldAcceptCallWithDOMProps";
20
+ export function shouldNotAcceptCallWithDOMPropsThatDontMatchElement(ref) {
21
+ // @ts-expect-error href should not be allowed on a <div>
22
+ return /*#__PURE__*/React.createElement(Overlay, {
23
+ returnFocusRef: ref,
24
+ onClickOutside: () => null,
25
+ onEscape: () => null,
26
+ href: "//primer.style/"
27
+ });
28
+ }
29
+ shouldNotAcceptCallWithDOMPropsThatDontMatchElement.displayName = "shouldNotAcceptCallWithDOMPropsThatDontMatchElement";
30
+ export function shouldAcceptCallWithAsAndDOMProps(ref) {
31
+ return /*#__PURE__*/React.createElement(Overlay, {
32
+ as: "a",
33
+ returnFocusRef: ref,
34
+ onClickOutside: () => null,
35
+ onEscape: () => null,
36
+ href: "//primer.style/"
37
+ });
38
+ }
39
+ shouldAcceptCallWithAsAndDOMProps.displayName = "shouldAcceptCallWithAsAndDOMProps";
11
40
  export function shouldNotAcceptSystemProps(ref) {
12
41
  return /*#__PURE__*/React.createElement(Overlay, {
13
42
  returnFocusRef: ref,
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ export declare function shouldAcceptCallWithNoProps(): JSX.Element;
3
+ export declare function shouldAcceptDOMPropsOnOverlay(): JSX.Element;
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+ import { SelectPanel } from '../SelectPanel';
3
+ export function shouldAcceptCallWithNoProps() {
4
+ return /*#__PURE__*/React.createElement(SelectPanel, {
5
+ placeholderText: "",
6
+ open: false,
7
+ onOpenChange: () => null,
8
+ items: [],
9
+ selected: [],
10
+ onSelectedChange: () => null,
11
+ onFilterChange: () => null
12
+ });
13
+ }
14
+ shouldAcceptCallWithNoProps.displayName = "shouldAcceptCallWithNoProps";
15
+ export function shouldAcceptDOMPropsOnOverlay() {
16
+ return /*#__PURE__*/React.createElement(SelectPanel, {
17
+ placeholderText: "",
18
+ open: false,
19
+ onOpenChange: () => null,
20
+ items: [],
21
+ selected: [],
22
+ onSelectedChange: () => null,
23
+ onFilterChange: () => null,
24
+ overlayProps: {
25
+ onMouseDown: () => null
26
+ }
27
+ });
28
+ }
29
+ shouldAcceptDOMPropsOnOverlay.displayName = "shouldAcceptDOMPropsOnOverlay";
@@ -115,4 +115,6 @@ export { default as Truncate } from './Truncate';
115
115
  export type { TruncateProps } from './Truncate';
116
116
  export { default as UnderlineNav } from './UnderlineNav';
117
117
  export type { UnderlineNavProps, UnderlineNavLinkProps } from './UnderlineNav';
118
+ export { default as Checkbox } from './Checkbox';
119
+ export type { CheckboxProps } from './Checkbox';
118
120
  export { SSRProvider, useSSRSafeId } from './utils/ssr';
package/lib-esm/index.js CHANGED
@@ -70,4 +70,5 @@ export { default as Token, IssueLabelToken, AvatarToken } from './Token';
70
70
  export { default as Tooltip } from './Tooltip';
71
71
  export { default as Truncate } from './Truncate';
72
72
  export { default as UnderlineNav } from './UnderlineNav';
73
+ export { default as Checkbox } from './Checkbox';
73
74
  export { SSRProvider, useSSRSafeId } from './utils/ssr';