@synerise/ds-checkbox 1.2.34 → 1.2.36

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
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.2.36](https://github.com/synerise/synerise-design/compare/@synerise/ds-checkbox@1.2.35...@synerise/ds-checkbox@1.2.36) (2026-07-23)
7
+
8
+ **Note:** Version bump only for package @synerise/ds-checkbox
9
+
10
+ ## [1.2.35](https://github.com/synerise/synerise-design/compare/@synerise/ds-checkbox@1.2.34...@synerise/ds-checkbox@1.2.35) (2026-06-27)
11
+
12
+ **Note:** Version bump only for package @synerise/ds-checkbox
13
+
6
14
  ## [1.2.34](https://github.com/synerise/synerise-design/compare/@synerise/ds-checkbox@1.2.33...@synerise/ds-checkbox@1.2.34) (2026-06-17)
7
15
 
8
16
  **Note:** Version bump only for package @synerise/ds-checkbox
package/CLAUDE.md ADDED
@@ -0,0 +1,139 @@
1
+ # Checkbox (`@synerise/ds-checkbox`)
2
+
3
+ > DS-native, antd-free checkbox with DS-specific extras (description, error text, error styling, padding control), a `Checkbox.Group`, and a three-state mode (unchecked → checked → indeterminate → unchecked) via the `tristate` prop.
4
+
5
+ ## Package structure
6
+
7
+ ```
8
+ src/
9
+ Checkbox.tsx — router: delegates to CheckboxBase or CheckboxTristate; attaches .Group
10
+ Checkbox.types.ts — CheckboxProps union, CheckboxGroupProps, event types, CheckboxValueType
11
+ Checkbox.styles.ts — CheckboxLabel (full visual), CheckboxWrapper, AdditionalData
12
+ CheckboxGroup.tsx — DS-native Checkbox.Group (context provider)
13
+ CheckboxContext.ts — group context (value + toggle + register)
14
+ index.ts — public exports
15
+ components/
16
+ CheckboxBase.tsx — DS-native checkbox input (DOM + group consumption + event synthesis)
17
+ CheckboxTristate.tsx — three-state stateful layer on top of CheckboxBase
18
+ utils/
19
+ isTristateCheckbox.ts — type guard: checks props.tristate === true
20
+ nextCheckedValues.ts — state machine: (checked, indeterminate) → [nextChecked, nextIndeterminate]
21
+ checkedValue.ts — maps (checked, indeterminate) → boolean | undefined for event payload
22
+ ```
23
+
24
+ No LESS, no antd — the antd base + `checkbox.mixin.less` + styled overrides were inlined into `Checkbox.styles.ts`.
25
+
26
+ ## Public exports
27
+
28
+ ### `Checkbox` (default)
29
+
30
+ Smart router component. If `tristate={true}`, renders `CheckboxTristate`; otherwise renders `CheckboxBase`. Attaches `Checkbox.Group` as a static property.
31
+
32
+ #### DS-specific props (from `BaseCheckboxProps`)
33
+
34
+ | Prop | Type | Default | Description |
35
+ |------|------|---------|-------------|
36
+ | `description` | `ReactNode` | `undefined` | Helper text rendered below the checkbox with `ds-typography` `Description`. Respects `disabled` state (greyed out). |
37
+ | `errorText` | `ReactNode` | `undefined` | Error message rendered below. Also triggers the error visual on the checkbox box. |
38
+ | `hasError` | `boolean` | `undefined` | Error visual (red border) without an error text message. |
39
+ | `withoutPadding` | `boolean` | `undefined` | Removes the default `4px 12px 8px 8px` padding from the wrapper div. |
40
+
41
+ #### Mode-selector prop
42
+
43
+ | Prop | Type | Default | Description |
44
+ |------|------|---------|-------------|
45
+ | `tristate` | `true` | `undefined` | Switches to tristate mode. Changes the `onChange` event signature (see below). Cannot be `false` — omit the prop entirely for standard mode. |
46
+
47
+ Standard checkbox props are supported: `checked`, `defaultChecked`, `disabled`, `indeterminate`, `autoFocus`, `onChange`, `children`, `value`, `name`, `id`, `tabIndex`. (DS-native types — no antd inheritance.)
48
+
49
+ #### `onChange` event in tristate mode
50
+
51
+ When `tristate={true}`, `onChange` receives a `CheckboxTristateChangeEvent` instead of the standard Ant Design `CheckboxChangeEvent`. The key difference: `event.target.checked` is `boolean | undefined` — `undefined` means the indeterminate state.
52
+
53
+ #### `Checkbox.Group`
54
+
55
+ DS-native group (`CheckboxGroup`) — a context provider that child `Checkbox`es read for their checked state and toggle through. Supports `value`/`defaultValue` (controlled/uncontrolled), `onChange(checkedValues)` (ordered by child mount order, or `options` order), `options`, `disabled`, `name`. Replaces the former antd `Checkbox.Group` re-export.
56
+
57
+ ### Utility functions (exported)
58
+
59
+ | Export | Signature | Description |
60
+ |--------|-----------|-------------|
61
+ | `isTristateCheckbox` | `(props) => props is CheckboxTristateProps` | Type guard: returns `true` when `props.tristate === true`. |
62
+ | `nextCheckedValues` | `(checked, indeterminate) => [boolean, boolean]` | Computes the next `[checked, indeterminate]` state in the tristate cycle. |
63
+ | `checkedValue` | `(checked, indeterminate) => boolean \| undefined` | Converts internal state to the external checked value (`undefined` = indeterminate). |
64
+
65
+ ### Types (exported)
66
+
67
+ | Export | Description |
68
+ |--------|-------------|
69
+ | `CheckboxProps` | `CheckboxBaseProps \| CheckboxTristateProps` — main union |
70
+ | `CheckboxBaseProps` | Ant `CheckboxProps` + `BaseCheckboxProps`, with standard `onChange` |
71
+ | `CheckboxTristateProps` | Ant `CheckboxProps` + `BaseCheckboxProps`, with `tristate: true` and tristate `onChange` |
72
+ | `BaseCheckboxProps` | DS-only additions: `description`, `errorText`, `hasError`, `withoutPadding` |
73
+ | `CheckboxTristateChangeEvent` | Tristate event type: `target.checked` is `boolean \| undefined` |
74
+ | `CheckboxTristateChangeEventTarget` | The `target` shape inside `CheckboxTristateChangeEvent` |
75
+
76
+ ## Usage patterns
77
+
78
+ ```tsx
79
+ import Checkbox from '@synerise/ds-checkbox';
80
+
81
+ // Standard checkbox
82
+ <Checkbox onChange={handleChange}>Label</Checkbox>
83
+
84
+ // With error and description
85
+ <Checkbox
86
+ hasError
87
+ errorText="This field is required"
88
+ description="Choose at least one option"
89
+ >
90
+ Accept terms
91
+ </Checkbox>
92
+
93
+ // Tristate (uncontrolled — cycles false → true → indeterminate)
94
+ <Checkbox
95
+ tristate
96
+ onChange={(e) => {
97
+ // e.target.checked: true | false | undefined (undefined = indeterminate)
98
+ console.log(e.target.checked);
99
+ }}
100
+ >
101
+ Select all
102
+ </Checkbox>
103
+
104
+ // Tristate (controlled)
105
+ <Checkbox
106
+ tristate
107
+ checked={someState} // boolean | undefined
108
+ onChange={(e) => setSomeState(e.target.checked)}
109
+ >
110
+ Select all
111
+ </Checkbox>
112
+
113
+ // Group (Ant Design pass-through)
114
+ <Checkbox.Group options={['A', 'B', 'C']} onChange={handleGroupChange} />
115
+ ```
116
+
117
+ ## Styling
118
+
119
+ `Checkbox.styles.ts` is pure styled-components (theme tokens). **Each element is its own styled-component and owns its styles** — the `.ant-checkbox-*` / `ds-checkbox-*` class names are kept on the elements purely as hooks (ui-tests / interim external CSS), never used as styling selectors. State is passed in as transient `$`-props by `CheckboxBase`:
120
+ - `CheckboxWrapper` — flex column container; `withoutPadding` removes default spacing.
121
+ - `CheckboxBox` — the `.ant-checkbox` span (positioning).
122
+ - `CheckboxInput` — the visually-hidden `<input>` overlaying the box.
123
+ - `CheckboxInner` — the visible box: `grey-300` border, white-tick check (inline SVG data URL) when `$checked`, 2px white bar when `$indeterminate`, `$error` border, `$disabled` greys.
124
+ - `CheckboxText` — the label text; `$checked`/`$disabled` drive its colour/opacity.
125
+ - `CheckboxLabel` — the `<label>`; layout + the **cross-element** rules (hover-preview, indeterminate hover, focus ring, disabled cursor) that reference the child styled-components (`&:hover ${CheckboxInner}`, `${CheckboxInput}:focus + ${CheckboxInner}`). The hover-preview rule is only emitted when `!$checked && !$indeterminate && !$disabled`, so checked/disabled states never fight it.
126
+ - `AdditionalData` — left-aligns `errorText` and `description` below the checkbox box (28px left indent to align with label text).
127
+
128
+ ## Implementation notes
129
+
130
+ - **Tristate state machine** — the cycle is: `false` (unchecked) → `true` (checked) → `indeterminate` (represented as `undefined` to consumers) → `false`. Implemented in `nextCheckedValues`:
131
+ - `checked=false` → `[true, false]`
132
+ - `checked=true, !indeterminate` → `[true, true]`
133
+ - anything else → `[false, false]`
134
+ - **`tristate` as discriminated union discriminant** — `tristate?: never | false | undefined` in `OnChangeBaseProps` vs `tristate: true` in `OnChangeTristateProps`. This means TypeScript narrows `onChange` type correctly, but `tristate={false}` is technically forbidden by the type (use omission instead).
135
+ - **Controlled tristate** — the `useEffect` in `CheckboxTristate` syncs external `checked` to internal state. If `checked === undefined` externally, sets `indeterminate=true` and internal `checked=false`. If `checked` is boolean, sets `indeterminate=false`.
136
+ - **`CheckboxBase` and `CheckboxTristate` are NOT re-exported** from the main `index.ts` — they are internal components. Import `Checkbox` and use the `tristate` prop instead.
137
+ - **`$solo` transient prop** — `CheckboxLabel` receives `$solo={!children && !errorText && !description}`. When true, adds `padding: 4px` to keep the bare checkbox box from being flush against its container.
138
+ - **`Checkbox.Group`** is a DS-native context provider (`CheckboxGroup`). Child `Checkbox`es read the group's `value`/`toggleOption` from `CheckboxContext`; `options`-mode renders `CheckboxBase` directly (avoids a `Checkbox` ↔ `CheckboxGroup` import cycle).
139
+ - **`onChange` event is synthesised** in `CheckboxBase` from the native input change: `{ target: { value, name, checked }, stopPropagation, preventDefault, nativeEvent }` — antd-compatible shape.
@@ -2,6 +2,6 @@ import { default as React } from 'react';
2
2
  import { CheckboxProps } from './Checkbox.types';
3
3
  export declare const Checkbox: {
4
4
  (props: CheckboxProps): React.JSX.Element;
5
- Group: React.MemoExoticComponent<React.ForwardRefExoticComponent<import('antd/lib/checkbox').CheckboxGroupProps & React.RefAttributes<HTMLDivElement>>>;
5
+ Group: ({ value, defaultValue, onChange, options, disabled, name, children, className, style, }: import('./Checkbox.types').CheckboxGroupProps) => React.JSX.Element;
6
6
  };
7
7
  export default Checkbox;
package/dist/Checkbox.js CHANGED
@@ -1,16 +1,15 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { AntdCheckbox } from "./Checkbox.styles.js";
2
+ import CheckboxGroup from "./CheckboxGroup.js";
3
3
  import { CheckboxBase } from "./components/CheckboxBase.js";
4
4
  import { CheckboxTristate } from "./components/CheckboxTristate.js";
5
5
  import { isTristateCheckbox } from "./utils/isTristateCheckbox.js";
6
- import "./style/index.css";
7
6
  const Checkbox = (props) => {
8
7
  if (isTristateCheckbox(props)) {
9
8
  return /* @__PURE__ */ jsx(CheckboxTristate, { ...props });
10
9
  }
11
10
  return /* @__PURE__ */ jsx(CheckboxBase, { ...props });
12
11
  };
13
- Checkbox.Group = AntdCheckbox.Group;
12
+ Checkbox.Group = CheckboxGroup;
14
13
  export {
15
14
  Checkbox,
16
15
  Checkbox as default
@@ -1,15 +1,23 @@
1
- import { Checkbox as BaseAntCheckbox, CheckboxProps } from 'antd';
2
- /**
3
- * error TS4023: Exported variable 'AntdCheckbox' has or is using name 'CompoundedComponent' from external module "/Users/biedronne/Documents/Work/DS2/synerise-design/node_modules/antd/lib/checkbox/index" but cannot be named.
4
- */
5
- type CompoundedComponent = React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>> & {
6
- Group: typeof BaseAntCheckbox.Group;
7
- };
8
- export declare const AntdCheckbox: import('styled-components').StyledComponent<CompoundedComponent, any, {
9
- $solo: boolean;
10
- }, never>;
11
- export declare const AdditionalData: import('styled-components').StyledComponent<"div", any, {}, never>;
12
1
  export declare const CheckboxWrapper: import('styled-components').StyledComponent<"div", any, {
13
2
  withoutPadding: boolean;
14
3
  }, never>;
15
- export {};
4
+ export declare const AdditionalData: import('styled-components').StyledComponent<"div", any, {}, never>;
5
+ export declare const CheckboxInput: import('styled-components').StyledComponent<"input", any, {}, never>;
6
+ export declare const CheckboxInner: import('styled-components').StyledComponent<"span", any, {
7
+ $checked?: boolean;
8
+ $indeterminate?: boolean;
9
+ $disabled?: boolean;
10
+ $error?: boolean;
11
+ }, never>;
12
+ export declare const CheckboxText: import('styled-components').StyledComponent<"span", any, {
13
+ $checked?: boolean;
14
+ $disabled?: boolean;
15
+ }, never>;
16
+ export declare const CheckboxBox: import('styled-components').StyledComponent<"span", any, {}, never>;
17
+ export declare const CheckboxLabel: import('styled-components').StyledComponent<"label", any, {
18
+ $solo?: boolean;
19
+ $checked?: boolean;
20
+ $indeterminate?: boolean;
21
+ $disabled?: boolean;
22
+ $error?: boolean;
23
+ }, never>;
@@ -1,25 +1,43 @@
1
- import { Checkbox } from "antd";
2
1
  import styled, { css } from "styled-components";
3
2
  const checkSvgWithCustomColor = (color) => {
4
3
  const colorValueForSvg = color.replace(/#/, "%23");
5
- const iconWithColor = `data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='3 3 18 18' >/><path fill='none' d='M0 0h24v24H0z' /><path style='fill: ${colorValueForSvg};' stroke-width='1' stroke='${colorValueForSvg}' d='M10.61 15.744a.75.75 0 01-.535-.224l-3.11-3.162a.75.75 0 011.07-1.052l2.575 2.618 5.355-5.444a.75.75 0 111.07 1.052l-5.89 5.988a.75.75 0 01-.535.224z'/></svg>`;
6
- return iconWithColor;
4
+ return `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="3 3 18 18" >/><path fill="none" d="M0 0h24v24H0z" /><path style="fill: ${colorValueForSvg};" stroke-width="1" stroke="${colorValueForSvg}" d="M10.61 15.744a.75.75 0 01-.535-.224l-3.11-3.162a.75.75 0 011.07-1.052l2.575 2.618 5.355-5.444a.75.75 0 111.07 1.052l-5.89 5.988a.75.75 0 01-.535.224z"/></svg>`;
7
5
  };
8
6
  const soloCss = /* @__PURE__ */ css(["padding:4px;"]);
9
- const AntdCheckbox = /* @__PURE__ */ styled(Checkbox).withConfig({
10
- displayName: "Checkboxstyles__AntdCheckbox",
7
+ const CheckboxWrapper = /* @__PURE__ */ styled.div.withConfig({
8
+ displayName: "Checkboxstyles__CheckboxWrapper",
11
9
  componentId: "sc-10i9aa0-0"
12
- })(["&&{display:flex;align-items:center;line-height:1;", ";.ant-checkbox{top:0;}}.ant-checkbox-input:focus + .ant-checkbox-inner{border:1px solid ", ";box-shadow:inset 0 0 0 1px ", ";}&& > .ant-checkbox-disabled.ant-checkbox-checked > span.ant-checkbox-inner{background-image:", ";}&& > .ant-checkbox-checked > span.ant-checkbox-inner{background-image:", ";::after{display:none;}:focus{border:none;}}&&{> .ant-checkbox-indeterminate,.ant-checkbox-indeterminate.ant-checkbox-checked{> span.ant-checkbox-inner{background-color:", ";border:1px solid ", ";background-image:none;::after{background:#fff;height:2px;display:table;left:50%;}}}:hover{> .ant-checkbox-indeterminate,.ant-checkbox-indeterminate.ant-checkbox-checked{> span.ant-checkbox-inner{background-color:", ";}}}}&&:hover > .ant-checkbox:not(.ant-checkbox-checked):not( .ant-checkbox-indeterminate ):not(.ant-checkbox-disabled) > span.ant-checkbox-inner{border-width:1px;border-style:solid;border-color:", " !important;outline:none;background-image:", ";}"], (props) => props.$solo && soloCss, (props) => props.theme.palette["blue-600"], (props) => props.theme.palette["blue-600"], (props) => `url("${checkSvgWithCustomColor(props.theme.palette["grey-400"])}")`, (props) => `url("${checkSvgWithCustomColor(props.theme.palette.white)}")`, (props) => props.theme.palette["blue-600"], (props) => props.theme.palette["blue-600"], (props) => props.theme.palette["blue-500"], (props) => props.theme.palette["blue-600"], (props) => `url("${checkSvgWithCustomColor(props.theme.palette["blue-600"])}")`);
10
+ })(["display:flex;padding:", ";flex-direction:column;"], (props) => props.withoutPadding ? "0" : "4px 12px 8px 8px");
13
11
  const AdditionalData = /* @__PURE__ */ styled.div.withConfig({
14
12
  displayName: "Checkboxstyles__AdditionalData",
15
13
  componentId: "sc-10i9aa0-1"
16
14
  })(["margin:2px 12px 0px 28px;"]);
17
- const CheckboxWrapper = /* @__PURE__ */ styled.div.withConfig({
18
- displayName: "Checkboxstyles__CheckboxWrapper",
15
+ const CheckboxInput = /* @__PURE__ */ styled.input.withConfig({
16
+ displayName: "Checkboxstyles__CheckboxInput",
19
17
  componentId: "sc-10i9aa0-2"
20
- })(["display:flex;padding:", ";flex-direction:column;"], (props) => props.withoutPadding ? "0" : "4px 12px 8px 8px");
18
+ })(["position:absolute;inset:0;width:16px;height:16px;margin:0;padding:0;opacity:0;cursor:pointer;z-index:1;"]);
19
+ const CheckboxInner = /* @__PURE__ */ styled.span.withConfig({
20
+ displayName: "Checkboxstyles__CheckboxInner",
21
+ componentId: "sc-10i9aa0-3"
22
+ })(["position:relative;display:block;width:16px;height:16px;box-sizing:border-box;background-color:", ";border:1px solid ", ";border-radius:3px;background-repeat:no-repeat;background-position:center;background-size:contain;", " ", " ", " ", " ", ""], (props) => props.theme.palette.white, (props) => props.theme.palette["grey-300"], (props) => props.$checked && css(["background-color:", ";border-color:", ";background-image:url('", "');"], props.theme.palette["blue-600"], props.theme.palette["blue-600"], checkSvgWithCustomColor(props.theme.palette.white)), (props) => props.$indeterminate && css(["background-color:", ";border-color:", ";background-image:none;&::after{content:'';position:absolute;top:50%;left:50%;width:8px;height:2px;background:", ";border-radius:2px;transform:translate(-50%,-50%);}"], props.theme.palette["blue-600"], props.theme.palette["blue-600"], props.theme.palette.white), (props) => props.$error && css(["border-color:", ";border-width:2px;"], props.theme.palette["red-600"]), (props) => props.$error && props.$checked && css(["border-color:", ";"], props.theme.palette["blue-600"]), (props) => props.$disabled && css(["border-color:", " !important;background-color:", " !important;", ""], props.theme.palette["grey-200"], props.theme.palette["grey-050"], props.$checked && `background-image: url('${checkSvgWithCustomColor(props.theme.palette["grey-400"])}');`));
23
+ const CheckboxText = /* @__PURE__ */ styled.span.withConfig({
24
+ displayName: "Checkboxstyles__CheckboxText",
25
+ componentId: "sc-10i9aa0-4"
26
+ })(["margin:0;padding-left:12px;font-size:14px;font-weight:500;color:", ";", ""], (props) => props.$checked ? props.theme.palette["grey-800"] : props.theme.palette["grey-700"], (props) => props.$disabled && css(["color:", ";opacity:0.4;"], props.theme.palette["grey-600"]));
27
+ const CheckboxBox = /* @__PURE__ */ styled.span.withConfig({
28
+ displayName: "Checkboxstyles__CheckboxBox",
29
+ componentId: "sc-10i9aa0-5"
30
+ })(["position:relative;top:0;display:inline-flex;flex:none;cursor:pointer;"]);
31
+ const CheckboxLabel = /* @__PURE__ */ styled.label.withConfig({
32
+ displayName: "Checkboxstyles__CheckboxLabel",
33
+ componentId: "sc-10i9aa0-6"
34
+ })(["display:flex;align-items:center;line-height:1;margin:0;cursor:pointer;", ";&:hover ", "{color:", ";}", " ", " ", ":focus + ", "{border-color:", ";box-shadow:inset 0 0 0 1px ", ";}", " ", ""], (props) => props.$solo && soloCss, CheckboxText, (props) => props.theme.palette["grey-800"], (props) => !props.$checked && !props.$indeterminate && !props.$disabled && css(["&:hover ", "{border-color:", ";background-image:url('", "');}"], CheckboxInner, props.theme.palette["blue-600"], checkSvgWithCustomColor(props.theme.palette["blue-600"])), (props) => props.$indeterminate && css(["&:hover ", "{background-color:", ";}"], CheckboxInner, props.theme.palette["blue-500"]), CheckboxInput, CheckboxInner, (props) => props.theme.palette["blue-600"], (props) => props.theme.palette["blue-600"], (props) => props.$error && css(["", ":focus + ", "{box-shadow:0 0 0 1px ", ";}"], CheckboxInput, CheckboxInner, props.theme.palette["red-600"]), (props) => props.$disabled && css(["cursor:not-allowed;", ",", "{cursor:not-allowed;}"], CheckboxBox, CheckboxInput));
21
35
  export {
22
36
  AdditionalData,
23
- AntdCheckbox,
37
+ CheckboxBox,
38
+ CheckboxInner,
39
+ CheckboxInput,
40
+ CheckboxLabel,
41
+ CheckboxText,
24
42
  CheckboxWrapper
25
43
  };
@@ -1,30 +1,76 @@
1
- import { AbstractCheckboxProps, CheckboxProps as AntCheckboxProps } from 'antd/lib/checkbox/Checkbox';
2
- import { ReactNode } from 'react';
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ export type CheckboxValueType = string | number | boolean;
3
3
  export type BaseCheckboxProps = {
4
4
  description?: ReactNode;
5
- errorText?: string;
5
+ errorText?: ReactNode;
6
6
  hasError?: boolean;
7
7
  withoutPadding?: boolean;
8
8
  };
9
- export type CheckboxTristateChangeEventTarget = CheckboxTristateProps & {
9
+ /** antd-compatible change event shape (`target.checked` is a boolean for the base checkbox). */
10
+ export type CheckboxChangeEventTarget = {
11
+ type: 'checkbox';
12
+ checked: boolean;
13
+ value?: CheckboxValueType;
14
+ name?: string;
15
+ [key: string]: unknown;
16
+ };
17
+ export type CheckboxChangeEvent = {
18
+ target: CheckboxChangeEventTarget;
19
+ stopPropagation: () => void;
20
+ preventDefault: () => void;
21
+ nativeEvent: Event;
22
+ };
23
+ /** Tristate event — `target.checked` may be `undefined` (the indeterminate state). */
24
+ export type CheckboxTristateChangeEventTarget = Omit<CheckboxChangeEventTarget, 'checked'> & {
10
25
  checked: boolean | undefined;
11
- onChange?: (e: CheckboxTristateChangeEvent) => void;
12
26
  };
13
27
  export type CheckboxTristateChangeEvent = {
14
28
  target: CheckboxTristateChangeEventTarget;
15
29
  stopPropagation: () => void;
16
30
  preventDefault: () => void;
17
- nativeEvent: MouseEvent;
31
+ nativeEvent: Event;
32
+ };
33
+ type CommonCheckboxProps = {
34
+ checked?: boolean;
35
+ defaultChecked?: boolean;
36
+ indeterminate?: boolean;
37
+ disabled?: boolean;
38
+ value?: CheckboxValueType;
39
+ name?: string;
40
+ id?: string;
41
+ autoFocus?: boolean;
42
+ tabIndex?: number;
43
+ className?: string;
44
+ style?: CSSProperties;
45
+ children?: ReactNode;
46
+ /** Forwarded to the underlying <input> (e.g. data-testid), matching antd's rc-checkbox. */
47
+ [dataAttr: `data-${string}`]: string;
18
48
  };
19
49
  type OnChangeBaseProps = {
20
50
  tristate?: never | false | undefined;
21
- onChange?: AntCheckboxProps['onChange'];
51
+ onChange?: (event: CheckboxChangeEvent) => void;
22
52
  };
23
53
  type OnChangeTristateProps = {
24
54
  tristate: true;
25
- onChange?: AbstractCheckboxProps<CheckboxTristateChangeEvent>['onChange'];
55
+ onChange?: (event: CheckboxTristateChangeEvent) => void;
26
56
  };
27
- export type CheckboxBaseProps = Omit<AntCheckboxProps, 'onChange'> & BaseCheckboxProps & OnChangeBaseProps;
28
- export type CheckboxTristateProps = Omit<AntCheckboxProps, 'onChange'> & BaseCheckboxProps & OnChangeTristateProps;
57
+ export type CheckboxBaseProps = CommonCheckboxProps & BaseCheckboxProps & OnChangeBaseProps;
58
+ export type CheckboxTristateProps = CommonCheckboxProps & BaseCheckboxProps & OnChangeTristateProps;
29
59
  export type CheckboxProps = CheckboxBaseProps | CheckboxTristateProps;
60
+ export type CheckboxOptionType = {
61
+ label: ReactNode;
62
+ value: CheckboxValueType;
63
+ disabled?: boolean;
64
+ };
65
+ export type CheckboxGroupProps = {
66
+ value?: CheckboxValueType[];
67
+ defaultValue?: CheckboxValueType[];
68
+ onChange?: (checkedValues: CheckboxValueType[]) => void;
69
+ options?: (CheckboxValueType | CheckboxOptionType)[];
70
+ disabled?: boolean;
71
+ name?: string;
72
+ className?: string;
73
+ style?: CSSProperties;
74
+ children?: ReactNode;
75
+ };
30
76
  export {};
@@ -0,0 +1,15 @@
1
+ import { CheckboxValueType } from './Checkbox.types';
2
+ export type CheckboxGroupContextValue = {
3
+ /** Currently checked values. */
4
+ value: CheckboxValueType[];
5
+ /** Toggle a value in/out of the checked set. */
6
+ toggleOption: (value: CheckboxValueType) => void;
7
+ /** Register a child value (in mount order) so onChange keeps child order. */
8
+ registerValue: (value: CheckboxValueType) => void;
9
+ /** Unregister a child value on unmount. */
10
+ unregisterValue: (value: CheckboxValueType) => void;
11
+ disabled?: boolean;
12
+ name?: string;
13
+ };
14
+ /** Provided by `Checkbox.Group`; consumed by child `Checkbox`es. `null` when standalone. */
15
+ export declare const CheckboxGroupContext: import('react').Context<CheckboxGroupContextValue | null>;
@@ -0,0 +1,5 @@
1
+ import { createContext } from "react";
2
+ const CheckboxGroupContext = createContext(null);
3
+ export {
4
+ CheckboxGroupContext
5
+ };
@@ -0,0 +1,9 @@
1
+ import { default as React } from 'react';
2
+ import { CheckboxGroupProps } from './Checkbox.types';
3
+ /**
4
+ * DS-native replacement for antd's `Checkbox.Group`. Provides a context that child `Checkbox`es read
5
+ * (checked state + toggle) and emits `onChange` with the checked values ordered by child mount order
6
+ * (or `options` order). Controlled via `value`, uncontrolled via `defaultValue`.
7
+ */
8
+ declare const CheckboxGroup: ({ value, defaultValue, onChange, options, disabled, name, children, className, style, }: CheckboxGroupProps) => React.JSX.Element;
9
+ export default CheckboxGroup;
@@ -0,0 +1,62 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useState, useRef, useCallback, useMemo } from "react";
3
+ import styled from "styled-components";
4
+ import { CheckboxGroupContext } from "./CheckboxContext.js";
5
+ import { CheckboxBase } from "./components/CheckboxBase.js";
6
+ import { cx } from "./utils/cx.js";
7
+ const GroupWrapper = /* @__PURE__ */ styled.div.withConfig({
8
+ displayName: "CheckboxGroup__GroupWrapper",
9
+ componentId: "sc-1a8ubty-0"
10
+ })(["display:inline-block;"]);
11
+ const CheckboxGroup = ({
12
+ value,
13
+ defaultValue = [],
14
+ onChange,
15
+ options,
16
+ disabled,
17
+ name,
18
+ children,
19
+ className,
20
+ style
21
+ }) => {
22
+ const isControlled = value !== void 0;
23
+ const [internalValue, setInternalValue] = useState(defaultValue);
24
+ const resolvedValue = isControlled ? value : internalValue;
25
+ const registeredRef = useRef([]);
26
+ const registerValue = useCallback((optionValue) => {
27
+ if (!registeredRef.current.includes(optionValue)) {
28
+ registeredRef.current = [...registeredRef.current, optionValue];
29
+ }
30
+ }, []);
31
+ const unregisterValue = useCallback((optionValue) => {
32
+ registeredRef.current = registeredRef.current.filter((registered) => registered !== optionValue);
33
+ }, []);
34
+ const toggleOption = useCallback((optionValue) => {
35
+ const isCurrentlyChecked = resolvedValue.includes(optionValue);
36
+ const nextSet = isCurrentlyChecked ? resolvedValue.filter((v) => v !== optionValue) : [...resolvedValue, optionValue];
37
+ const order = options ? options.map((option) => typeof option === "object" ? option.value : option) : registeredRef.current;
38
+ const ordered = order.filter((v) => nextSet.includes(v));
39
+ const extras = nextSet.filter((v) => !order.includes(v));
40
+ const result = [...ordered, ...extras];
41
+ if (!isControlled) {
42
+ setInternalValue(result);
43
+ }
44
+ onChange?.(result);
45
+ }, [resolvedValue, isControlled, onChange, options]);
46
+ const contextValue = useMemo(() => ({
47
+ value: resolvedValue,
48
+ toggleOption,
49
+ registerValue,
50
+ unregisterValue,
51
+ disabled,
52
+ name
53
+ }), [resolvedValue, toggleOption, registerValue, unregisterValue, disabled, name]);
54
+ const normalizedOptions = options?.map((option) => typeof option === "object" ? option : {
55
+ label: String(option),
56
+ value: option
57
+ });
58
+ return /* @__PURE__ */ jsx(CheckboxGroupContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(GroupWrapper, { className: cx("ant-checkbox-group", "ds-checkbox-group", className), style, children: normalizedOptions ? normalizedOptions.map((option) => /* @__PURE__ */ jsx(CheckboxBase, { value: option.value, disabled: option.disabled, children: option.label }, String(option.value))) : children }) });
59
+ };
60
+ export {
61
+ CheckboxGroup as default
62
+ };
@@ -1,3 +1,3 @@
1
1
  import { default as React } from 'react';
2
2
  import { CheckboxBaseProps } from '../Checkbox.types';
3
- export declare const CheckboxBase: ({ description, errorText, children, withoutPadding, hasError, ...antdCheckboxProps }: CheckboxBaseProps) => React.JSX.Element;
3
+ export declare const CheckboxBase: ({ description, errorText, children, withoutPadding, hasError, checked, defaultChecked, indeterminate, disabled, onChange, tristate, value, name, id, autoFocus, tabIndex, className, style, ...rest }: CheckboxBaseProps) => React.JSX.Element;
@@ -1,19 +1,90 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useContext, useRef, useState, useEffect } from "react";
2
3
  import { ErrorText, Description } from "@synerise/ds-typography";
3
- import { CheckboxWrapper, AntdCheckbox, AdditionalData } from "../Checkbox.styles.js";
4
+ import { CheckboxWrapper, CheckboxLabel, CheckboxBox, CheckboxInput, CheckboxInner, CheckboxText, AdditionalData } from "../Checkbox.styles.js";
5
+ import { CheckboxGroupContext } from "../CheckboxContext.js";
6
+ import { cx } from "../utils/cx.js";
4
7
  const CheckboxBase = ({
5
8
  description,
6
9
  errorText,
7
10
  children,
8
11
  withoutPadding,
9
12
  hasError,
10
- ...antdCheckboxProps
13
+ checked,
14
+ defaultChecked,
15
+ indeterminate,
16
+ disabled,
17
+ onChange,
18
+ // discriminant for the tristate union — consumed here so it never leaks onto the input via ...rest
19
+ tristate,
20
+ value,
21
+ name,
22
+ id,
23
+ autoFocus,
24
+ tabIndex,
25
+ className,
26
+ style,
27
+ // forward data-*/aria-* (e.g. data-testid) to the input, as antd's rc-checkbox did
28
+ ...rest
11
29
  }) => {
12
- return /* @__PURE__ */ jsxs(CheckboxWrapper, { className: "ds-checkbox", withoutPadding: Boolean(withoutPadding), children: [
13
- /* @__PURE__ */ jsx(AntdCheckbox, { ...antdCheckboxProps, className: hasError || errorText ? "error" : void 0, $solo: !children && !errorText && !description, children }),
30
+ const group = useContext(CheckboxGroupContext);
31
+ const inputRef = useRef(null);
32
+ const isControlled = checked !== void 0;
33
+ const [internalChecked, setInternalChecked] = useState(Boolean(defaultChecked));
34
+ const isChecked = group ? group.value.includes(value) : isControlled ? Boolean(checked) : internalChecked;
35
+ const isDisabled = Boolean(disabled ?? group?.disabled);
36
+ const hasErr = Boolean(hasError || errorText);
37
+ const isSolo = !children && !errorText && !description;
38
+ useEffect(() => {
39
+ if (!group || value === void 0) {
40
+ return void 0;
41
+ }
42
+ group.registerValue(value);
43
+ return () => group.unregisterValue(value);
44
+ }, [value]);
45
+ useEffect(() => {
46
+ if (inputRef.current) {
47
+ inputRef.current.indeterminate = Boolean(indeterminate);
48
+ }
49
+ }, [indeterminate]);
50
+ const handleChange = (event) => {
51
+ if (isDisabled) {
52
+ return;
53
+ }
54
+ const nextChecked = event.target.checked;
55
+ if (!group && !isControlled) {
56
+ setInternalChecked(nextChecked);
57
+ }
58
+ if (group && value !== void 0) {
59
+ group.toggleOption(value);
60
+ }
61
+ const changeEvent = {
62
+ // `type: 'checkbox'` mirrors antd/rc-checkbox's event target — consumers that read
63
+ // `event.target.type` (e.g. react-final-form's getValue) need it to treat the value as a
64
+ // boolean from `checked`; without it they fall back to `target.value` and the field never updates.
65
+ target: {
66
+ type: "checkbox",
67
+ value,
68
+ name: name ?? group?.name,
69
+ checked: nextChecked
70
+ },
71
+ stopPropagation: () => event.stopPropagation(),
72
+ preventDefault: () => event.preventDefault(),
73
+ nativeEvent: event.nativeEvent
74
+ };
75
+ onChange?.(changeEvent);
76
+ };
77
+ return /* @__PURE__ */ jsxs(CheckboxWrapper, { className: cx("ds-checkbox", className), style, withoutPadding: Boolean(withoutPadding), children: [
78
+ /* @__PURE__ */ jsxs(CheckboxLabel, { className: cx("ant-checkbox-wrapper", "ds-checkbox-wrapper", hasErr && "error", isDisabled && "ant-checkbox-wrapper-disabled", isDisabled && "ds-checkbox-disabled"), $solo: isSolo, $checked: isChecked, $indeterminate: Boolean(indeterminate), $disabled: isDisabled, $error: hasErr, children: [
79
+ /* @__PURE__ */ jsxs(CheckboxBox, { className: cx("ant-checkbox", "ds-checkbox-box", isChecked && "ant-checkbox-checked", indeterminate && "ant-checkbox-indeterminate", isDisabled && "ant-checkbox-disabled"), children: [
80
+ /* @__PURE__ */ jsx(CheckboxInput, { ref: inputRef, type: "checkbox", className: "ant-checkbox-input ds-checkbox-input", checked: isChecked, disabled: isDisabled, name: name ?? group?.name, id, autoFocus, tabIndex, onChange: handleChange, ...rest }),
81
+ /* @__PURE__ */ jsx(CheckboxInner, { className: "ant-checkbox-inner ds-checkbox-inner", $checked: isChecked, $indeterminate: Boolean(indeterminate), $disabled: isDisabled, $error: hasErr })
82
+ ] }),
83
+ children !== void 0 && children !== null && children !== false && /* @__PURE__ */ jsx(CheckboxText, { $checked: isChecked, $disabled: isDisabled, children })
84
+ ] }),
14
85
  (errorText || description) && /* @__PURE__ */ jsxs(AdditionalData, { children: [
15
86
  errorText && /* @__PURE__ */ jsx(ErrorText, { children: errorText }),
16
- description && /* @__PURE__ */ jsx(Description, { disabled: antdCheckboxProps.disabled, children: description })
87
+ description && /* @__PURE__ */ jsx(Description, { disabled: isDisabled, children: description })
17
88
  ] })
18
89
  ] });
19
90
  };
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { Checkbox } from "./Checkbox.js";
2
2
  import { checkedValue } from "./utils/checkedValue.js";
3
+ import { cx } from "./utils/cx.js";
3
4
  import { isTristateCheckbox } from "./utils/isTristateCheckbox.js";
4
5
  import { nextCheckedValues } from "./utils/nextCheckedValues.js";
5
6
  export {
6
7
  checkedValue,
8
+ cx,
7
9
  Checkbox as default,
8
10
  isTristateCheckbox,
9
11
  nextCheckedValues
@@ -0,0 +1 @@
1
+ export declare const cx: (...classes: (string | false | undefined)[]) => string;
@@ -0,0 +1,4 @@
1
+ const cx = (...classes) => classes.filter(Boolean).join(" ");
2
+ export {
3
+ cx
4
+ };
@@ -1,3 +1,4 @@
1
1
  export { checkedValue } from './checkedValue';
2
+ export { cx } from './cx';
2
3
  export { isTristateCheckbox } from './isTristateCheckbox';
3
4
  export { nextCheckedValues } from './nextCheckedValues';
@@ -1,8 +1,10 @@
1
1
  import { checkedValue } from "./checkedValue.js";
2
+ import { cx } from "./cx.js";
2
3
  import { isTristateCheckbox } from "./isTristateCheckbox.js";
3
4
  import { nextCheckedValues } from "./nextCheckedValues.js";
4
5
  export {
5
6
  checkedValue,
7
+ cx,
6
8
  isTristateCheckbox,
7
9
  nextCheckedValues
8
10
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synerise/ds-checkbox",
3
- "version": "1.2.34",
3
+ "version": "1.2.36",
4
4
  "description": "Checkbox UI Component for the Synerise Design System",
5
5
  "license": "ISC",
6
6
  "repository": "synerise/synerise-design",
@@ -17,6 +17,7 @@
17
17
  "files": [
18
18
  "/dist",
19
19
  "CHANGELOG.md",
20
+ "CLAUDE.md",
20
21
  "README.md",
21
22
  "package.json",
22
23
  "LICENSE.md"
@@ -40,16 +41,15 @@
40
41
  "*.less"
41
42
  ],
42
43
  "dependencies": {
43
- "@synerise/ds-typography": "^1.1.26"
44
+ "@synerise/ds-typography": "^1.1.27"
44
45
  },
45
46
  "devDependencies": {
46
47
  "vitest": "4"
47
48
  },
48
49
  "peerDependencies": {
49
50
  "@synerise/ds-core": "*",
50
- "antd": "4.24.16",
51
51
  "react": ">=16.9.0 <= 18.3.1",
52
52
  "styled-components": "^5.3.3"
53
53
  },
54
- "gitHead": "d8c64070f58f14e3fb1bfbcbf00d1e3b8fd51eb8"
54
+ "gitHead": "d0a43cc43d8528a36f105aceea52ab470edb71d9"
55
55
  }
File without changes
@@ -1 +0,0 @@
1
- @keyframes antCheckboxEffect{0%{transform:scale(1);opacity:.5}100%{transform:scale(1.6);opacity:0}}.ant-checkbox{box-sizing:border-box;margin:0;padding:0;color:#6a7580;font-size:13px;font-variant:tabular-nums;line-height:1.38;list-style:none;font-feature-settings:'tnum';position:relative;top:.2em;line-height:1;white-space:nowrap;outline:0;cursor:pointer}.ant-checkbox-input:focus+.ant-checkbox-inner,.ant-checkbox-wrapper:hover .ant-checkbox-inner,.ant-checkbox:hover .ant-checkbox-inner{border-color:#0b68ff}.ant-checkbox-checked::after{position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid #0b68ff;border-radius:3px;visibility:hidden;animation:antCheckboxEffect .36s ease-in-out;animation-fill-mode:backwards;content:''}.ant-checkbox-wrapper:hover .ant-checkbox::after,.ant-checkbox:hover::after{visibility:visible}.ant-checkbox-inner{position:relative;top:0;left:0;display:block;width:16px;height:16px;direction:ltr;background-color:#fff;border:1px solid #dbe0e3;border-radius:3px;border-collapse:separate;transition:all .3s}.ant-checkbox-inner::after{position:absolute;top:50%;left:21.5%;display:table;width:5.71428571px;height:9.14285714px;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(0) translate(-50%,-50%);opacity:0;transition:all .1s cubic-bezier(.71, -.46, .88, .6),opacity .1s;content:' '}.ant-checkbox-input{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;width:100%;height:100%;cursor:pointer;opacity:0}.ant-checkbox-checked .ant-checkbox-inner::after{position:absolute;display:table;border:2px solid #fff;border-top:0;border-left:0;transform:rotate(45deg) scale(1) translate(-50%,-50%);opacity:1;transition:all .2s cubic-bezier(.12, .4, .29, 1.46) .1s;content:' '}.ant-checkbox-checked .ant-checkbox-inner{background-color:#0b68ff;border-color:#0b68ff}.ant-checkbox-disabled{cursor:not-allowed}.ant-checkbox-disabled.ant-checkbox-checked .ant-checkbox-inner::after{border-color:#b5bdc3;animation-name:none}.ant-checkbox-disabled .ant-checkbox-input{cursor:not-allowed;pointer-events:none}.ant-checkbox-disabled .ant-checkbox-inner{background-color:#f9fafb;border-color:#dbe0e3!important}.ant-checkbox-disabled .ant-checkbox-inner::after{border-color:#f9fafb;border-collapse:separate;animation-name:none}.ant-checkbox-disabled+span{color:#b5bdc3;cursor:not-allowed}.ant-checkbox-disabled:hover::after,.ant-checkbox-wrapper:hover .ant-checkbox-disabled::after{visibility:hidden}.ant-checkbox-wrapper{box-sizing:border-box;margin:0;padding:0;color:#6a7580;font-size:13px;font-variant:tabular-nums;line-height:1.38;list-style:none;font-feature-settings:'tnum';display:inline-flex;align-items:baseline;line-height:unset;cursor:pointer}.ant-checkbox-wrapper::after{display:inline-block;width:0;overflow:hidden;content:'\a0'}.ant-checkbox-wrapper.ant-checkbox-wrapper-disabled{cursor:not-allowed}.ant-checkbox-wrapper+.ant-checkbox-wrapper{margin-left:8px}.ant-checkbox-wrapper.ant-checkbox-wrapper-in-form-item input[type=checkbox]{width:14px;height:14px}.ant-checkbox+span{padding-right:8px;padding-left:8px}.ant-checkbox-group{box-sizing:border-box;margin:0;padding:0;color:#6a7580;font-size:13px;font-variant:tabular-nums;line-height:1.38;list-style:none;font-feature-settings:'tnum';display:inline-block}.ant-checkbox-group-item{margin-right:8px}.ant-checkbox-group-item:last-child{margin-right:0}.ant-checkbox-group-item+.ant-checkbox-group-item{margin-left:0}.ant-checkbox-indeterminate .ant-checkbox-inner{background-color:#fff;border-color:#dbe0e3}.ant-checkbox-indeterminate .ant-checkbox-inner::after{top:50%;left:50%;width:8px;height:8px;background-color:#0b68ff;border:0;transform:translate(-50%,-50%) scale(1);opacity:1;content:' '}.ant-checkbox-indeterminate.ant-checkbox-disabled .ant-checkbox-inner::after{background-color:#b5bdc3;border-color:#b5bdc3}.ant-checkbox-rtl{direction:rtl}.ant-checkbox-group-rtl .ant-checkbox-group-item{margin-right:0;margin-left:8px}.ant-checkbox-group-rtl .ant-checkbox-group-item:last-child{margin-left:0!important}.ant-checkbox-group-rtl .ant-checkbox-group-item+.ant-checkbox-group-item{margin-left:8px}.ant-checkbox-inner.ant-checkbox-inner{transition:unset}.ant-checkbox-inner.ant-checkbox-inner:after{transition:unset}.ant-checkbox-wrapper{transition:unset}.ant-checkbox-wrapper *{transition:unset}.ant-checkbox+span{margin:0;padding-left:12px;font-size:14px;color:#57616d;font-weight:500;position:relative}.ant-checkbox-wrapper:hover .ant-checkbox+span{color:#384350}.ant-checkbox-wrapper:after{display:none}.ant-checkbox-wrapper.error .ant-checkbox-inner{border-color:#f52922!important;border-width:2px;box-shadow:0 2px 4px 0 rgba(181,189,195,.2)}.ant-checkbox-wrapper.error .ant-checkbox-input:focus+.ant-checkbox-inner{box-shadow:0 0 0 1px #f52922}.ant-checkbox-wrapper.error .ant-checkbox-checked .ant-checkbox-inner{border-color:#0b68ff!important}.ant-checkbox-wrapper.error .ant-checkbox-checked .ant-checkbox-input:hover+.ant-checkbox-inner{border-color:#238afe;background-color:#238afe}.ant-checkbox-wrapper.error .ant-checkbox-checked .ant-checkbox-input:focus+.ant-checkbox-inner{border-color:#0b68ff;background-color:#238afe;box-shadow:0 0 0 1px #0b68ff}.ant-checkbox-wrapper.error .ant-checkbox-checked .ant-checkbox-input:focus+.ant-checkbox-inner:after{left:20%}.ant-checkbox-input:hover+.ant-checkbox-inner{border-color:#b5bdc3}.ant-checkbox-input:focus+.ant-checkbox-inner{border-color:#0b68ff;background-color:#f4faff;border-width:2px}.ant-checkbox-wrapper-disabled .ant-checkbox+span{color:#6a7580;opacity:.4}.ant-checkbox-disabled .ant-checkbox-inner{border-color:#e9edee!important;background-color:#f9fafb!important}.ant-checkbox-checked .ant-checkbox-input:hover+.ant-checkbox-inner{border-color:#238afe;background-color:#238afe}.ant-checkbox-checked .ant-checkbox-input:focus+.ant-checkbox-inner{border-color:#0b68ff;background-color:#238afe}.ant-checkbox-checked .ant-checkbox-input:focus+.ant-checkbox-inner:after{left:20%}.ant-checkbox-checked+span{color:#384350}.ant-checkbox-indeterminate .ant-checkbox-inner::after{border-radius:2px}