@dt-dds/react-checkbox 1.0.0-beta.57 → 1.0.0-beta.59

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @dt-ui/react-checkbox
2
2
 
3
+ ## 1.0.0-beta.59
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: change color logic on typography
8
+ - Updated dependencies
9
+ - @dt-dds/themes@1.0.0-beta.12
10
+ - @dt-dds/react-core@1.0.0-beta.57
11
+ - @dt-dds/react-icon@1.0.0-beta.60
12
+
13
+ ## 1.0.0-beta.58
14
+
15
+ ### Minor Changes
16
+
17
+ - feat: refactor checkbox
18
+
3
19
  ## 1.0.0-beta.57
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -6,31 +6,57 @@ A checkbox toggles between checked and unchecked states, enabling users to make
6
6
 
7
7
  ```jsx
8
8
  import { Checkbox } from '@dt-dds/react-checkbox';
9
+ import { useState } from 'react';
9
10
 
10
11
  export const App = () => {
11
- const [checked, setChecked] = React.useState(true);
12
+ const [checked, setChecked] = useState(false);
12
13
 
13
- const handleChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
14
+ const handleChange = (evt) => {
14
15
  setChecked(evt.target.checked);
15
16
  };
16
17
 
17
18
  return (
18
- <Checkbox isChecked={checked} onChange={handleChange}>
19
- Label
19
+ <Checkbox checked={checked} onChange={handleChange}>
20
+ Accept terms and conditions
20
21
  </Checkbox>
21
22
  );
22
23
  };
23
24
  ```
24
25
 
26
+ ## Indeterminate State
27
+
28
+ ```jsx
29
+ const [checkedItems, setCheckedItems] = useState([false, false, false]);
30
+
31
+ const allChecked = checkedItems.every(Boolean);
32
+ const isIndeterminate = checkedItems.some(Boolean) && !allChecked;
33
+
34
+ <Checkbox
35
+ checked={allChecked}
36
+ indeterminate={isIndeterminate}
37
+ onChange={(e) => setCheckedItems([e.target.checked, e.target.checked, e.target.checked])}
38
+ >
39
+ Select all
40
+ </Checkbox>
41
+ ```
42
+
25
43
  ## Properties
26
44
 
27
- | Property | Type | Default | Description |
28
- | ------------ | ---------------------------------------------- | ------------- | ----------------------------------------------------------------------------- |
29
- | `children` | `ReactNode` | - | Child components to be rendered as the label. |
30
- | `onChange` | `(evt: ChangeEvent<HTMLInputElement>) => void` | - | The triggered function when the input change. |
31
- | `isDisabled` | `boolean` | `false` | Specifies if the element should be disabled. |
32
- | `isChecked` | `boolean` | `false` | Specifies if the element should be pre-selected (checked) when the page loads |
33
- | `dataTestId` | `string` | `checkbox-id` | Customizable test identifier |
45
+ | Property | Type | Default | Description |
46
+ |--------------------|-----------------------------------------------|---------------|-----------------------------------------------------------------------------|
47
+ | isChecked | `boolean` | | Controls the checked state |
48
+ | onChange | `(evt: ChangeEvent<HTMLInputElement>) => void`| | Callback fired when the state changes. |
49
+ | isDisabled | `boolean` | `false` | If `true`, the checkbox is disabled. |
50
+ | isIndeterminate | `boolean` | `false` | If `true`, the checkbox appears in an indeterminate state. |
51
+ | hasError | `boolean` | `false` | If `true`, the checkbox displays an error state. |
52
+ | size | `'small' \| 'large'` | `'large'` | Size of the checkbox. |
53
+ | label | `ReactNode` | — | Text or elements to display as the label. |
54
+ | children | `ReactNode` | — | Alternative way to provide label content. |
55
+ | dataTestId | `string` | `'checkbox'` | Test identifier for testing libraries. |
56
+ | id | `string` | — | HTML `id` attribute for the input element. |
57
+ | aria-label | `string` | — | Accessibility label (required if no `label` or `children` provided). |
58
+ | style | `CSSProperties` | — | Inline styles for the wrapper. |
59
+ | ref | `Ref<HTMLInputElement>` | — | Ref forwarded to the input element. |
34
60
 
