@synerise/ds-radio 1.1.16 → 1.1.18
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 +8 -0
- package/CLAUDE.md +109 -0
- package/dist/Radio.d.ts +7 -5
- package/dist/Radio.js +6 -26
- package/dist/Radio.styles.d.ts +25 -3
- package/dist/Radio.styles.js +46 -15
- package/dist/Radio.types.d.ts +69 -13
- package/dist/RadioContext.d.ts +17 -0
- package/dist/RadioContext.js +5 -0
- package/dist/RadioGroup.d.ts +9 -0
- package/dist/RadioGroup.js +61 -0
- package/dist/components/RadioBase.d.ts +3 -0
- package/dist/components/RadioBase.js +66 -0
- package/dist/components/RadioButton.d.ts +10 -0
- package/dist/components/RadioButton.js +49 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +6 -0
- package/dist/index.d.ts +1 -1
- package/package.json +6 -5
- package/dist/assets/style/index-tn0RQdqM.css +0 -0
- package/dist/style/index.css +0 -3
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.1.18](https://github.com/synerise/synerise-design/compare/@synerise/ds-radio@1.1.17...@synerise/ds-radio@1.1.18) (2026-07-23)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @synerise/ds-radio
|
|
9
|
+
|
|
10
|
+
## [1.1.17](https://github.com/synerise/synerise-design/compare/@synerise/ds-radio@1.1.16...@synerise/ds-radio@1.1.17) (2026-06-27)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @synerise/ds-radio
|
|
13
|
+
|
|
6
14
|
## [1.1.16](https://github.com/synerise/synerise-design/compare/@synerise/ds-radio@1.1.15...@synerise/ds-radio@1.1.16) (2026-06-17)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @synerise/ds-radio
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Radio (`@synerise/ds-radio`)
|
|
2
|
+
|
|
3
|
+
> DS-native, antd-free radio: a `label` prop (renders via `FormFieldLabel`), a `description` below the radio, a context-based `Radio.Group`, a segmented `Radio.Button`, and group-level `fullWidth`/`big` layout variants.
|
|
4
|
+
|
|
5
|
+
## Package structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/
|
|
9
|
+
Radio.tsx — assembles Radio (= RadioBase) + .Group + .Button
|
|
10
|
+
Radio.types.ts — RadioProps, RadioGroupProps, RadioButtonProps, RadioChangeEvent, RadioValueType
|
|
11
|
+
Radio.styles.tsx — styled-components (RadioLabel = radio-dot visual; RadioGroupWrapper = layout + segmented buttons)
|
|
12
|
+
RadioGroup.tsx — DS-native Radio.Group (single-select context provider)
|
|
13
|
+
RadioContext.ts — group context (value + onChange)
|
|
14
|
+
components/
|
|
15
|
+
RadioBase.tsx — the radio input (DOM + group consumption + event synthesis)
|
|
16
|
+
RadioButton.tsx — segmented button-style radio
|
|
17
|
+
index.ts — public exports
|
|
18
|
+
__specs__/Radio.spec.tsx — Vitest tests
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
No LESS, no antd — antd's base + `radio.mixin.less` were inlined into `Radio.styles.tsx`.
|
|
22
|
+
|
|
23
|
+
## Public exports
|
|
24
|
+
|
|
25
|
+
### `Radio` (default export)
|
|
26
|
+
|
|
27
|
+
Compound component: `Radio` + `Radio.Group` + `Radio.Button`.
|
|
28
|
+
|
|
29
|
+
| Prop | Type | Default | Description |
|
|
30
|
+
|------|------|---------|-------------|
|
|
31
|
+
| `label` | `ReactNode` | `undefined` | Renders label text via `FormFieldLabel`. Takes precedence over `children` |
|
|
32
|
+
| `description` | `ReactNode` | `undefined` | Additional text rendered below the radio in small grey text |
|
|
33
|
+
| `children` | `ReactNode` | `undefined` | **@deprecated** — use `label` instead. Only rendered when `label` is not provided |
|
|
34
|
+
| `checked` | `boolean` | `undefined` | Controlled checked state |
|
|
35
|
+
| `defaultChecked` | `boolean` | `undefined` | Initial uncontrolled checked state |
|
|
36
|
+
| `disabled` | `boolean` | `undefined` | Disables the radio; also dims `label` and `description` to 40% opacity |
|
|
37
|
+
| `value` | `any` | `undefined` | Value used by `Radio.Group` for comparison |
|
|
38
|
+
| `autoFocus` | `boolean` | `undefined` | Focuses the input on mount |
|
|
39
|
+
| `value`, `name`, `id`, `autoFocus`, `tabIndex`, `onChange` | — | — | DS-native props (no antd inheritance). `onChange` receives a `RadioChangeEvent` (`target.value`, `target.checked`). |
|
|
40
|
+
|
|
41
|
+
### `Radio.Group`
|
|
42
|
+
|
|
43
|
+
Wraps `AntdRadio.Group` with two additional layout props:
|
|
44
|
+
|
|
45
|
+
| Prop | Type | Default | Description |
|
|
46
|
+
|------|------|---------|-------------|
|
|
47
|
+
| `fullWidth` | `boolean` | `undefined` | Makes the group `display: flex; width: 100%` — each radio button gets `flex: 1` |
|
|
48
|
+
| `big` | `boolean` | `undefined` | When combined with `fullWidth`, sets button height to `48px` instead of `32px` |
|
|
49
|
+
| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Segmented `Radio.Button` height: `small` 24px · `middle` 32px · `large` 40px |
|
|
50
|
+
| + DS `RadioGroupProps` | — | — | `value`, `defaultValue`, `onChange`, `options`, `optionType`, `buttonStyle`, `disabled`, `name` (DS-native, no antd inheritance) |
|
|
51
|
+
|
|
52
|
+
### `Radio.Button`
|
|
53
|
+
|
|
54
|
+
DS-native segmented button-style radio (replaces the former `AntdRadio.Button` re-export). Reads the `Radio.Group` context; styled by the group as a connected segment. Use for segmented/toggle-button radio groups (`optionType="button"` or explicit `<Radio.Button>` children).
|
|
55
|
+
|
|
56
|
+
### Types exported
|
|
57
|
+
|
|
58
|
+
| Type | Description |
|
|
59
|
+
|------|-------------|
|
|
60
|
+
| `RadioProps` | Props for `Radio` |
|
|
61
|
+
| `RadioGroupProps` | Props for `Radio.Group` |
|
|
62
|
+
| `Props` | **@deprecated** alias for `RadioProps` |
|
|
63
|
+
|
|
64
|
+
## Usage patterns
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import Radio from '@synerise/ds-radio';
|
|
68
|
+
|
|
69
|
+
// Basic radio with label and description
|
|
70
|
+
<Radio.Group value={selected} onChange={(e) => setSelected(e.target.value)}>
|
|
71
|
+
<Radio value="a" label="Option A" description="Some extra context" />
|
|
72
|
+
<Radio value="b" label="Option B" />
|
|
73
|
+
</Radio.Group>
|
|
74
|
+
|
|
75
|
+
// Full-width button group
|
|
76
|
+
<Radio.Group value={tab} onChange={(e) => setTab(e.target.value)} fullWidth big>
|
|
77
|
+
<Radio.Button value="list">List</Radio.Button>
|
|
78
|
+
<Radio.Button value="grid">Grid</Radio.Button>
|
|
79
|
+
</Radio.Group>
|
|
80
|
+
|
|
81
|
+
// Shorthand options
|
|
82
|
+
<Radio.Group options={['A', 'B', 'C']} value={val} onChange={handleChange} />
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Styling
|
|
86
|
+
|
|
87
|
+
Styles live in `Radio.styles.tsx`. **Each element is its own styled-component and owns its styles** — the `.ant-radio-*` / `ds-radio-*` 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. Uses `@synerise/ds-core` theme tokens:
|
|
88
|
+
- `grey-600` — `Description` text colour; `opacity: 0.4` applied on `disabled` to `Label`/`Description`/`RadioText`
|
|
89
|
+
- `Label` extends `FormFieldLabel` from `@synerise/ds-form-field`
|
|
90
|
+
- radio dot: `RadioBox` / `RadioInput` / `RadioInner` / `RadioText`. `RadioInner` is the 16px circle (`grey-300` border, blue-600 dot scaled in on `$checked`, greyed on `$disabled`); `RadioLabel` holds the cross-element hover-preview + focus-ring rules (`${RadioInput}:focus + ${RadioInner}`, white centre once `$checked`).
|
|
91
|
+
- segmented button: `RadioButtonLabel` (+ `RadioButtonInput`) owns the full segment visual including the connected-border `:first-child`/`:last-child` rules and the `$solid`/`$checked`/`$disabled` variants — driven by `$`-props read from the group context, not by group-level `.ant-radio-button-*` selectors.
|
|
92
|
+
- `RadioGroupWrapper` is `inline-block` (vertical stacking) and, with `fullWidth`, switches to flex and stretches `${RadioLabel}`/`${RadioButtonLabel}` (`big` → 48px height).
|
|
93
|
+
- `AdditionalData` is the margin wrapper for `Description`
|
|
94
|
+
|
|
95
|
+
All styling is in `Radio.styles.tsx` (no LESS).
|
|
96
|
+
|
|
97
|
+
## Key dependencies
|
|
98
|
+
|
|
99
|
+
- DS-native (no antd) — radio + `Radio.Group` (context) + `Radio.Button` reimplemented in `src/`
|
|
100
|
+
- `@synerise/ds-form-field` — `FormFieldLabel` used for the `label` prop rendering
|
|
101
|
+
- `@synerise/ds-typography` — `macro.small` applied to `Description` font size
|
|
102
|
+
|
|
103
|
+
## Implementation notes
|
|
104
|
+
|
|
105
|
+
- **`label` vs `children`**: `label` takes precedence — if `label` is set, `children` is ignored entirely. `children` is marked `@deprecated` in the type file.
|
|
106
|
+
- **`Radio.Button` is DS-native**: reads `RadioContext` for checked state; the segment visual (connected borders, checked, focus, `buttonStyle` solid/outline) is styled by `RadioGroupWrapper`.
|
|
107
|
+
- **`RadioChangeEvent`** is synthesised from the native input change (`{ target: { value, checked, name }, stopPropagation, preventDefault, nativeEvent }`); `target.value` is `RadioValueType` (consumers needing a narrower type cast it — antd typed it `any`).
|
|
108
|
+
- **`AdditionalData` styled-component** is marked `@deprecated` in its source comment but is still the live wrapper div for `Description` — the comment is misleading.
|
|
109
|
+
- **Uses Vitest** for testing.
|
package/dist/Radio.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* DS-native, antd-free radio. `Radio` (radio + label + description) with `Radio.Group` (single-select
|
|
3
|
+
* context) and `Radio.Button` (segmented control) attached as static members.
|
|
4
|
+
*/
|
|
5
|
+
declare const Radio: (({ value, checked, defaultChecked, disabled, name, id, autoFocus, tabIndex, onChange, onClick, label, description, children, className, style, ...rest }: import('./Radio.types').RadioProps) => import("react").JSX.Element) & {
|
|
6
|
+
Group: ({ value, defaultValue, onChange, options, optionType, buttonStyle, size, disabled, name, fullWidth, big, children, className, style, }: import('./Radio.types').RadioGroupProps) => import("react").JSX.Element;
|
|
7
|
+
Button: ({ value, disabled, children, className, checked, onChange, onClick, style, ...rest }: import('./Radio.types').RadioButtonProps) => import("react").JSX.Element;
|
|
6
8
|
};
|
|
7
9
|
export default Radio;
|
package/dist/Radio.js
CHANGED
|
@@ -1,29 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
fullWidth,
|
|
8
|
-
big,
|
|
9
|
-
...props
|
|
10
|
-
}) => {
|
|
11
|
-
return /* @__PURE__ */ jsx(AntRadioGroup, { fullWidth, big, ...props, children });
|
|
12
|
-
};
|
|
13
|
-
const RadioComponent = ({
|
|
14
|
-
description,
|
|
15
|
-
label,
|
|
16
|
-
children,
|
|
17
|
-
...antdRadioButtonProps
|
|
18
|
-
}) => {
|
|
19
|
-
return /* @__PURE__ */ jsxs(RadioWrapper, { children: [
|
|
20
|
-
/* @__PURE__ */ jsx(AntRadio, { ...antdRadioButtonProps, children: label ? /* @__PURE__ */ jsx(Label, { disabled: antdRadioButtonProps.disabled, children: label }) : children }),
|
|
21
|
-
description && /* @__PURE__ */ jsx(AdditionalData, { children: /* @__PURE__ */ jsx(Description, { disabled: antdRadioButtonProps.disabled, children: description }) })
|
|
22
|
-
] });
|
|
23
|
-
};
|
|
24
|
-
const Radio = Object.assign(RadioComponent, {
|
|
25
|
-
Group,
|
|
26
|
-
Button: Radio$1.Button
|
|
1
|
+
import RadioGroup from "./RadioGroup.js";
|
|
2
|
+
import { RadioBase } from "./components/RadioBase.js";
|
|
3
|
+
import { RadioButton } from "./components/RadioButton.js";
|
|
4
|
+
const Radio = Object.assign(RadioBase, {
|
|
5
|
+
Group: RadioGroup,
|
|
6
|
+
Button: RadioButton
|
|
27
7
|
});
|
|
28
8
|
export {
|
|
29
9
|
Radio as default
|
package/dist/Radio.styles.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { default as React } from 'react';
|
|
2
1
|
export declare const RadioWrapper: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
3
2
|
export declare const Description: import('styled-components').StyledComponent<"div", any, {
|
|
4
3
|
disabled?: boolean;
|
|
@@ -7,8 +6,31 @@ export declare const Label: import('styled-components').StyledComponent<({ id, l
|
|
|
7
6
|
disabled?: boolean;
|
|
8
7
|
}, never>;
|
|
9
8
|
export declare const AdditionalData: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
10
|
-
export declare const
|
|
11
|
-
export declare const
|
|
9
|
+
export declare const RadioInput: import('styled-components').StyledComponent<"input", any, {}, never>;
|
|
10
|
+
export declare const RadioInner: import('styled-components').StyledComponent<"span", any, {
|
|
11
|
+
$checked?: boolean;
|
|
12
|
+
$disabled?: boolean;
|
|
13
|
+
}, never>;
|
|
14
|
+
export declare const RadioText: import('styled-components').StyledComponent<"span", any, {
|
|
15
|
+
$checked?: boolean;
|
|
16
|
+
$disabled?: boolean;
|
|
17
|
+
}, never>;
|
|
18
|
+
export declare const RadioBox: import('styled-components').StyledComponent<"span", any, {}, never>;
|
|
19
|
+
export declare const RadioLabel: import('styled-components').StyledComponent<"label", any, {
|
|
20
|
+
$checked?: boolean;
|
|
21
|
+
$disabled?: boolean;
|
|
22
|
+
}, never>;
|
|
23
|
+
export declare const RadioButtonInput: import('styled-components').StyledComponent<"input", any, {}, never>;
|
|
24
|
+
export declare const RadioButtonLabel: import('styled-components').StyledComponent<"label", any, {
|
|
25
|
+
$checked?: boolean;
|
|
26
|
+
$disabled?: boolean;
|
|
27
|
+
$solid?: boolean;
|
|
28
|
+
$size?: "small" | "middle" | "large";
|
|
29
|
+
}, never>;
|
|
30
|
+
/**
|
|
31
|
+
* The `Radio.Group` container. Lays out the children and owns the `fullWidth`/`big` layout.
|
|
32
|
+
*/
|
|
33
|
+
export declare const RadioGroupWrapper: import('styled-components').StyledComponent<"div", any, {
|
|
12
34
|
fullWidth?: boolean;
|
|
13
35
|
big?: boolean;
|
|
14
36
|
}, never>;
|
package/dist/Radio.styles.js
CHANGED
|
@@ -1,39 +1,70 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Radio } from "antd";
|
|
3
1
|
import styled, { css } from "styled-components";
|
|
4
2
|
import { FormFieldLabel } from "@synerise/ds-form-field";
|
|
5
3
|
import { macro } from "@synerise/ds-typography";
|
|
6
4
|
const RadioWrapper = /* @__PURE__ */ styled.div.withConfig({
|
|
7
5
|
displayName: "Radiostyles__RadioWrapper",
|
|
8
6
|
componentId: "sc-137n5jf-0"
|
|
9
|
-
})(["
|
|
7
|
+
})(["display:block;margin-bottom:15px;"]);
|
|
10
8
|
const Description = /* @__PURE__ */ styled.div.withConfig({
|
|
11
9
|
displayName: "Radiostyles__Description",
|
|
12
10
|
componentId: "sc-137n5jf-1"
|
|
13
|
-
})(["color:", ";", " ", ""], (props) => props.theme.palette["grey-600"], (props) => props.disabled ?
|
|
11
|
+
})(["color:", ";", " ", ""], (props) => props.theme.palette["grey-600"], (props) => props.disabled ? "opacity: 0.4;" : "", macro.small);
|
|
14
12
|
const Label = /* @__PURE__ */ styled(FormFieldLabel).withConfig({
|
|
15
13
|
displayName: "Radiostyles__Label",
|
|
16
14
|
componentId: "sc-137n5jf-2"
|
|
17
|
-
})(["", ""], (props) => props.disabled ?
|
|
15
|
+
})(["", ""], (props) => props.disabled ? "opacity: 0.4;" : "");
|
|
18
16
|
const AdditionalData = /* @__PURE__ */ styled.div.withConfig({
|
|
19
17
|
displayName: "Radiostyles__AdditionalData",
|
|
20
18
|
componentId: "sc-137n5jf-3"
|
|
21
19
|
})(["margin:4px 8px 15px 28px;"]);
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
}) => /* @__PURE__ */ jsx(Radio, { ...rest })).withConfig({
|
|
25
|
-
displayName: "Radiostyles__AntRadio",
|
|
20
|
+
const RadioInput = /* @__PURE__ */ styled.input.withConfig({
|
|
21
|
+
displayName: "Radiostyles__RadioInput",
|
|
26
22
|
componentId: "sc-137n5jf-4"
|
|
27
|
-
})(["
|
|
28
|
-
const
|
|
29
|
-
displayName: "
|
|
23
|
+
})(["position:absolute;inset:0;width:16px;height:16px;margin:0;padding:0;opacity:0;cursor:pointer;z-index:1;"]);
|
|
24
|
+
const RadioInner = /* @__PURE__ */ styled.span.withConfig({
|
|
25
|
+
displayName: "Radiostyles__RadioInner",
|
|
30
26
|
componentId: "sc-137n5jf-5"
|
|
31
|
-
})(["", ""], (props) => props.
|
|
27
|
+
})(["position:relative;display:block;width:16px;height:16px;box-sizing:border-box;background-color:", ";border:1px solid ", ";border-radius:50%;&::after{content:'';position:absolute;inset:0;margin:auto;width:8px;height:8px;border-radius:50%;background-color:", ";transform:scale(0);transition:transform 0.2s ease;}", " ", ""], (props) => props.theme.palette.white, (props) => props.theme.palette["grey-300"], (props) => props.theme.palette["blue-600"], (props) => props.$checked && css(["border-color:", ";border-width:2px;&::after{transform:scale(1);}"], props.theme.palette["blue-600"]), (props) => props.$disabled && css(["border-color:", " !important;background-color:", " !important;&::after{background-color:", ";}"], props.theme.palette["grey-200"], props.theme.palette["grey-050"], props.theme.palette["grey-400"]));
|
|
28
|
+
const RadioText = /* @__PURE__ */ styled.span.withConfig({
|
|
29
|
+
displayName: "Radiostyles__RadioText",
|
|
30
|
+
componentId: "sc-137n5jf-6"
|
|
31
|
+
})(["flex-grow:1;margin:0 12px;padding:0;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"]));
|
|
32
|
+
const RadioBox = /* @__PURE__ */ styled.span.withConfig({
|
|
33
|
+
displayName: "Radiostyles__RadioBox",
|
|
34
|
+
componentId: "sc-137n5jf-7"
|
|
35
|
+
})(["position:relative;top:0;display:inline-flex;flex:none;height:16px;cursor:pointer;"]);
|
|
36
|
+
const RadioLabel = /* @__PURE__ */ styled.label.withConfig({
|
|
37
|
+
displayName: "Radiostyles__RadioLabel",
|
|
38
|
+
componentId: "sc-137n5jf-8"
|
|
39
|
+
})(["display:flex;align-items:flex-start;margin:0 8px 0 0;cursor:pointer;white-space:normal;", ":hover + ", "{border-color:", ";}", ":focus + ", "{border-color:", ";background-color:", ";border-width:2px;}", ""], RadioInput, RadioInner, (props) => props.theme.palette["grey-400"], RadioInput, RadioInner, (props) => props.theme.palette["blue-600"], (props) => props.$checked ? props.theme.palette.white : props.theme.palette["blue-050"], (props) => props.$disabled && css(["cursor:not-allowed;", ",", "{cursor:not-allowed;}"], RadioBox, RadioInput));
|
|
40
|
+
const RadioButtonInput = /* @__PURE__ */ styled.input.withConfig({
|
|
41
|
+
displayName: "Radiostyles__RadioButtonInput",
|
|
42
|
+
componentId: "sc-137n5jf-9"
|
|
43
|
+
})(["position:absolute;inset:0;opacity:0;cursor:pointer;"]);
|
|
44
|
+
const BUTTON_HEIGHT = {
|
|
45
|
+
small: "24px",
|
|
46
|
+
middle: "32px",
|
|
47
|
+
large: "40px"
|
|
48
|
+
};
|
|
49
|
+
const RadioButtonLabel = /* @__PURE__ */ styled.label.withConfig({
|
|
50
|
+
displayName: "Radiostyles__RadioButtonLabel",
|
|
51
|
+
componentId: "sc-137n5jf-10"
|
|
52
|
+
})(["position:relative;display:inline-flex;align-items:center;justify-content:center;height:", ";margin:0;padding:0 16px;color:", ";background-color:", ";border:1px solid ", ";border-left-width:0;cursor:pointer;&:first-child{border-left:1px solid ", ";border-radius:3px 0 0 3px;}&:last-child{border-radius:0 3px 3px 0;}&:hover{background-color:", ";}&:focus-within{border-color:", ";box-shadow:inset 0 0 0 1px ", ";z-index:2;}", " ", " ", ""], (props) => BUTTON_HEIGHT[props.$size ?? "middle"], (props) => props.theme.palette["grey-700"], (props) => props.theme.palette["grey-050"], (props) => props.theme.palette["grey-300"], (props) => props.theme.palette["grey-300"], (props) => props.theme.palette.white, (props) => props.theme.palette["blue-600"], (props) => props.theme.palette["blue-600"], (props) => props.$checked && css(["&&{color:", ";border-color:", ";box-shadow:-1px 0 0 0 ", ";z-index:1;}"], props.theme.palette["blue-600"], props.theme.palette["blue-600"], props.theme.palette["blue-600"]), (props) => props.$disabled && css(["color:", ";opacity:0.4;cursor:not-allowed;", "{cursor:not-allowed;}"], props.theme.palette["grey-700"], RadioButtonInput), (props) => props.$solid && props.$checked && !props.$disabled && css(["&&{color:", ";background-color:", ";border-color:", ";&:hover{background-color:", ";border-color:", ";box-shadow:-1px 0 0 0 ", ";}}"], props.theme.palette.white, props.theme.palette["blue-600"], props.theme.palette["blue-600"], props.theme.palette["blue-500"], props.theme.palette["blue-500"], props.theme.palette["blue-500"]));
|
|
53
|
+
const RadioGroupWrapper = /* @__PURE__ */ styled.div.withConfig({
|
|
54
|
+
displayName: "Radiostyles__RadioGroupWrapper",
|
|
55
|
+
componentId: "sc-137n5jf-11"
|
|
56
|
+
})(["display:inline-block;", ""], (props) => props.fullWidth && css(["&&{display:flex;width:100%;", ",", "{flex:1;height:", ";display:flex;align-items:center;justify-content:center;font-weight:500;}}"], RadioLabel, RadioButtonLabel, props.big ? "48px" : "32px"));
|
|
32
57
|
export {
|
|
33
58
|
AdditionalData,
|
|
34
|
-
AntRadio,
|
|
35
|
-
AntRadioGroup,
|
|
36
59
|
Description,
|
|
37
60
|
Label,
|
|
61
|
+
RadioBox,
|
|
62
|
+
RadioButtonInput,
|
|
63
|
+
RadioButtonLabel,
|
|
64
|
+
RadioGroupWrapper,
|
|
65
|
+
RadioInner,
|
|
66
|
+
RadioInput,
|
|
67
|
+
RadioLabel,
|
|
68
|
+
RadioText,
|
|
38
69
|
RadioWrapper
|
|
39
70
|
};
|
package/dist/Radio.types.d.ts
CHANGED
|
@@ -1,18 +1,74 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export type
|
|
4
|
-
|
|
1
|
+
import { CSSProperties, MouseEventHandler, ReactNode } from 'react';
|
|
2
|
+
import { DataAttributes } from '@synerise/ds-utils';
|
|
3
|
+
export type RadioValueType = string | number | boolean;
|
|
4
|
+
/** antd-compatible radio change event. */
|
|
5
|
+
export type RadioChangeEventTarget = {
|
|
6
|
+
value?: RadioValueType;
|
|
7
|
+
checked: boolean;
|
|
8
|
+
name?: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
export type RadioChangeEvent = {
|
|
12
|
+
target: RadioChangeEventTarget;
|
|
13
|
+
stopPropagation: () => void;
|
|
14
|
+
preventDefault: () => void;
|
|
15
|
+
nativeEvent: Event;
|
|
16
|
+
};
|
|
17
|
+
export type RadioProps = {
|
|
18
|
+
value?: RadioValueType;
|
|
19
|
+
checked?: boolean;
|
|
20
|
+
defaultChecked?: boolean;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
name?: string;
|
|
23
|
+
id?: string;
|
|
24
|
+
autoFocus?: boolean;
|
|
25
|
+
tabIndex?: number;
|
|
26
|
+
onChange?: (event: RadioChangeEvent) => void;
|
|
27
|
+
/** Label text (rendered via `FormFieldLabel`). Takes precedence over `children`. */
|
|
5
28
|
label?: ReactNode;
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
29
|
+
/** Helper text rendered below the radio. */
|
|
30
|
+
description?: ReactNode;
|
|
31
|
+
/** @deprecated use `label` instead */
|
|
9
32
|
children?: ReactNode;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
33
|
+
className?: string;
|
|
34
|
+
style?: CSSProperties;
|
|
35
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
36
|
+
} & DataAttributes;
|
|
37
|
+
/** @deprecated use `RadioProps` instead */
|
|
14
38
|
export type Props = RadioProps;
|
|
15
|
-
export type
|
|
39
|
+
export type RadioOptionType = {
|
|
40
|
+
label: ReactNode;
|
|
41
|
+
value: RadioValueType;
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
};
|
|
44
|
+
export type RadioGroupProps = {
|
|
45
|
+
value?: RadioValueType;
|
|
46
|
+
defaultValue?: RadioValueType;
|
|
47
|
+
onChange?: (event: RadioChangeEvent) => void;
|
|
48
|
+
options?: (RadioValueType | RadioOptionType)[];
|
|
49
|
+
optionType?: 'default' | 'button';
|
|
50
|
+
buttonStyle?: 'outline' | 'solid';
|
|
51
|
+
/** Segmented-button height: `small` 24px · `middle` (default) 32px · `large` 40px. */
|
|
52
|
+
size?: 'small' | 'middle' | 'large';
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
name?: string;
|
|
55
|
+
/** Group laid out full-width with equal-flex buttons. */
|
|
16
56
|
fullWidth?: boolean;
|
|
57
|
+
/** With `fullWidth`, taller (48px) buttons. */
|
|
17
58
|
big?: boolean;
|
|
18
|
-
|
|
59
|
+
children?: ReactNode;
|
|
60
|
+
className?: string;
|
|
61
|
+
style?: CSSProperties;
|
|
62
|
+
} & DataAttributes;
|
|
63
|
+
export type RadioButtonProps = {
|
|
64
|
+
value?: RadioValueType;
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
children?: ReactNode;
|
|
67
|
+
className?: string;
|
|
68
|
+
/** Override the group-derived checked state (e.g. when used standalone). */
|
|
69
|
+
checked?: boolean;
|
|
70
|
+
/** Fired on selection, in addition to the group's `onChange`. */
|
|
71
|
+
onChange?: (event: RadioChangeEvent) => void;
|
|
72
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
73
|
+
style?: CSSProperties;
|
|
74
|
+
} & DataAttributes;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RadioValueType } from './Radio.types';
|
|
2
|
+
export type RadioGroupContextValue = {
|
|
3
|
+
/** Currently selected value (single). */
|
|
4
|
+
value?: RadioValueType;
|
|
5
|
+
/** Select a value; the group builds the change event + calls the consumer onChange. */
|
|
6
|
+
onChange: (value: RadioValueType, nativeEvent: Event) => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
name?: string;
|
|
9
|
+
/** `'button'` makes the group render segmented `Radio.Button`s. */
|
|
10
|
+
optionType?: 'default' | 'button';
|
|
11
|
+
/** Button visual when `optionType === 'button'`. */
|
|
12
|
+
buttonStyle?: 'outline' | 'solid';
|
|
13
|
+
/** Segmented-button height (`small`/`middle`/`large`). */
|
|
14
|
+
size?: 'small' | 'middle' | 'large';
|
|
15
|
+
};
|
|
16
|
+
/** Provided by `Radio.Group`; consumed by child `Radio`/`Radio.Button`. `null` when standalone. */
|
|
17
|
+
export declare const RadioGroupContext: import('react').Context<RadioGroupContextValue | null>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { RadioGroupProps } from './Radio.types';
|
|
3
|
+
/**
|
|
4
|
+
* DS-native `Radio.Group`. Provides a single-value selection context that child `Radio`/`Radio.Button`s
|
|
5
|
+
* read, and emits `onChange(RadioChangeEvent)` (`target.value` = the selected value). Controlled via
|
|
6
|
+
* `value`, uncontrolled via `defaultValue`. `optionType="button"` renders segmented `Radio.Button`s.
|
|
7
|
+
*/
|
|
8
|
+
declare const RadioGroup: ({ value, defaultValue, onChange, options, optionType, buttonStyle, size, disabled, name, fullWidth, big, children, className, style, }: RadioGroupProps) => React.JSX.Element;
|
|
9
|
+
export default RadioGroup;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useCallback, useMemo } from "react";
|
|
3
|
+
import { RadioGroupWrapper } from "./Radio.styles.js";
|
|
4
|
+
import { RadioGroupContext } from "./RadioContext.js";
|
|
5
|
+
import { RadioBase } from "./components/RadioBase.js";
|
|
6
|
+
import { RadioButton } from "./components/RadioButton.js";
|
|
7
|
+
const cx = (...classes) => classes.filter(Boolean).join(" ");
|
|
8
|
+
const RadioGroup = ({
|
|
9
|
+
value,
|
|
10
|
+
defaultValue,
|
|
11
|
+
onChange,
|
|
12
|
+
options,
|
|
13
|
+
optionType = "default",
|
|
14
|
+
buttonStyle = "outline",
|
|
15
|
+
size,
|
|
16
|
+
disabled,
|
|
17
|
+
name,
|
|
18
|
+
fullWidth,
|
|
19
|
+
big,
|
|
20
|
+
children,
|
|
21
|
+
className,
|
|
22
|
+
style
|
|
23
|
+
}) => {
|
|
24
|
+
const isControlled = value !== void 0;
|
|
25
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
26
|
+
const resolvedValue = isControlled ? value : internalValue;
|
|
27
|
+
const handleChange = useCallback((newValue, nativeEvent) => {
|
|
28
|
+
if (!isControlled) {
|
|
29
|
+
setInternalValue(newValue);
|
|
30
|
+
}
|
|
31
|
+
const event = {
|
|
32
|
+
target: {
|
|
33
|
+
value: newValue,
|
|
34
|
+
checked: true,
|
|
35
|
+
name
|
|
36
|
+
},
|
|
37
|
+
stopPropagation: () => nativeEvent.stopPropagation?.(),
|
|
38
|
+
preventDefault: () => nativeEvent.preventDefault?.(),
|
|
39
|
+
nativeEvent
|
|
40
|
+
};
|
|
41
|
+
onChange?.(event);
|
|
42
|
+
}, [isControlled, name, onChange]);
|
|
43
|
+
const contextValue = useMemo(() => ({
|
|
44
|
+
value: resolvedValue,
|
|
45
|
+
onChange: handleChange,
|
|
46
|
+
disabled,
|
|
47
|
+
name,
|
|
48
|
+
optionType,
|
|
49
|
+
buttonStyle,
|
|
50
|
+
size
|
|
51
|
+
}), [resolvedValue, handleChange, disabled, name, optionType, buttonStyle, size]);
|
|
52
|
+
const normalizedOptions = options?.map((option) => typeof option === "object" ? option : {
|
|
53
|
+
label: String(option),
|
|
54
|
+
value: option
|
|
55
|
+
});
|
|
56
|
+
const renderOptions = () => normalizedOptions?.map((option) => optionType === "button" ? /* @__PURE__ */ jsx(RadioButton, { value: option.value, disabled: option.disabled, children: option.label }, String(option.value)) : /* @__PURE__ */ jsx(RadioBase, { value: option.value, disabled: option.disabled, label: option.label }, String(option.value)));
|
|
57
|
+
return /* @__PURE__ */ jsx(RadioGroupContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(RadioGroupWrapper, { className: cx("ant-radio-group", `ant-radio-group-${buttonStyle}`, "ds-radio-group", className), style, fullWidth, big, children: normalizedOptions ? renderOptions() : children }) });
|
|
58
|
+
};
|
|
59
|
+
export {
|
|
60
|
+
RadioGroup as default
|
|
61
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { RadioProps } from '../Radio.types';
|
|
3
|
+
export declare const RadioBase: ({ value, checked, defaultChecked, disabled, name, id, autoFocus, tabIndex, onChange, onClick, label, description, children, className, style, ...rest }: RadioProps) => React.JSX.Element;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useContext, useState } from "react";
|
|
3
|
+
import { RadioWrapper, RadioLabel, RadioBox, RadioInput, RadioInner, RadioText, Label, AdditionalData, Description } from "../Radio.styles.js";
|
|
4
|
+
import { RadioGroupContext } from "../RadioContext.js";
|
|
5
|
+
const cx = (...classes) => classes.filter(Boolean).join(" ");
|
|
6
|
+
const RadioBase = ({
|
|
7
|
+
value,
|
|
8
|
+
checked,
|
|
9
|
+
defaultChecked,
|
|
10
|
+
disabled,
|
|
11
|
+
name,
|
|
12
|
+
id,
|
|
13
|
+
autoFocus,
|
|
14
|
+
tabIndex,
|
|
15
|
+
onChange,
|
|
16
|
+
onClick,
|
|
17
|
+
label,
|
|
18
|
+
description,
|
|
19
|
+
children,
|
|
20
|
+
className,
|
|
21
|
+
style,
|
|
22
|
+
// forward data-*/aria-* (e.g. data-testid) to the input, as antd's rc-checkbox did
|
|
23
|
+
...rest
|
|
24
|
+
}) => {
|
|
25
|
+
const group = useContext(RadioGroupContext);
|
|
26
|
+
const isControlled = checked !== void 0;
|
|
27
|
+
const [internalChecked, setInternalChecked] = useState(Boolean(defaultChecked));
|
|
28
|
+
const isChecked = group ? group.value === value : isControlled ? Boolean(checked) : internalChecked;
|
|
29
|
+
const isDisabled = Boolean(disabled ?? group?.disabled);
|
|
30
|
+
const handleChange = (event) => {
|
|
31
|
+
if (isDisabled) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (group) {
|
|
35
|
+
group.onChange(value, event.nativeEvent);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!isControlled) {
|
|
39
|
+
setInternalChecked(true);
|
|
40
|
+
}
|
|
41
|
+
const changeEvent = {
|
|
42
|
+
target: {
|
|
43
|
+
value,
|
|
44
|
+
checked: true,
|
|
45
|
+
name
|
|
46
|
+
},
|
|
47
|
+
stopPropagation: () => event.stopPropagation(),
|
|
48
|
+
preventDefault: () => event.preventDefault(),
|
|
49
|
+
nativeEvent: event.nativeEvent
|
|
50
|
+
};
|
|
51
|
+
onChange?.(changeEvent);
|
|
52
|
+
};
|
|
53
|
+
return /* @__PURE__ */ jsxs(RadioWrapper, { className: cx("ds-radio-field", className), style, children: [
|
|
54
|
+
/* @__PURE__ */ jsxs(RadioLabel, { className: cx("ant-radio-wrapper", "ds-radio", isChecked && "ant-radio-wrapper-checked", isDisabled && "ant-radio-wrapper-disabled"), $checked: isChecked, $disabled: isDisabled, onClick, children: [
|
|
55
|
+
/* @__PURE__ */ jsxs(RadioBox, { className: cx("ant-radio", "ds-radio-box", isChecked && "ant-radio-checked", isDisabled && "ant-radio-disabled"), children: [
|
|
56
|
+
/* @__PURE__ */ jsx(RadioInput, { type: "radio", className: "ant-radio-input ds-radio-input", checked: isChecked, disabled: isDisabled, name: name ?? group?.name, id, autoFocus, tabIndex, value: value === void 0 ? void 0 : String(value), onChange: handleChange, ...rest }),
|
|
57
|
+
/* @__PURE__ */ jsx(RadioInner, { className: "ant-radio-inner ds-radio-inner", $checked: isChecked, $disabled: isDisabled })
|
|
58
|
+
] }),
|
|
59
|
+
/* @__PURE__ */ jsx(RadioText, { $checked: isChecked, $disabled: isDisabled, children: label ? /* @__PURE__ */ jsx(Label, { disabled: isDisabled, children: label }) : children })
|
|
60
|
+
] }),
|
|
61
|
+
description && /* @__PURE__ */ jsx(AdditionalData, { children: /* @__PURE__ */ jsx(Description, { disabled: isDisabled, children: description }) })
|
|
62
|
+
] });
|
|
63
|
+
};
|
|
64
|
+
export {
|
|
65
|
+
RadioBase
|
|
66
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { RadioButtonProps } from '../Radio.types';
|
|
3
|
+
/**
|
|
4
|
+
* Segmented button-style radio (`Radio.Button`). Reproduces antd's `ant-radio-button-wrapper` DOM
|
|
5
|
+
* (class names kept as hooks only); the segment visual lives in the `RadioButtonLabel`
|
|
6
|
+
* styled-component, driven by checked/disabled/solid `$`-props read from the group context. When
|
|
7
|
+
* standalone (no group) `checked` applies directly; inside a group the group's value wins (antd
|
|
8
|
+
* parity). `onChange`/`onClick`/`style` always pass through.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RadioButton: ({ value, disabled, children, className, checked, onChange, onClick, style, ...rest }: RadioButtonProps) => React.JSX.Element;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
import { RadioButtonLabel, RadioButtonInput } from "../Radio.styles.js";
|
|
4
|
+
import { RadioGroupContext } from "../RadioContext.js";
|
|
5
|
+
const cx = (...classes) => classes.filter(Boolean).join(" ");
|
|
6
|
+
const RadioButton = ({
|
|
7
|
+
value,
|
|
8
|
+
disabled,
|
|
9
|
+
children,
|
|
10
|
+
className,
|
|
11
|
+
checked,
|
|
12
|
+
onChange,
|
|
13
|
+
onClick,
|
|
14
|
+
style,
|
|
15
|
+
// forward data-*/aria-* (e.g. data-testid) to the input, as antd's rc-checkbox did
|
|
16
|
+
...rest
|
|
17
|
+
}) => {
|
|
18
|
+
const group = useContext(RadioGroupContext);
|
|
19
|
+
const isChecked = group ? group.value === value : Boolean(checked);
|
|
20
|
+
const isDisabled = Boolean(disabled ?? group?.disabled);
|
|
21
|
+
const handleChange = (event) => {
|
|
22
|
+
if (isDisabled) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (group) {
|
|
26
|
+
group.onChange(value, event.nativeEvent);
|
|
27
|
+
}
|
|
28
|
+
if (onChange) {
|
|
29
|
+
const changeEvent = {
|
|
30
|
+
target: {
|
|
31
|
+
value,
|
|
32
|
+
checked: true,
|
|
33
|
+
name: group?.name
|
|
34
|
+
},
|
|
35
|
+
stopPropagation: () => event.stopPropagation(),
|
|
36
|
+
preventDefault: () => event.preventDefault(),
|
|
37
|
+
nativeEvent: event.nativeEvent
|
|
38
|
+
};
|
|
39
|
+
onChange(changeEvent);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return /* @__PURE__ */ jsxs(RadioButtonLabel, { className: cx("ant-radio-button-wrapper", "ds-radio-button", isChecked && "ant-radio-button-wrapper-checked", isDisabled && "ant-radio-button-wrapper-disabled", className), style, onClick, $checked: isChecked, $disabled: isDisabled, $solid: group?.buttonStyle === "solid", $size: group?.size, children: [
|
|
43
|
+
/* @__PURE__ */ jsx("span", { className: cx("ant-radio-button", isChecked && "ant-radio-button-checked", isDisabled && "ant-radio-button-disabled"), children: /* @__PURE__ */ jsx(RadioButtonInput, { type: "radio", className: "ant-radio-button-input ds-radio-button-input", checked: isChecked, disabled: isDisabled, name: group?.name, value: value === void 0 ? void 0 : String(value), onChange: handleChange, ...rest }) }),
|
|
44
|
+
/* @__PURE__ */ jsx("span", { children })
|
|
45
|
+
] });
|
|
46
|
+
};
|
|
47
|
+
export {
|
|
48
|
+
RadioButton
|
|
49
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default } from './Radio';
|
|
2
|
-
export type { RadioProps, RadioGroupProps } from './Radio.types';
|
|
2
|
+
export type { RadioProps, RadioGroupProps, RadioButtonProps, RadioChangeEvent, RadioValueType, Props, } from './Radio.types';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synerise/ds-radio",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.18",
|
|
4
4
|
"description": "Radio 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"
|
|
@@ -41,15 +42,15 @@
|
|
|
41
42
|
],
|
|
42
43
|
"types": "dist/index.d.ts",
|
|
43
44
|
"dependencies": {
|
|
44
|
-
"@synerise/ds-form-field": "^1.3.
|
|
45
|
-
"@synerise/ds-typography": "^1.1.
|
|
45
|
+
"@synerise/ds-form-field": "^1.3.24",
|
|
46
|
+
"@synerise/ds-typography": "^1.1.27",
|
|
47
|
+
"@synerise/ds-utils": "^1.10.2"
|
|
46
48
|
},
|
|
47
49
|
"peerDependencies": {
|
|
48
50
|
"@synerise/ds-core": "*",
|
|
49
|
-
"antd": "4.24.16",
|
|
50
51
|
"react": ">=16.9.0 <= 18.3.1",
|
|
51
52
|
"styled-components": "^5.3.3",
|
|
52
53
|
"vitest": "4"
|
|
53
54
|
},
|
|
54
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "d0a43cc43d8528a36f105aceea52ab470edb71d9"
|
|
55
56
|
}
|
|
File without changes
|
package/dist/style/index.css
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
.ant-radio-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;font-size:0}.ant-radio-group .ant-badge-count{z-index:1}.ant-radio-group>.ant-badge:not(:first-child)>.ant-radio-button-wrapper{border-left:none}.ant-radio-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';position:relative;display:inline-flex;align-items:baseline;margin-right:8px;cursor:pointer}.ant-radio-wrapper-disabled{cursor:not-allowed}.ant-radio-wrapper::after{display:inline-block;width:0;overflow:hidden;content:'\a0'}.ant-radio-wrapper.ant-radio-wrapper-in-form-item input[type=radio]{width:14px;height:14px}.ant-radio{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;display:inline-block;outline:0;cursor:pointer}.ant-radio-input:focus+.ant-radio-inner,.ant-radio-wrapper:hover .ant-radio,.ant-radio:hover .ant-radio-inner{border-color:#0b68ff}.ant-radio-input:focus+.ant-radio-inner{box-shadow:0 0 0 3px #85b4ff}.ant-radio-checked::after{position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid #0b68ff;border-radius:50%;visibility:hidden;animation:antRadioEffect .36s ease-in-out;animation-fill-mode:both;content:''}.ant-radio-wrapper:hover .ant-radio::after,.ant-radio:hover::after{visibility:visible}.ant-radio-inner{position:relative;top:0;left:0;display:block;width:16px;height:16px;background-color:#fff;border-color:#dbe0e3;border-style:solid;border-width:1px;border-radius:50%;transition:all .3s}.ant-radio-inner::after{position:absolute;top:50%;left:50%;display:block;width:16px;height:16px;margin-top:-8px;margin-left:-8px;background-color:#0b68ff;border-top:0;border-left:0;border-radius:16px;transform:scale(0);opacity:0;transition:all .3s cubic-bezier(.78, .14, .15, .86);content:' '}.ant-radio-input{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;cursor:pointer;opacity:0}.ant-radio.ant-radio-disabled .ant-radio-inner{border-color:#dbe0e3}.ant-radio-checked .ant-radio-inner{border-color:#0b68ff}.ant-radio-checked .ant-radio-inner::after{transform:scale(.5);opacity:1;transition:all .3s cubic-bezier(.78, .14, .15, .86)}.ant-radio-disabled{cursor:not-allowed}.ant-radio-disabled .ant-radio-inner{background-color:#f9fafb;cursor:not-allowed}.ant-radio-disabled .ant-radio-inner::after{background-color:rgba(0,0,0,.2)}.ant-radio-disabled .ant-radio-input{cursor:not-allowed}.ant-radio-disabled+span{color:#b5bdc3;cursor:not-allowed}span.ant-radio+*{padding-right:8px;padding-left:8px}.ant-radio-button-wrapper{position:relative;display:inline-block;height:32px;margin:0;padding:0 15px;color:#6a7580;font-size:13px;line-height:30px;background:#fff;border:1px solid #dbe0e3;border-top-width:1.02px;border-left-width:0;cursor:pointer;transition:color .3s,background .3s,border-color .3s,box-shadow .3s}.ant-radio-button-wrapper a{color:#6a7580}.ant-radio-button-wrapper>.ant-radio-button{position:absolute;top:0;left:0;z-index:-1;width:100%;height:100%}.ant-radio-group-large .ant-radio-button-wrapper{height:48px;font-size:13px;line-height:46px}.ant-radio-group-small .ant-radio-button-wrapper{height:24px;padding:0 7px;line-height:22px}.ant-radio-button-wrapper:not(:first-child)::before{position:absolute;top:-1px;left:-1px;display:block;box-sizing:content-box;width:1px;height:100%;padding:1px 0;background-color:#dbe0e3;transition:background-color .3s;content:''}.ant-radio-button-wrapper:first-child{border-left:1px solid #dbe0e3;border-radius:3px 0 0 3px}.ant-radio-button-wrapper:last-child{border-radius:0 3px 3px 0}.ant-radio-button-wrapper:first-child:last-child{border-radius:3px}.ant-radio-button-wrapper:hover{position:relative;color:#0b68ff}.ant-radio-button-wrapper:focus-within{box-shadow:0 0 0 3px #85b4ff}.ant-radio-button-wrapper .ant-radio-inner,.ant-radio-button-wrapper input[type=checkbox],.ant-radio-button-wrapper input[type=radio]{width:0;height:0;opacity:0;pointer-events:none}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled){z-index:1;color:#0b68ff;background:#f9fafb;border-color:#0b68ff}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before{background-color:#0b68ff}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):first-child{border-color:#0b68ff}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{color:#38f;border-color:#38f}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover::before{background-color:#38f}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active{color:#004cd9;border-color:#004cd9}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active::before{background-color:#004cd9}.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):focus-within{box-shadow:0 0 0 3px #85b4ff}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled){color:#fff;background:#0b68ff;border-color:#0b68ff}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{color:#fff;background:#38f;border-color:#38f}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active{color:#fff;background:#004cd9;border-color:#004cd9}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):focus-within{box-shadow:0 0 0 3px #85b4ff}.ant-radio-button-wrapper-disabled{color:#b5bdc3;background-color:#f9fafb;border-color:#dbe0e3;cursor:not-allowed}.ant-radio-button-wrapper-disabled:first-child,.ant-radio-button-wrapper-disabled:hover{color:#b5bdc3;background-color:#f9fafb;border-color:#dbe0e3}.ant-radio-button-wrapper-disabled:first-child{border-left-color:#dbe0e3}.ant-radio-button-wrapper-disabled.ant-radio-button-wrapper-checked{color:#b5bdc3;background-color:#e6e6e6;border-color:#dbe0e3;box-shadow:none}@keyframes antRadioEffect{0%{transform:scale(1);opacity:.5}100%{transform:scale(1.6);opacity:0}}.ant-radio-group.ant-radio-group-rtl{direction:rtl}.ant-radio-wrapper.ant-radio-wrapper-rtl{margin-right:0;margin-left:8px;direction:rtl}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl{border-right-width:0;border-left-width:1px}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl.ant-radio-button-wrapper:not(:first-child)::before{right:-1px;left:0}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl.ant-radio-button-wrapper:first-child{border-right:1px solid #dbe0e3;border-radius:0 3px 3px 0}.ant-radio-button-wrapper-checked:not([class*=' ant-radio-button-wrapper-disabled']).ant-radio-button-wrapper:first-child{border-right-color:#38f}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl.ant-radio-button-wrapper:last-child{border-radius:3px 0 0 3px}.ant-radio-button-wrapper.ant-radio-button-wrapper-rtl.ant-radio-button-wrapper-disabled:first-child{border-right-color:#dbe0e3}.ant-radio-wrapper{display:flex;white-space:normal}.ant-radio+span{padding:0;color:#57616d;font-weight:500;margin:0 12px 0 12px;position:relative}.ant-radio-checked+span{color:#384350}.ant-radio-wrapper-disabled .ant-radio+span{color:#6a7580;opacity:.4}.ant-radio-wrapper{align-items:unset}.ant-radio-wrapper::after{display:none}.ant-radio-input:hover+.ant-radio-inner{border-color:#b5bdc3}.ant-radio-input:focus+.ant-radio-inner{border-color:#0b68ff;background-color:#f4faff;border-width:2px}.ant-radio-input:focus+.ant-radio-inner{box-shadow:none}.ant-radio-checked .ant-radio-inner{border-color:#0b68ff;border-width:2px}.ant-radio-button-wrapper{background-color:#f9fafb;color:#57616d}.ant-radio-button-wrapper:hover{background-color:#fff;color:#57616d}.ant-radio-button-wrapper:focus{border:2px solid #0b68ff;z-index:2;margin-left:-1px;top:1px}.ant-radio-button-wrapper:focus span+span{top:-2px}.ant-radio-button-wrapper:not(:focus){top:0}.ant-radio-button-wrapper:not(:first-child)::before{display:none}.ant-radio-button-wrapper:not(:first-child):not(:focus)::before{position:absolute;top:0;left:-1px;display:block;width:1px;height:100%;background-color:#dbe0e3;content:''}.ant-radio-button-wrapper-checked:not( .ant-radio-button-wrapper-disabled){box-shadow:-1px 0 0 0 #0b68ff}.ant-radio-button-wrapper span+span{position:relative;top:-1px}.ant-radio-button-wrapper-disabled{color:#57616d;opacity:.4}.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(
|
|
2
|
-
.ant-radio-button-wrapper-disabled
|
|
3
|
-
):hover{color:#fff;background:#238afe;border-color:#238afe;box-shadow:-1px 0 0 0 #238afe}
|