Skip to content

Commit

Permalink
Merge pull request #509 from deadkex/#486
Browse files Browse the repository at this point in the history
add CheckboxCard, CheckboxIndicator, RadioCard, RadioIndicator #486
  • Loading branch information
AnnMarieW authored Feb 15, 2025
2 parents 5ea4c5d + 4df6215 commit 4bc5efd
Show file tree
Hide file tree
Showing 12 changed files with 456 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
- If you were using `dmc < 0.15.0`, please follow our [migration guide](https://www.dash-mantine-components.com/migration).
- ⚠️ **Important:** Apps using `dmc < 1.0.0` must pin `dash < 3` to avoid compatibility issues.

### Added

- Added `CheckboxCard` `CheckboxIndicator` `RadioCard` `RadioIndicator` components #486 by @deadkex

### Changed
- Updated to handle changes in Dash 3 #506 by @AnnMarieW:
- Removed `defaultProps` to be compatible with React 18.3
Expand Down
59 changes: 59 additions & 0 deletions src/ts/components/core/checkbox/CheckboxCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
CheckboxCard as MantineCheckboxCard,
MantineRadius,
MantineSize,
} from "@mantine/core";
import { BoxProps } from "props/box";
import { DashBaseProps, PersistenceProps } from "props/dash";
import { StylesApiProps } from "props/styles";
import React from "react";
import { setPersistence, getLoadingState } from "../../../utils/dash3";

interface Props
extends BoxProps,
StylesApiProps,
DashBaseProps,
PersistenceProps {
/** State of check box */
checked?: boolean;
/** Uncontrolled component default value */
defaultChecked?: boolean;
/** Determines whether the card should have border, `true` by default */
withBorder?: boolean;
/** Key of `theme.radius` or any valid CSS value to set `border-radius,` `theme.defaultRadius` by default */
radius?: MantineRadius;
/** To be used with checkbox group */
value?: string;
/** Props passed down to the root element */
wrapperProps?: Record<string, any>;
/** Determines whether CheckboxCard is disabled and non-selectable */
disabled?: boolean;
/** CheckboxCard content */
children?: React.ReactNode;
}

/** CheckboxCard */
const CheckboxCard = ({
children,
setProps,
loading_state,
persistence,
persisted_props,
persistence_type,
...others
}: Props) => {

return (
<MantineCheckboxCard
data-dash-is-loading={getLoadingState(loading_state) || undefined}
onChange={(state: boolean) => setProps({ checked: state })}
{...others}
>
{children}
</MantineCheckboxCard>
);
};

setPersistence(CheckboxCard, ["checked"]);

export default CheckboxCard;
71 changes: 71 additions & 0 deletions src/ts/components/core/checkbox/CheckboxIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {
CheckboxIndicator as MantineCheckboxIndicator,
MantineColor,
MantineRadius,
MantineSize,
} from "@mantine/core";
import { BoxProps } from "props/box";
import { DashBaseProps, PersistenceProps } from "props/dash";
import { StylesApiProps } from "props/styles";
import React from "react";
import { setPersistence, getLoadingState, applyDashProps } from "../../../utils/dash3";

interface Props
extends BoxProps,
StylesApiProps,
DashBaseProps,
PersistenceProps {
/** Key of `theme.colors` or any valid CSS color to set input background color in checked state, `theme.primaryColor` by default */
color?: MantineColor;
/** Controls size of the component, `'sm'` by default */
size?: MantineSize | (string & {});
/** Key of `theme.radius` or any valid CSS value to set `border-radius,` `theme.defaultRadius` by default */
radius?: MantineRadius;
/** Props passed down to the root element */
wrapperProps?: Record<string, any>;
/** Indeterminate state of the checkbox. If set, `checked` prop is ignored. */
indeterminate?: boolean;
/** Key of `theme.colors` or any valid CSS color to set icon color, by default value depends on `theme.autoContrast` */
iconColor?: MantineColor;
/** Determines whether icon color with filled variant should depend on `background-color`. If luminosity of the `color` prop is less than `theme.luminosityThreshold`, then `theme.white` will be used for text color, otherwise `theme.black`. Overrides `theme.autoContrast`. */
autoContrast?: boolean;
/** State of check box */
checked?: boolean;
/** Whether component is disabled */
disabled?: boolean;
/** Icon */
icon?: React.ReactNode;
/** Indeterminate icon */
indeterminateIcon?: React.ReactNode;
}