35
61
  ### Note
36
62
 
package/dist/index.d.mts CHANGED
@@ -1,19 +1,25 @@
1
1
  import { CustomTheme } from '@dt-dds/themes';
2
2
  import * as react from 'react';
3
- import { ComponentPropsWithRef, ChangeEvent } from 'react';
4
- import { BaseProps } from '@dt-dds/react-core';
3
+ import { ComponentPropsWithRef, ChangeEvent, ReactNode } from 'react';
4
+ import { BaseProps, ComponentSize } from '@dt-dds/react-core';
5
5
 
6
- interface CheckBoxProps extends BaseProps, ComponentPropsWithRef<'input'> {
7
- onChange?: (evt: ChangeEvent<HTMLInputElement>) => void;
6
+ type CheckboxSize = Extract<ComponentSize, 'small' | 'large'>;
7
+ interface CheckboxProps extends BaseProps, Omit<ComponentPropsWithRef<'input'>, 'size' | 'onChange'> {
8
+ onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
8
9
  isChecked?: boolean;
9
10
  isDisabled?: boolean;
10
- className?: string;
11
+ isIndeterminate?: boolean;
12
+ hasError?: boolean;
13
+ size?: CheckboxSize;
14
+ label?: ReactNode;
15
+ 'aria-label'?: string;
11
16
  }
12
- declare const Checkbox: react.ForwardRefExoticComponent<Omit<CheckBoxProps, "ref"> & react.RefAttributes<HTMLInputElement>>;
17
+
18
+ declare const Checkbox: react.ForwardRefExoticComponent<Omit<CheckboxProps, "ref"> & react.RefAttributes<HTMLInputElement>>;
13
19
 
14
20
  declare module '@emotion/react' {
15
21
  interface Theme extends CustomTheme {
16
22
  }
17
23
  }
18
24
 
19
- export { type CheckBoxProps, Checkbox };
25
+ export { Checkbox, type CheckboxProps, type CheckboxSize };
package/dist/index.d.ts CHANGED
@@ -1,19 +1,25 @@
1
1
  import { CustomTheme } from '@dt-dds/themes';
2
2
  import * as react from 'react';
3
- import { ComponentPropsWithRef, ChangeEvent } from 'react';
4
- import { BaseProps } from '@dt-dds/react-core';
3
+ import { ComponentPropsWithRef, ChangeEvent, ReactNode } from 'react';
4
+ import { BaseProps, ComponentSize } from '@dt-dds/react-core';
5
5
 
6
- interface CheckBoxProps extends BaseProps, ComponentPropsWithRef<'input'> {
7
- onChange?: (evt: ChangeEvent<HTMLInputElement>) => void;
6
+ type CheckboxSize = Extract<ComponentSize, 'small' | 'large'>;
7
+ interface CheckboxProps extends BaseProps, Omit<ComponentPropsWithRef<'input'>, 'size' | 'onChange'> {
8
+ onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
8
9
  isChecked?: boolean;
9
10
  isDisabled?: boolean;
10
- className?: string;
11
+ isIndeterminate?: boolean;
12
+ hasError?: boolean;
13
+ size?: CheckboxSize;
14
+ label?: ReactNode;
15
+ 'aria-label'?: string;
11
16
  }
12
- declare const Checkbox: react.ForwardRefExoticComponent<Omit<CheckBoxProps, "ref"> & react.RefAttributes<HTMLInputElement>>;
17
+
18
+ declare const Checkbox: react.ForwardRefExoticComponent<Omit<CheckboxProps, "ref"> & react.RefAttributes<HTMLInputElement>>;
13
19
 
14
20
  declare module '@emotion/react' {
15
21
  interface Theme extends CustomTheme {
16
22
  }
17
23
  }
18
24
 
19
- export { type CheckBoxProps, Checkbox };
25
+ export { Checkbox, type CheckboxProps, type CheckboxSize };
package/dist/index.js CHANGED
@@ -66,142 +66,229 @@ var import_react2 = require("@emotion/react");
66
66
  var import_react_icon = require("@dt-dds/react-icon");
67
67
 
68
68
  // src/Checkbox.styled.ts
69
+ var import_is_prop_valid = __toESM(require("@emotion/is-prop-valid"));
69
70
  var import_styled = __toESM(require("@emotion/styled"));
70
71
 
71
- // src/utils/checkboxStyles.ts
72
- var checkboxStyles = (theme, isChecked, isDisabled) => {
73
- if (isChecked) {
74
- return `
75
- border: none;
76
- background-color: ${isDisabled ? theme.palette.informative.light : theme.palette.informative.default};
77
- `;
78
- }
79
- return `
80
- border: 1px solid ${theme.palette.informative.medium};
81
- background-color: ${isDisabled ? theme.palette.informative.light : theme.palette.surface.contrast};
82
- `;
72
+ // src/constants/index.ts
73
+ var SIZES = {
74
+ small: 20,
75
+ large: 24
83
76
  };
84
77
 
85
78
  // src/Checkbox.styled.ts
86
- var CheckboxStyled = import_styled.default.label`
87
- display: flex;
88
- align-items: center;
89
- width: 100%;
90
-
91
- ${({ theme, isChecked, isDisabled }) => `
92
- & > div {
93
- border-radius: ${theme.shape.checkbox};
94
- ${checkboxStyles(theme, isChecked, isDisabled)}
79
+ var getCheckboxColors = (theme) => ({
80
+ disabled: {
81
+ active: {
82
+ bg: theme.palette.informative.light,
83
+ border: "transparent"
84
+ },
85
+ inactive: {
86
+ bg: theme.palette.informative.light,
87
+ border: theme.palette.informative.medium
95
88
  }
96
- cursor: ${isDisabled ? "not-allowed" : "pointer"};
97
-
98
- &:hover > div {
99
- ${!isDisabled && !isChecked && `
100
- border: 1px solid ${theme.palette.primary.default};
101
- `};
102
- }
103
- `}
104
- `;
105
- var CheckBoxInputWrapper = import_styled.default.div`
106
- height: 20px;
107
- min-height: 20px;
108
- width: 20px;
109
- min-width: 20px;
89
+ },
90
+ default: {
91
+ active: {
92
+ normal: {
93
+ bg: theme.palette.informative.default,
94
+ border: "transparent",
95
+ hover: theme.palette.informative.dark
96
+ },
97
+ error: {
98
+ bg: theme.palette.error.default,
99
+ border: "transparent",
100
+ hover: theme.palette.error.dark
101
+ }
102
+ },
103
+ inactive: {
104
+ normal: {
105
+ bg: theme.palette.surface.contrast,
106
+ border: theme.palette.informative.default,
107
+ hover: theme.palette.informative.light
108
+ },
109
+ error: {
110
+ bg: theme.palette.surface.contrast,
111
+ border: theme.palette.error.default,
112
+ hover: theme.palette.error.light
113
+ }
114
+ }
115
+ }
116
+ });
117
+ var CheckboxStyled = (0, import_styled.default)("label", {
118
+ shouldForwardProp: (prop) => (0, import_is_prop_valid.default)(prop) && !prop.startsWith("$")
119
+ })`
120
+ display: inline-flex;
121
+ align-items: center;
122
+ cursor: ${({ $disabled }) => $disabled ? "not-allowed" : "pointer"};
110
123
  position: relative;
111
- display: flex;
112
124
  `;
113
125
  var CheckboxInputStyled = import_styled.default.input`
114
- cursor: pointer;
115
126
  appearance: none;
116
127
  position: absolute;
117
- width: 100%;
118
- height: 100%;
119
- top: 0;
120
- left: 0;
128
+ inset: 0;
121
129
  margin: 0;
122
130
  padding: 0;
131
+ opacity: 0;
132
+ cursor: inherit;
133
+ `;
134
+ var CheckboxBoxStyled = (0, import_styled.default)("div", {
135
+ shouldForwardProp: (prop) => (0, import_is_prop_valid.default)(prop) && !prop.startsWith("$")
136
+ })`
137
+ pointer-events: none;
138
+ position: relative;
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: center;
142
+ border-radius: ${({ theme }) => theme.shape.checkbox};
143
+
144
+ ${({ theme, $checked, $indeterminate, $disabled, $error, $size }) => {
145
+ const colors = getCheckboxColors(theme);
146
+ const active = $checked || $indeterminate;
147
+ const state = $disabled ? colors.disabled[active ? "active" : "inactive"] : colors.default[active ? "active" : "inactive"][$error ? "error" : "normal"];
148
+ return `
149
+ height: ${SIZES[$size]}px;
150
+ min-height: ${SIZES[$size]}px;
151
+ width: ${SIZES[$size]}px;
152
+ min-width: ${SIZES[$size]}px;
123
153
 
124
- &:disabled {
125
- cursor: not-allowed;
154
+ background-color: ${state.bg};
155
+ border: 1px solid ${state.border};
156
+
157
+ ${!$disabled && "hover" in state ? `
158
+ label:hover & {
159
+ background-color: ${state.hover};
160
+ }
161
+ ` : ""}
162
+ `;
163
+ }}
164
+
165
+ input:focus-visible + & {
166
+ outline: 2px solid ${({ theme }) => theme.palette.primary.default};
167
+ outline-offset: 2px;
126
168
  }
127
169
  `;
128
- var CheckboxLabelStyled = import_styled.default.span`
170
+ var CheckboxLabelStyled = (0, import_styled.default)("div", {
171
+ shouldForwardProp: (prop) => (0, import_is_prop_valid.default)(prop) && !prop.startsWith("$")
172
+ })`
129
173
  user-select: none;
130
- text-overflow: ellipsis;
131
- white-space: nowrap;
132
- overflow: hidden;
133
- width: 100%;
174
+ display: flex;
175
+ align-items: center;
134
176
 
135
- ${({ theme, isDisabled }) => `
177
+ ${({ theme, $disabled, $size }) => `
136
178
  padding-left: ${theme.spacing.spacing_30};
137
- ${theme.fontStyles.bodyMdRegular};
138
- color: ${isDisabled ? theme.palette.content.medium : theme.palette.content.default};
179
+ ${$size === "small" ? theme.fontStyles.bodyMdRegular : theme.fontStyles.bodyLgRegular};
180
+ color: ${$disabled ? theme.palette.content.light : theme.palette.content.default};
139
181
  `}
140
182
  `;
141
183
 
184
+ // src/utils/mergeRefs.ts
185
+ function mergeRefs(...refs) {
186
+ return (node) => {
187
+ for (const ref of refs) {
188
+ if (!ref) continue;
189
+ if (typeof ref === "function") {
190
+ ref(node);
191
+ } else if (ref) {
192
+ ref.current = node;
193
+ }
194
+ }
195
+ };
196
+ }
197
+
142
198
  // src/Checkbox.tsx
143
199
  var import_jsx_runtime = require("react/jsx-runtime");
144
200
  var Checkbox = (0, import_react.forwardRef)(
145
201
  (_a, ref) => {
146
202
  var _b = _a, {
147
- dataTestId = "checkbox-id",
203
+ dataTestId = "checkbox",
148
204
  onChange,
149
- children,
150
205
  isChecked = false,
151
206
  isDisabled = false,
207
+ isIndeterminate = false,
208
+ hasError = false,
209
+ size = "large",
210
+ label,
211
+ children,
152
212
  style,
153
- className
213
+ id,
214
+ "aria-label": ariaLabel
154
215
  } = _b, rest = __objRest(_b, [
155
216
  "dataTestId",
156
217
  "onChange",
157
- "children",
158
218
  "isChecked",
159
219
  "isDisabled",
220
+ "isIndeterminate",
221
+ "hasError",
222
+ "size",
223
+ "label",
224
+ "children",
160
225
  "style",
161
- "className"
226
+ "id",
227
+ "aria-label"
162
228
  ]);
163
229
  const theme = (0, import_react2.useTheme)();
164
- const handleOnChangeTrigger = (event) => {
165
- if (isDisabled) {
166
- return;
230
+ const internalRef = (0, import_react.useRef)(null);
231
+ const mergedRef = mergeRefs(internalRef, ref);
232
+ (0, import_react.useEffect)(() => {
233
+ if (internalRef.current) {
234
+ internalRef.current.indeterminate = isIndeterminate;
167
235
  }
236
+ }, [isIndeterminate]);
237
+ const handleChange = (event) => {
238
+ if (isDisabled) return;
168
239
  onChange == null ? void 0 : onChange(event);
169
240
  };
241
+ const hasLabel = Boolean(label || children);
242
+ const inputId = id || (hasLabel ? dataTestId : void 0);
243
+ const iconCode = isIndeterminate ? "remove" : isChecked ? "check" : null;
244
+ const iconSize = size === "small" ? "medium" : "large";
170
245
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
171
246
  CheckboxStyled,
172
247
  {
173
- className,
248
+ $disabled: isDisabled,
174
249
  "data-testid": dataTestId,
175
- isChecked,
176
- isDisabled,
250
+ htmlFor: inputId,
177
251
  style,
178
252
  children: [
179
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CheckBoxInputWrapper, { children: [
180
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
181
- CheckboxInputStyled,
182
- __spreadValues({
183
- checked: isChecked,
184
- disabled: isDisabled,
185
- onChange: handleOnChangeTrigger,
186
- ref,
187
- type: "checkbox"
188
- }, rest)
189
- ),
190
- isChecked ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
191
- import_react_icon.Icon,
192
- {
193
- code: "check",
194
- color: theme.palette.content.contrast,
195
- size: "medium"
196
- }
197
- ) : null
198
- ] }),
199
- children ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckboxLabelStyled, { isChecked, isDisabled, children }) : null
253
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
254
+ CheckboxInputStyled,
255
+ __spreadValues({
256
+ "aria-checked": isIndeterminate ? "mixed" : void 0,
257
+ "aria-invalid": hasError,
258
+ "aria-label": !hasLabel ? ariaLabel || "Checkbox" : void 0,
259
+ checked: isChecked,
260
+ disabled: isDisabled,
261
+ id: inputId,
262
+ onChange: handleChange,
263
+ ref: mergedRef,
264
+ type: "checkbox"
265
+ }, rest)
266
+ ),
267
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
268
+ CheckboxBoxStyled,
269
+ {
270
+ $checked: isChecked,
271
+ $disabled: isDisabled,
272
+ $error: hasError,
273
+ $indeterminate: isIndeterminate,
274
+ $size: size,
275
+ children: iconCode ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
276
+ import_react_icon.Icon,
277
+ {
278
+ code: iconCode,
279
+ color: theme.palette.content.contrast,
280
+ size: iconSize
281
+ }
282
+ ) : null
283
+ }
284
+ ),
285
+ hasLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckboxLabelStyled, { $disabled: isDisabled, $size: size, children: label || children }) : null
200
286
  ]
201
287
  }
202
288
  );
203
289
  }
204
290
  );
291
+ Checkbox.displayName = "Checkbox";
205
292
  // Annotate the CommonJS export names for ESM import in node:
206
293
  0 && (module.exports = {
207
294
  Checkbox
package/dist/index.mjs CHANGED
@@ -28,147 +28,234 @@ var __objRest = (source, exclude) => {
28
28
  };
29
29
 
30
30
  // src/Checkbox.tsx
31
- import { forwardRef } from "react";
31
+ import { forwardRef, useEffect, useRef } from "react";
32
32
  import { useTheme } from "@emotion/react";
33
33
  import { Icon } from "@dt-dds/react-icon";
34
34
 
35
35
  // src/Checkbox.styled.ts
36
+ import isPropValid from "@emotion/is-prop-valid";
36
37
  import styled from "@emotion/styled";
37
38
 
38
- // src/utils/checkboxStyles.ts
39
- var checkboxStyles = (theme, isChecked, isDisabled) => {
40
- if (isChecked) {
41
- return `
42
- border: none;
43
- background-color: ${isDisabled ? theme.palette.informative.light : theme.palette.informative.default};
44
- `;
45
- }
46
- return `
47
- border: 1px solid ${theme.palette.informative.medium};
48
- background-color: ${isDisabled ? theme.palette.informative.light : theme.palette.surface.contrast};
49
- `;
39
+ // src/constants/index.ts
40
+ var SIZES = {
41
+ small: 20,
42
+ large: 24
50
43
  };
51
44
 
52
45
  // src/Checkbox.styled.ts
53
- var CheckboxStyled = styled.label`
54
- display: flex;
55
- align-items: center;
56
- width: 100%;
57
-
58
- ${({ theme, isChecked, isDisabled }) => `
59
- & > div {
60
- border-radius: ${theme.shape.checkbox};
61
- ${checkboxStyles(theme, isChecked, isDisabled)}
46
+ var getCheckboxColors = (theme) => ({
47
+ disabled: {
48
+ active: {
49
+ bg: theme.palette.informative.light,
50
+ border: "transparent"
51
+ },
52
+ inactive: {
53
+ bg: theme.palette.informative.light,
54
+ border: theme.palette.informative.medium
62
55
  }
63
- cursor: ${isDisabled ? "not-allowed" : "pointer"};
64
-
65
- &:hover > div {
66
- ${!isDisabled && !isChecked && `
67
- border: 1px solid ${theme.palette.primary.default};
68
- `};
69
- }
70
- `}
71
- `;
72
- var CheckBoxInputWrapper = styled.div`
73
- height: 20px;
74
- min-height: 20px;
75
- width: 20px;
76
- min-width: 20px;
56
+ },
57
+ default: {
58
+ active: {
59
+ normal: {
60
+ bg: theme.palette.informative.default,
61
+ border: "transparent",
62
+ hover: theme.palette.informative.dark
63
+ },
64
+ error: {
65
+ bg: theme.palette.error.default,
66
+ border: "transparent",
67
+ hover: theme.palette.error.dark
68
+ }
69
+ },
70
+ inactive: {
71
+ normal: {
72
+ bg: theme.palette.surface.contrast,
73
+ border: theme.palette.informative.default,
74
+ hover: theme.palette.informative.light
75
+ },
76
+ error: {
77
+ bg: theme.palette.surface.contrast,
78
+ border: theme.palette.error.default,
79
+ hover: theme.palette.error.light
80
+ }
81
+ }
82
+ }
83
+ });
84
+ var CheckboxStyled = styled("label", {
85
+ shouldForwardProp: (prop) => isPropValid(prop) && !prop.startsWith("$")
86
+ })`
87
+ display: inline-flex;
88
+ align-items: center;
89
+ cursor: ${({ $disabled }) => $disabled ? "not-allowed" : "pointer"};
77
90
  position: relative;
78
- display: flex;
79
91
  `;
80
92
  var CheckboxInputStyled = styled.input`
81
- cursor: pointer;
82
93
  appearance: none;
83
94
  position: absolute;
84
- width: 100%;
85
- height: 100%;
86
- top: 0;
87
- left: 0;
95
+ inset: 0;
88
96
  margin: 0;
89
97
  padding: 0;
98
+ opacity: 0;
99
+ cursor: inherit;
100
+ `;
101
+ var CheckboxBoxStyled = styled("div", {
102
+ shouldForwardProp: (prop) => isPropValid(prop) && !prop.startsWith("$")
103
+ })`
104
+ pointer-events: none;
105
+ position: relative;
106
+ display: flex;
107
+ align-items: center;
108
+ justify-content: center;
109
+ border-radius: ${({ theme }) => theme.shape.checkbox};
110
+
111
+ ${({ theme, $checked, $indeterminate, $disabled, $error, $size }) => {
112
+ const colors = getCheckboxColors(theme);
113
+ const active = $checked || $indeterminate;
114
+ const state = $disabled ? colors.disabled[active ? "active" : "inactive"] : colors.default[active ? "active" : "inactive"][$error ? "error" : "normal"];
115
+ return `
116
+ height: ${SIZES[$size]}px;
117
+ min-height: ${SIZES[$size]}px;
118
+ width: ${SIZES[$size]}px;
119
+ min-width: ${SIZES[$size]}px;
90
120
 
91
- &:disabled {
92
- cursor: not-allowed;
121
+ background-color: ${state.bg};
122
+ border: 1px solid ${state.border};
123
+
124
+ ${!$disabled && "hover" in state ? `
125
+ label:hover & {
126
+ background-color: ${state.hover};
127
+ }
128
+ ` : ""}
129
+ `;
130
+ }}
131
+
132
+ input:focus-visible + & {
133
+ outline: 2px solid ${({ theme }) => theme.palette.primary.default};
134
+ outline-offset: 2px;
93
135
  }
94
136
  `;
95
- var CheckboxLabelStyled = styled.span`
137
+ var CheckboxLabelStyled = styled("div", {
138
+ shouldForwardProp: (prop) => isPropValid(prop) && !prop.startsWith("$")
139
+ })`
96
140
  user-select: none;
97
- text-overflow: ellipsis;
98
- white-space: nowrap;
99
- overflow: hidden;
100
- width: 100%;
141
+ display: flex;
142
+ align-items: center;
101
143
 
102
- ${({ theme, isDisabled }) => `
144
+ ${({ theme, $disabled, $size }) => `
103
145
  padding-left: ${theme.spacing.spacing_30};
104
- ${theme.fontStyles.bodyMdRegular};
105
- color: ${isDisabled ? theme.palette.content.medium : theme.palette.content.default};
146
+ ${$size === "small" ? theme.fontStyles.bodyMdRegular : theme.fontStyles.bodyLgRegular};
147
+ color: ${$disabled ? theme.palette.content.light : theme.palette.content.default};
106
148
  `}
107
149
  `;
108
150
 
151
+ // src/utils/mergeRefs.ts
152
+ function mergeRefs(...refs) {
153
+ return (node) => {
154
+ for (const ref of refs) {
155
+ if (!ref) continue;
156
+ if (typeof ref === "function") {
157
+ ref(node);
158
+ } else if (ref) {
159
+ ref.current = node;
160
+ }
161
+ }
162
+ };
163
+ }
164
+
109
165
  // src/Checkbox.tsx
110
166
  import { jsx, jsxs } from "react/jsx-runtime";
111
167
  var Checkbox = forwardRef(
112
168
  (_a, ref) => {
113
169
  var _b = _a, {
114
- dataTestId = "checkbox-id",
170
+ dataTestId = "checkbox",
115
171
  onChange,
116
- children,
117
172
  isChecked = false,
118
173
  isDisabled = false,
174
+ isIndeterminate = false,
175
+ hasError = false,
176
+ size = "large",
177
+ label,
178
+ children,
119
179
  style,
120
- className
180
+ id,
181
+ "aria-label": ariaLabel
121
182
  } = _b, rest = __objRest(_b, [
122
183
  "dataTestId",
123
184
  "onChange",
124
- "children",
125
185
  "isChecked",
126
186
  "isDisabled",
187
+ "isIndeterminate",
188
+ "hasError",
189
+ "size",
190
+ "label",
191
+ "children",
127
192
  "style",
128
- "className"
193
+ "id",
194
+ "aria-label"
129
195
  ]);
130
196
  const theme = useTheme();
131
- const handleOnChangeTrigger = (event) => {
132
- if (isDisabled) {
133
- return;
197
+ const internalRef = useRef(null);
198
+ const mergedRef = mergeRefs(internalRef, ref);
199
+ useEffect(() => {
200
+ if (internalRef.current) {
201
+ internalRef.current.indeterminate = isIndeterminate;
134
202
  }
203
+ }, [isIndeterminate]);
204
+ const handleChange = (event) => {
205
+ if (isDisabled) return;
135
206
  onChange == null ? void 0 : onChange(event);
136
207
  };
208
+ const hasLabel = Boolean(label || children);
209
+ const inputId = id || (hasLabel ? dataTestId : void 0);
210
+ const iconCode = isIndeterminate ? "remove" : isChecked ? "check" : null;
211
+ const iconSize = size === "small" ? "medium" : "large";
137
212
  return /* @__PURE__ */ jsxs(
138
213
  CheckboxStyled,
139
214
  {
140
- className,
215
+ $disabled: isDisabled,
141
216
  "data-testid": dataTestId,
142
- isChecked,
143
- isDisabled,
217
+ htmlFor: inputId,
144
218
  style,
145
219
  children: [
146
- /* @__PURE__ */ jsxs(CheckBoxInputWrapper, { children: [
147
- /* @__PURE__ */ jsx(
148
- CheckboxInputStyled,
149
- __spreadValues({
150
- checked: isChecked,
151
- disabled: isDisabled,
152
- onChange: handleOnChangeTrigger,
153
- ref,
154
- type: "checkbox"
155
- }, rest)
156
- ),
157
- isChecked ? /* @__PURE__ */ jsx(
158
- Icon,
159
- {
160
- code: "check",
161
- color: theme.palette.content.contrast,
162
- size: "medium"
163
- }
164
- ) : null
165
- ] }),
166
- children ? /* @__PURE__ */ jsx(CheckboxLabelStyled, { isChecked, isDisabled, children }) : null
220
+ /* @__PURE__ */ jsx(
221
+ CheckboxInputStyled,
222
+ __spreadValues({
223
+ "aria-checked": isIndeterminate ? "mixed" : void 0,
224
+ "aria-invalid": hasError,
225
+ "aria-label": !hasLabel ? ariaLabel || "Checkbox" : void 0,
226
+ checked: isChecked,
227
+ disabled: isDisabled,
228
+ id: inputId,
229
+ onChange: handleChange,
230
+ ref: mergedRef,
231
+ type: "checkbox"
232
+ }, rest)
233
+ ),
234
+ /* @__PURE__ */ jsx(
235
+ CheckboxBoxStyled,
236
+ {
237
+ $checked: isChecked,
238
+ $disabled: isDisabled,
239
+ $error: hasError,
240
+ $indeterminate: isIndeterminate,
241
+ $size: size,
242
+ children: iconCode ? /* @__PURE__ */ jsx(
243
+ Icon,
244
+ {
245
+ code: iconCode,
246
+ color: theme.palette.content.contrast,
247
+ size: iconSize
248
+ }
249
+ ) : null
250
+ }
251
+ ),
252
+ hasLabel ? /* @__PURE__ */ jsx(CheckboxLabelStyled, { $disabled: isDisabled, $size: size, children: label || children }) : null
167
253
  ]
168
254
  }
169
255
  );
170
256
  }
171
257
  );
258
+ Checkbox.displayName = "Checkbox";
172
259
  export {
173
260
  Checkbox
174
261
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dt-dds/react-checkbox",
3
- "version": "1.0.0-beta.57",
3
+ "version": "1.0.0-beta.59",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js"
@@ -20,9 +20,9 @@
20
20
  "test:update:snapshot": "jest -u"
21
21
  },
22
22
  "dependencies": {
23
- "@dt-dds/react-core": "1.0.0-beta.56",
24
- "@dt-dds/react-icon": "1.0.0-beta.59",
25
- "@dt-dds/themes": "1.0.0-beta.11"
23
+ "@dt-dds/react-core": "1.0.0-beta.57",
24
+ "@dt-dds/react-icon": "1.0.0-beta.60",
25
+ "@dt-dds/themes": "1.0.0-beta.12"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@babel/core": "^7.22.9",