Add a dark version of the checkbox component (#30213)

* Add a dark version of the checkbox component

* Add theming to storybook

* Fix storybook

* adding correct border colors

---------

Co-authored-by: davibaweja <davibaweja@gmail.com>
GitOrigin-RevId: e350ab7a0800edd960d99bb892e527b97106b17d
This commit is contained in:
David
2026-01-23 10:39:49 +00:00
committed by Copybot
parent f7b42d212a
commit 3d18d02846
4 changed files with 194 additions and 17 deletions

View File

@@ -35,7 +35,7 @@ function OLFormCheckbox(props: OLFormCheckboxProps) {
}
/>
) : (
<Form.Check ref={inputRef} {...rest} />
<Form.Check className="form-checkbox" ref={inputRef} {...rest} />
)
}

View File

@@ -2,10 +2,11 @@ import { useRef, useLayoutEffect } from 'react'
import { Form } from 'react-bootstrap'
import type { Meta, StoryObj } from '@storybook/react'
import { figmaDesignUrl } from '../../../../.storybook/utils/figma-design-url'
import OLFormCheckbox from '@/shared/components/ol/ol-form-checkbox'
const meta: Meta<(typeof Form)['Check']> = {
title: 'Shared / Components / Form',
component: Form.Check,
component: OLFormCheckbox,
parameters: {
controls: {
include: ['disabled'],
@@ -40,7 +41,7 @@ export const CheckboxChecked: Story = {
}
export const CheckboxIndeterminate = (args: Story['args']) => {
const ref = useRef<HTMLInputElement>()
const ref = useRef<HTMLInputElement>(null)
useLayoutEffect(() => {
if (ref.current) {
@@ -48,7 +49,7 @@ export const CheckboxIndeterminate = (args: Story['args']) => {
}
}, [])
return <Form.Check ref={ref} {...args} />
return <OLFormCheckbox inputRef={ref} {...args} />
}
CheckboxIndeterminate.args = {
id: 'id-2',

View File

@@ -1,16 +1,117 @@
@function form-check-box-svg($color) {
@return url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/></svg>");
}
@function form-check-radio-svg($color) {
@return url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='2' fill='#{$color}'/></svg>");
}
@function form-check-indeterminate-svg($color) {
@return url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/></svg>");
}
@mixin form-check-light {
--checkbox-label-color: var(--content-primary);
--checkbox-border-color: var(--border-primary);
--checkbox-bg: var(--bg-light-primary);
// Hover
--checkbox-hover-border-color: var(--border-hover);
// Checked
--checkbox-checked-bg: var(--bg-accent-01);
--checkbox-checked-border-color: var(--bg-accent-01);
--checkbox-checked-background-image: #{escape-svg(
form-check-box-svg($content-primary-dark)
)};
// Indeterminate
--checkbox-indeterminate-background-image: #{escape-svg(
form-check-indeterminate-svg($content-primary-dark)
)};
// Checked & hover
--checkbox-hover-checked-bg: var(--bg-accent-02);
--checkbox-hover-checked-border-color: var(--bg-accent-02);
// Focus
--checkbox-focus-border-color: var(--border-primary);
// Disabled
--checkbox-disabled-bg: var(--bg-light-disabled);
--checkbox-disabled-border-color: var(--border-disabled);
// Disabled & checked
--checkbox-disabled-checked-background-image: #{escape-svg(
form-check-box-svg($content-disabled-dark)
)};
// Disabled & indeterminate
--checkbox-disabled-indeterminate-background-image: #{escape-svg(
form-check-indeterminate-svg($content-disabled-dark)
)};
}
@mixin form-check-dark {
--checkbox-label-color: var(--content-primary-dark);
--checkbox-border-color: var(--border-primary-dark);
--checkbox-bg: var(--bg-dark-primary);
// Hover
--checkbox-hover-border-color: var(--border-hover-dark);
// Checked
--checkbox-checked-bg: var(--bg-accent-03);
--checkbox-checked-border-color: var(--bg-accent-03);
--checkbox-checked-background-image: #{escape-svg(
form-check-box-svg($content-primary)
)};
// Indeterminate
--checkbox-indeterminate-background-image: #{escape-svg(
form-check-indeterminate-svg($content-primary)
)};
// Checked & hover
--checkbox-hover-checked-bg: var(--bg-accent-03);
--checkbox-hover-checked-border-color: var(--bg-accent-03);
// Focus
--checkbox-focus-border-color: var(--border-primary-dark);
// Disabled
--checkbox-disabled-bg: var(--bg-dark-disabled);
--checkbox-disabled-border-color: var(--border-disabled-dark);
// Disabled & checked
--checkbox-disabled-checked-background-image: #{escape-svg(
form-check-box-svg($content-disabled-dark)
)};
// Disabled & indeterminate
--checkbox-disabled-indeterminate-background-image: #{escape-svg(
form-check-indeterminate-svg($content-disabled-dark)
)};
}
:root {
@include form-check-light;
}
@include theme('default') {
.ide-redesign-main,
.project-ds-nav-page {
@include form-check-dark;
}
}
#storybook-root {
@include theme('default') {
@include form-check-dark;
}
}
.form-check-input {
@function form-check-box-svg($color) {
@return url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/></svg>");
}
@function form-check-radio-svg($color) {
@return url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='2' fill='#{$color}'/></svg>");
}
@function form-check-indeterminate-svg($color) {
@return url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/></svg>");
}
&:hover {
&:not(:disabled) {
border-color: var(--border-hover);
@@ -59,6 +160,76 @@
}
}
// TODO: compare to live storybook
// NOTE: Nesting inside .form-checkbox to avoid affecting other form checks
// such as input switches and radio buttons.
.form-checkbox {
.form-check-input {
background-color: var(--checkbox-bg);
border-color: var(--checkbox-border-color);
&:checked,
&:indeterminate {
background-color: var(--checkbox-checked-bg);
border-color: var(--checkbox-checked-border-color);
}
&:checked {
background-image: var(--checkbox-checked-background-image);
}
&:indeterminate {
background-image: var(--checkbox-indeterminate-background-image);
}
&:hover {
&:not(:disabled) {
border-color: var(--checkbox-hover-border-color);
&:checked,
&:indeterminate {
background-color: var(--checkbox-hover-checked-bg);
border-color: var(--checkbox-hover-checked-border-color);
}
}
}
&:disabled {
background-color: var(--checkbox-disabled-bg);
border-color: var(--checkbox-disabled-border-color);
&:indeterminate {
background-color: var(--checkbox-disabled-bg);
border-color: var(--checkbox-disabled-border-color);
background-image: var(
--checkbox-disabled-indeterminate-background-image
);
}
}
// Use disabled attribute in addition of :disabled pseudo-class
// See: https://github.com/twbs/bootstrap/issues/28247
&[disabled],
&:disabled {
~ .form-check-label {
color: $input-disabled-color;
}
&:checked {
background-image: var(--checkbox-disabled-checked-background-image);
}
}
&:focus-visible {
border-color: var(--checkbox-focus-border-color);
}
}
}
.form-check-label {
color: var(--checkbox-label-color);
}
.form-control {
&[disabled],
&:disabled {
@@ -240,6 +411,10 @@
.checkbox-label {
margin-left: var(--spacing-04);
}
.form-check-label {
color: var(--checkbox-label-color);
}
}
%input-focus-style {

View File

@@ -3,8 +3,9 @@
}
.modal {
// Until we add a dark modal version, all dropdowns in modals should use light theme
// Until we add a dark modal version, all core components in modals should use light theme
@include light-dropdown-menu;
@include form-check-light;
}
@include media-breakpoint-up(sm) {