11import { clsx } from 'clsx'
2+ import styled from 'styled-components'
23import { useProvidedRefOrCreate } from '../hooks'
34import React , { useContext , useEffect , type ChangeEventHandler , type InputHTMLAttributes , type ReactElement } from 'react'
4- import { type SxProp } from '../sx'
5+ import sx , { type SxProp } from '../sx'
56import useLayoutEffect from '../utils/useIsomorphicLayoutEffect'
67import type { FormValidationStatus } from '../utils/types/FormValidationStatus'
78import { CheckboxGroupContext } from '../CheckboxGroup/CheckboxGroupContext'
9+ import getGlobalFocusStyles from '../internal/utils/getGlobalFocusStyles'
10+ import { get } from '../constants'
11+ import { sharedCheckboxAndRadioStyles } from '../internal/utils/sharedCheckboxAndRadioStyles'
812import classes from './Checkbox.module.css'
913import sharedClasses from './shared.module.css'
14+ import { useFeatureFlag } from '../FeatureFlags'
1015import Box from '../Box'
1116
1217export type CheckboxProps = {
@@ -38,6 +43,106 @@ export type CheckboxProps = {
3843} & Exclude < InputHTMLAttributes < HTMLInputElement > , 'value' > &
3944 SxProp
4045
46+ const StyledCheckbox = styled . input `
47+ ${ sharedCheckboxAndRadioStyles } ;
48+ border-radius: ${ get ( 'radii.1' ) } ;
49+ transition:
50+ background-color,
51+ border-color 80ms cubic-bezier(0.33, 1, 0.68, 1); /* checked -> unchecked - add 120ms delay to fully see animation-out */
52+
53+ &::before {
54+ width: var(--base-size-16, 16px);
55+ height: var(--base-size-16, 16px);
56+ visibility: hidden;
57+ content: '';
58+ background-color: ${ get ( 'colors.fg.onEmphasis' ) } ;
59+ transition: visibility 0s linear 230ms;
60+ clip-path: inset(var(--base-size-16, 16px) 0 0 0);
61+ mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOSIgdmlld0JveD0iMCAwIDEyIDkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTEuNzgwMyAwLjIxOTYyNUMxMS45MjEgMC4zNjA0MjcgMTIgMC41NTEzMDUgMTIgMC43NTAzMTNDMTIgMC45NDkzMjEgMTEuOTIxIDEuMTQwMTkgMTEuNzgwMyAxLjI4MUw0LjUxODYgOC41NDA0MkM0LjM3Nzc1IDguNjgxIDQuMTg2ODIgOC43NiAzLjk4Nzc0IDguNzZDMy43ODg2NyA4Ljc2IDMuNTk3NzMgOC42ODEgMy40NTY4OSA4LjU0MDQyTDAuMjAxNjIyIDUuMjg2MkMwLjA2ODkyNzcgNS4xNDM4MyAtMC4wMDMzMDkwNSA0Ljk1NTU1IDAuMDAwMTE2NDkzIDQuNzYwOThDMC4wMDM1NTIwNSA0LjU2NjQzIDAuMDgyMzg5NCA0LjM4MDgxIDAuMjIwMDMyIDQuMjQzMjFDMC4zNTc2NjUgNC4xMDU2MiAwLjU0MzM1NSA0LjAyNjgxIDAuNzM3OTcgNC4wMjMzOEMwLjkzMjU4NCA0LjAxOTk0IDEuMTIwOTMgNC4wOTIxNyAxLjI2MzM0IDQuMjI0ODJMMy45ODc3NCA2Ljk0ODM1TDEwLjcxODYgMC4yMTk2MjVDMTAuODU5NSAwLjA3ODk5MjMgMTEuMDUwNCAwIDExLjI0OTUgMEMxMS40NDg1IDAgMTEuNjM5NSAwLjA3ODk5MjMgMTEuNzgwMyAwLjIxOTYyNVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=');
62+ mask-size: 75%;
63+ mask-repeat: no-repeat;
64+ mask-position: center;
65+
66+ animation: checkmarkOut 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
67+ }
68+
69+ &:checked,
70+ &:indeterminate {
71+ background: var(--control-checked-bgColor-rest, ${ get ( 'colors.accent.fg' ) } );
72+ border-color: var(
73+ --control-checked-bgColor-rest,
74+ ${ get ( 'colors.accent.fg' ) }
75+ ); /* using bgColor here to avoid a border change in dark high contrast */
76+
77+ &::before {
78+ animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms;
79+ }
80+ }
81+
82+ &:disabled {
83+ cursor: not-allowed;
84+ }
85+
86+ &:checked {
87+ transition:
88+ background-color,
89+ border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms;
90+
91+ &::before {
92+ visibility: visible;
93+ transition: visibility 0s linear 0s;
94+ }
95+
96+ &:disabled {
97+ background-color: var(--control-checked-bgColor-disabled, ${ get ( 'colors.fg.muted' ) } );
98+ border-color: var(--control-checked-borderColor-disabled, ${ get ( 'colors.fg.muted' ) } );
99+ opacity: 1;
100+
101+ &::before {
102+ background-color: var(--control-checked-fgColor-disabled, ${ get ( 'colors.fg.onEmphasis' ) } );
103+ }
104+ }
105+
106+ /* Windows High Contrast mode */
107+ @media (forced-colors: active) {
108+ background-color: canvastext;
109+ border-color: canvastext;
110+ }
111+ }
112+
113+ &:indeterminate {
114+ background: var(--control-checked-bgColor-rest, ${ get ( 'colors.accent.fg' ) } );
115+ &::before {
116+ mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMiIgdmlld0JveD0iMCAwIDEwIDIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMCAxQzAgMC40NDc3MTUgMC40NDc3MTUgMCAxIDBIOUM5LjU1MjI5IDAgMTAgMC40NDc3MTUgMTAgMUMxMCAxLjU1MjI4IDkuNTUyMjkgMiA5IDJIMUMwLjQ0NzcxNSAyIDAgMS41NTIyOCAwIDFaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K');
117+ visibility: visible;
118+ }
119+ }
120+
121+ ${ getGlobalFocusStyles ( ) } ;
122+
123+ ${ sx } ;
124+
125+ @keyframes checkmarkIn {
126+ from {
127+ clip-path: inset(var(--base-size-16, 16px) 0 0 0);
128+ }
129+
130+ to {
131+ clip-path: inset(0 0 0 0);
132+ }
133+ }
134+
135+ @keyframes checkmarkOut {
136+ from {
137+ clip-path: inset(0 0 0 0);
138+ }
139+
140+ to {
141+ clip-path: inset(var(--base-size-16, 16px) 0 0 0);
142+ }
143+ }
144+ `
145+
41146/**
42147 * An accessible, native checkbox component
43148 */
@@ -58,6 +163,7 @@ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
58163 } ,
59164 ref ,
60165 ) : ReactElement => {
166+ const enabled = useFeatureFlag ( 'primer_react_css_modules_ga' )
61167 const checkboxRef = useProvidedRefOrCreate ( ref as React . RefObject < HTMLInputElement > )
62168 const checkboxGroupContext = useContext ( CheckboxGroupContext )
63169 const handleOnChange : ChangeEventHandler < HTMLInputElement > = e => {
@@ -98,17 +204,21 @@ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
98204 }
99205 } )
100206
101- if ( sxProp ) {
102- return (
103- < Box
104- as = "input"
105- { ...inputProps }
106- className = { clsx ( className , sharedClasses . Input , classes . Checkbox ) }
107- sx = { sxProp }
108- />
109- )
207+ if ( enabled ) {
208+ if ( sxProp ) {
209+ return (
210+ < Box
211+ as = "input"
212+ { ...inputProps }
213+ className = { clsx ( className , sharedClasses . Input , classes . Checkbox ) }
214+ sx = { sxProp }
215+ />
216+ )
217+ }
218+ return < input { ...inputProps } className = { clsx ( className , sharedClasses . Input , classes . Checkbox ) } />
110219 }
111- return < input { ...inputProps } className = { clsx ( className , sharedClasses . Input , classes . Checkbox ) } />
220+
221+ return < StyledCheckbox { ...inputProps } className = { className } sx = { sxProp } />
112222 } ,
113223)
114224
0 commit comments