/** CheckboxIndicator */
const CheckboxIndicator = ({
setProps,
loading_state,
persistence,
persisted_props,
persistence_type,
icon,
indeterminateIcon,
...others
}: Props) => {


const iconFunc = ({ indeterminate, ...others }) => {
const selected: any = indeterminate ? indeterminateIcon : icon;
return applyDashProps(selected, others);
};

return (
<MantineCheckboxIndicator
data-dash-is-loading={getLoadingState(loading_state) || undefined}
icon={icon || indeterminateIcon ? iconFunc : undefined}
{...others}
/>
);
};

setPersistence(CheckboxIndicator, ["checked"] )

export default CheckboxIndicator;
4 changes: 3 additions & 1 deletion src/ts/components/core/radio/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const Radio = (props: Props) => {
persistence,
persisted_props,
persistence_type,
value,
...others
} = props;

Expand All @@ -59,7 +60,8 @@ const Radio = (props: Props) => {
<MantineRadio
data-dash-is-loading={getLoadingState(loading_state) || undefined}
onChange={(ev) => setProps({ checked: ev.currentTarget.checked })}
onClick={radioOnClick}
onClick={radioOnClick ? () => radioOnClick(value) : null}
value={value}
{...others}
/>
);
Expand Down
64 changes: 64 additions & 0 deletions src/ts/components/core/radio/RadioCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {
RadioCard as MantineRadioCard,
MantineRadius,
} from "@mantine/core";
import { BoxProps } from "props/box";
import { DashBaseProps, PersistenceProps } from "props/dash";
import { StylesApiProps } from "props/styles";
import React from "react";
import { setPersistence, getLoadingState } from "../../../utils/dash3";
import RadioGroupContext from "./RadioGroupContext";

interface Props
extends BoxProps,
StylesApiProps,
DashBaseProps,
PersistenceProps {
/** Checked state */
checked?: boolean;
/** Determines whether the card should have border, `true` by default */
withBorder?: boolean;
/** Key of `theme.radius` or any valid CSS value to set `border-radius,` "xl" by default */
radius?: MantineRadius;
/** To be used with Radio group */
value?: string;
/** Value used to associate all related radio cards, required for accessibility if used outside of `Radio.Group` */
name?: string;
/** Props passed down to the root element */
wrapperProps?: Record<string, any>;
/** Determines whether RadioCard is disabled and non-selectable */
disabled?: boolean;
/** RadioCard content */
children?: React.ReactNode;
}

/** RadioCard */
const RadioCard = (props: Props) => {
const {
children,
setProps,
loading_state,
persistence,
persisted_props,
persistence_type,
value,
...others
} = props;

const { radioOnClick } = React.useContext(RadioGroupContext) || {};

return (
<MantineRadioCard
data-dash-is-loading={getLoadingState(loading_state) || undefined}
onClick={radioOnClick ? () => radioOnClick(value) : null}
value={value}
{...others}
>
{children}
</MantineRadioCard>
);
};

setPersistence(RadioCard, ["checked"]);

export default RadioCard;
6 changes: 3 additions & 3 deletions src/ts/components/core/radio/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ const RadioGroup = (props: Props) => {
setProps({ value });
};

