@synerise/ds-radio 1.1.16 → 1.1.17

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,10 @@
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.17](https://github.com/synerise/synerise-design/compare/@synerise/ds-radio@1.1.16...@synerise/ds-radio@1.1.17) (2026-06-27)
7
+
8
+ **Note:** Version bump only for package @synerise/ds-radio
9
+
6
10
  ## [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
11
 
8
12
  **Note:** Version bump only for package @synerise/ds-radio
package/dist/Radio.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { default as React } from 'react';
2
- import { RadioGroupProps, RadioProps } from './Radio.types';
3
- declare const Radio: (({ description, label, children, ...antdRadioButtonProps }: RadioProps) => React.JSX.Element) & {
4
- Group: ({ children, fullWidth, big, ...props }: RadioGroupProps) => React.JSX.Element;
5
- Button: React.ForwardRefExoticComponent<import('antd/lib/radio/radioButton').RadioButtonProps & React.RefAttributes<any>>;
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 { jsxs, jsx } from "react/jsx-runtime";
2
- import { Radio as Radio$1 } from "antd";
3
- import { RadioWrapper, AntRadio, Label, AdditionalData, Description, AntRadioGroup } from "./Radio.styles.js";
4
- import "./style/index.css";
5
- const Group = ({
6
- children,
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
@@ -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 AntRadio: import('styled-components').StyledComponent<({ ...rest }: any) => React.JSX.Element, any, {}, never>;
11
- export declare const AntRadioGroup: import('styled-components').StyledComponent<React.MemoExoticComponent<React.ForwardRefExoticComponent<import('antd').RadioGroupProps & React.RefAttributes<HTMLDivElement>>>, any, {
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>;
@@ -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
- })(["&{display:block;margin-bottom:15px;}"]);
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 ? `opacity: 0.4;` : "", macro.small);
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 ? `opacity: 0.4;` : "");
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 AntRadio = /* @__PURE__ */ styled(({
23
- ...rest
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
- })([".ant-radio{height:16px;top:0;}.ant-radio + span{flex-grow:1;}"]);
28
- const AntRadioGroup = /* @__PURE__ */ styled(Radio.Group).withConfig({
29
- displayName: "Radiostyles__AntRadioGroup",
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.fullWidth && css(["&&{display:flex;width:100%;label{flex:1;height:", ";display:flex;align-items:center;justify-content:center;font-weight:500;}}"], props.big ? "48px" : "32px"));
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
  };
@@ -1,18 +1,74 @@
1
- import { RadioGroupProps as AntdRadioGroupProps, RadioProps as AntdRadioProps } from 'antd';
2
- import { ReactNode } from 'react';
3
- export type RadioProps = AntdRadioProps & {
4
- description?: ReactNode;
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
- * @deprecated, use label instead
8
- */
29
+ /** Helper text rendered below the radio. */
30
+ description?: ReactNode;
31
+ /** @deprecated use `label` instead */
9
32
  children?: ReactNode;
10
- };
11
- /**
12
- * @deprecated, use RadioProps instead
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 RadioGroupProps = AntdRadioGroupProps & {
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,5 @@
1
+ import { createContext } from "react";
2
+ const RadioGroupContext = createContext(null);
3
+ export {
4
+ RadioGroupContext
5
+ };
@@ -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
+ };
@@ -0,0 +1,2 @@
1
+ export { RadioBase } from './RadioBase';
2
+ export { RadioButton } from './RadioButton';
@@ -0,0 +1,6 @@
1
+ import { RadioBase } from "./RadioBase.js";
2
+ import { RadioButton } from "./RadioButton.js";
3
+ export {
4
+ RadioBase,
5
+ RadioButton
6
+ };
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.16",
3
+ "version": "1.1.17",
4
4
  "description": "Radio UI Component for the Synerise Design System",
5
5
  "license": "ISC",
6
6
  "repository": "synerise/synerise-design",
@@ -42,14 +42,14 @@
42
42
  "types": "dist/index.d.ts",
43
43
  "dependencies": {
44
44
  "@synerise/ds-form-field": "^1.3.23",
45
- "@synerise/ds-typography": "^1.1.26"
45
+ "@synerise/ds-typography": "^1.1.26",
46
+ "@synerise/ds-utils": "^1.10.1"
46
47
  },
47
48
  "peerDependencies": {
48
49
  "@synerise/ds-core": "*",
49
- "antd": "4.24.16",
50
50
  "react": ">=16.9.0 <= 18.3.1",
51
51
  "styled-components": "^5.3.3",
52
52
  "vitest": "4"
53
53
  },
54
- "gitHead": "d8c64070f58f14e3fb1bfbcbf00d1e3b8fd51eb8"
54
+ "gitHead": "dfd892acc1d02abebcf661db3fb32f0fc4b6c354"
55
55
  }
File without changes
@@ -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}