diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..6e22ae8a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [v1.10.7] - 2024-10-22 + +- Create custom styled checkbox +- Update primary and light checkbox styles +- Update color for checkbox label +- Add disabled state style +- Add error state style +- Add error prop to checkbox \ No newline at end of file diff --git a/package.json b/package.json index 0eacc7ca..55d4b7d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openstax/ui-components", - "version": "1.10.6", + "version": "1.10.7", "license": "MIT", "source": "./src/index.ts", "types": "./dist/index.d.ts", diff --git a/src/components/Checkbox.tsx b/src/components/Checkbox.tsx index b979a87a..a4bac656 100644 --- a/src/components/Checkbox.tsx +++ b/src/components/Checkbox.tsx @@ -2,37 +2,84 @@ import { LabelHTMLAttributes, PropsWithChildren } from "react"; import { colors } from "../theme"; import styled from "styled-components"; import { InputHTMLAttributes } from "react"; +import { whiteCheckmark, grayCheckmark, redCheckmark } from "./svgs/checkmarksvgs"; -type CheckboxVariant = keyof typeof checkboxVariants; -type CheckboxSize = 1.4 | 1.6 | 1.8 | 2; +export type CheckboxVariant = keyof typeof checkboxVariants; +export type CheckboxSize = 1.4 | 1.6 | 1.8 | 2; export const checkboxVariants = { primary: { - accentColor: colors.palette.mediumBlue, - boxShadow: 'none', + backgroundColor: colors.palette.mediumBlue, + color: 'inherit', + unCheckedBorder: `1px solid ${colors.palette.neutralThin}`, + checkedBorder: `1px solid ${colors.palette.mediumBlue}`, + backgroundImage: whiteCheckmark }, light: { - accentColor: colors.palette.white, - boxShadow: '0 0 1px 0', + backgroundColor: colors.palette.white, + color: 'inherit', + unCheckedBorder: `1px solid ${colors.palette.pale}`, + checkedBorder: `1px solid ${colors.palette.pale}`, + backgroundImage: grayCheckmark + }, + error: { + backgroundColor: colors.palette.paleRed, + color: colors.palette.darkRed, + unCheckedBorder: `1px solid ${colors.palette.lightRed}`, + checkedBorder: `1px solid ${colors.palette.lightRed}`, + backgroundImage: redCheckmark + }, + disabled: { + backgroundColor: colors.palette.white, + color: 'inherit', + unCheckedBorder: `1px solid ${colors.palette.pale}`, + checkedBorder: `1px solid ${colors.palette.pale}`, + backgroundImage: 'none' } } as const; -const StyledLabel = styled.label<{ bold: boolean; }>` +const StyledLabel = styled.label<{ bold: boolean; variant: CheckboxVariant; isDisabled?: boolean; }>` font-size: 1.4rem; display: flex; align-items: center; - font-weight: ${props => props.bold ? 700 : 400} + font-weight: ${props => props.bold ? 700 : 400}; + color: ${(props => props.isDisabled ? colors.palette.neutralLight : checkboxVariants[props.variant].color)}; `; -const StyledInput = styled.input<{ variant: CheckboxVariant; checkboxSize: CheckboxSize; }>` - accent-color: ${props => checkboxVariants[props.variant].accentColor}; +// https://moderncss.dev/pure-css-custom-checkbox-style/ +const StyledInput = styled.input<{ variant: CheckboxVariant; checkboxSize: CheckboxSize; isDisabled?: boolean; }>` + appearance: none; + /* For iOS < 15 to remove gradient background */ + background-color: ${colors.palette.white}; + opacity: ${(props => props.isDisabled ? '0.4' : '1')}; + border: ${props => props.isDisabled ? `1px solid ${colors.palette.pale}` : checkboxVariants[props.variant].unCheckedBorder}; + border-radius: 0.2rem; + transform: translateY(-0.075em); width: ${props => props.checkboxSize}rem; height: ${props => props.checkboxSize}rem; margin: 0 1.6rem 0 0; - &:checked { - box-shadow: ${props => checkboxVariants[props.variant].boxShadow}; + display: grid; + place-content: center; + + &::before { + content: ""; + width: ${props => props.checkboxSize}rem; + height: ${props => props.checkboxSize}rem; + border: ${props => checkboxVariants[props.variant].checkedBorder}; + border-radius: 0.2rem; + transform: scale(0); + background-color: ${props => checkboxVariants[props.variant].backgroundColor}; + background-image: url('${props => checkboxVariants[props.variant].backgroundImage}'); + background-size: 80%; + background-position: center; + background-repeat: no-repeat; } -`; + + &:checked::before { + transform: scale(1); + opacity: ${(props => props.isDisabled ? 0 : 1)}; + } + `; type CheckboxProps = PropsWithChildren< Omit, 'type'> & { @@ -42,10 +89,10 @@ type CheckboxProps = PropsWithChildren< labelProps?: LabelHTMLAttributes; }>; -export const Checkbox = ({ children, variant = 'primary', bold = false, size = 1.6, labelProps, ...props }: CheckboxProps) => { +export const Checkbox = ({ children, disabled, variant = 'primary', bold = false, size = 1.6, labelProps, ...props }: CheckboxProps) => { return ( - - + + {children} ); diff --git a/src/components/__snapshots__/Checkbox.spec.tsx.snap b/src/components/__snapshots__/Checkbox.spec.tsx.snap index f7969870..5be37703 100644 --- a/src/components/__snapshots__/Checkbox.spec.tsx.snap +++ b/src/components/__snapshots__/Checkbox.spec.tsx.snap @@ -3,10 +3,10 @@ exports[`Checkbox allows setting props on label 1`] = `