const handleRadioClick = (event: React.MouseEvent<HTMLInputElement>) => {
if (event.currentTarget.value === value) {
const handleRadioClick = (val?: string) => {
if (val === value) {
setProps({ value: null });
}
};
};

return (
<Radio.Group
Expand Down
2 changes: 1 addition & 1 deletion src/ts/components/core/radio/RadioGroupContext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { createContext } from "react";

interface RadioGroupContextProps {
radioOnClick?: (e: React.MouseEvent<HTMLInputElement>) => void;
radioOnClick?: (val?: string) => void;
}

const RadioGroupContext = createContext<RadioGroupContextProps | null>(null);
Expand Down
57 changes: 57 additions & 0 deletions src/ts/components/core/radio/RadioIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
MantineColor,
RadioIndicator as MantineRadioIndicator,
MantineRadius,
MantineSize,
} from "@mantine/core";
import { BoxProps } from "props/box";
import { DashBaseProps, PersistenceProps } from "props/dash";
import { StylesApiProps } from "props/styles";
import React from "react";
import { setPersistence, getLoadingState } from "../../../utils/dash3";

interface Props
extends BoxProps,
StylesApiProps,
DashBaseProps,
PersistenceProps {
/** Key of `theme.colors` or any valid CSS color to set input color in checked state, `theme.primaryColor` by default */
color?: MantineColor;
/** Controls size of the component, `'sm'` by default */
size?: MantineSize;
/** Props passed down to the root element */
wrapperProps?: Record<string, any>;
/** Key of `theme.radius` or any valid CSS value to set `border-radius,` "xl" by default */
radius?: MantineRadius;
/** Key of `theme.colors` or any valid CSS color to set icon color, by default value depends on `theme.autoContrast` */
iconColor?: MantineColor;
/** Determines whether icon color with filled variant should depend on `background-color`. If luminosity of the `color` prop is less than `theme.luminosityThreshold`, then `theme.white` will be used for text color, otherwise `theme.black`. Overrides `theme.autoContrast`. */
autoContrast?: boolean;
/** Determines whether the component should have checked styles */
checked?: boolean;
/** Determines whether Radio disabled and non-selectable */
disabled?: boolean;
}

/** RadioIndicator */
const RadioIndicator = (props: Props) => {
const {
setProps,
loading_state,
persistence,
persisted_props,
persistence_type,
...others
} = props;

return (
<MantineRadioIndicator
data-dash-is-loading={getLoadingState(loading_state) || undefined}
{...others}
/>
);
};

setPersistence(RadioIndicator, ['checked'])

export default RadioIndicator;
8 changes: 8 additions & 0 deletions src/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ import Card from "./components/core/card/Card";
import CardSection from "./components/core/card/CardSection";
import Checkbox from "./components/core/checkbox/Checkbox";
import CheckboxGroup from "./components/core/checkbox/CheckboxGroup";
import CheckboxCard from "./components/core/checkbox/CheckboxCard";
import CheckboxIndicator from "./components/core/checkbox/CheckboxIndicator";
import Chip from "./components/core/chip/Chip";
import ColorInput from "./components/core/color/ColorInput";
import ColorPicker from "./components/core/color/ColorPicker";
Expand Down Expand Up @@ -113,6 +115,8 @@ import ProgressRoot from "./components/core/progress/ProgressRoot";
import ProgressSection from "./components/core/progress/ProgressSection";
import Radio from "./components/core/radio/Radio";
import RadioGroup from "./components/core/radio/RadioGroup";
import RadioIndicator from "./components/core/radio/RadioIndicator";
import RadioCard from "./components/core/radio/RadioCard";
import RangeSlider from "./components/core/slider/RangeSlider";
import SemiCircleProgress from "./components/core/SemiCircleProgress";
import Slider from "./components/core/slider/Slider";
Expand Down Expand Up @@ -194,6 +198,8 @@ export {
Center,
Checkbox,
CheckboxGroup,
CheckboxCard,
CheckboxIndicator,
Chip,
ChipGroup,
Code,
Expand Down Expand Up @@ -267,6 +273,8 @@ export {
RadarChart,
Radio,
RadioGroup,
RadioIndicator,
RadioCard,
RangeSlider,
Rating,
RingProgress,
Expand Down
Loading

0 comments on commit 4bc5efd

Please sign in to comment.