Add new axo checkbox square variant

This commit is contained in:
Jamie Kyle
2025-11-12 17:03:30 -08:00
parent bf9d36f2f0
commit b29aedf1c8
3 changed files with 62 additions and 12 deletions

View File

@@ -11,6 +11,7 @@ export default {
function Template(props: { function Template(props: {
label: string; label: string;
variant: AxoCheckbox.Variant;
defaultChecked: boolean; defaultChecked: boolean;
disabled?: boolean; disabled?: boolean;
}): JSX.Element { }): JSX.Element {
@@ -18,6 +19,7 @@ function Template(props: {
return ( return (
<label className={tw('my-2 flex items-center gap-2')}> <label className={tw('my-2 flex items-center gap-2')}>
<AxoCheckbox.Root <AxoCheckbox.Root
variant={props.variant}
checked={checked} checked={checked}
onCheckedChange={setChecked} onCheckedChange={setChecked}
disabled={props.disabled} disabled={props.disabled}
@@ -31,10 +33,30 @@ export function Basic(): JSX.Element {
return ( return (
<> <>
<h1 className={tw('type-title-large')}>AxoCheckbox</h1> <h1 className={tw('type-title-large')}>AxoCheckbox</h1>
<Template label="Unchecked" defaultChecked={false} /> {AxoCheckbox._getAllCheckboxVariants().map(variant => {
<Template label="Checked" defaultChecked /> return (
<Template label="Unchecked+Disabled" defaultChecked={false} disabled /> <section>
<Template label="Checked+Disabled" defaultChecked disabled /> <Template
variant={variant}
label="Unchecked"
defaultChecked={false}
/>
<Template variant={variant} label="Checked" defaultChecked />
<Template
variant={variant}
label="Unchecked+Disabled"
defaultChecked={false}
disabled
/>
<Template
variant={variant}
label="Checked+Disabled"
defaultChecked
disabled
/>
</section>
);
})}
</> </>
); );
} }

View File

@@ -3,13 +3,37 @@
import React, { memo } from 'react'; import React, { memo } from 'react';
import { Checkbox } from 'radix-ui'; import { Checkbox } from 'radix-ui';
import { AxoSymbol } from './AxoSymbol.dom.js'; import { AxoSymbol } from './AxoSymbol.dom.js';
import type { TailwindStyles } from './tw.dom.js';
import { tw } from './tw.dom.js'; import { tw } from './tw.dom.js';
const Namespace = 'AxoCheckbox'; const Namespace = 'AxoCheckbox';
export namespace AxoCheckbox { export namespace AxoCheckbox {
type VariantConfig = {
rootStyles: TailwindStyles;
iconSize: AxoSymbol.IconSize;
};
const Variants: Record<Variant, VariantConfig> = {
round: {
rootStyles: tw('size-5 rounded-full'),
iconSize: 14,
},
square: {
rootStyles: tw('size-4 rounded-sm'),
iconSize: 12,
},
};
export function _getAllCheckboxVariants(): ReadonlyArray<Variant> {
return Object.keys(Variants) as Array<Variant>;
}
export type Variant = 'round' | 'square';
export type RootProps = Readonly<{ export type RootProps = Readonly<{
id?: string; id?: string;
variant: Variant;
checked: boolean; checked: boolean;
onCheckedChange: (nextChecked: boolean) => void; onCheckedChange: (nextChecked: boolean) => void;
disabled?: boolean; disabled?: boolean;
@@ -17,6 +41,7 @@ export namespace AxoCheckbox {
}>; }>;
export const Root = memo((props: RootProps) => { export const Root = memo((props: RootProps) => {
const variantConfig = Variants[props.variant];
return ( return (
<Checkbox.Root <Checkbox.Root
id={props.id} id={props.id}
@@ -25,24 +50,26 @@ export namespace AxoCheckbox {
disabled={props.disabled} disabled={props.disabled}
required={props.required} required={props.required}
className={tw( className={tw(
'flex size-5 items-center justify-center rounded-full leading-none', variantConfig.rootStyles,
'flex items-center justify-center',
'border border-border-primary inset-shadow-on-color', 'border border-border-primary inset-shadow-on-color',
'data-[state=unchecked]:bg-fill-primary', 'data-[state=unchecked]:bg-fill-primary',
'data-[state=unchecked]:pressed:bg-fill-primary-pressed', 'data-[state=unchecked]:pressed:bg-fill-primary-pressed',
'data-[state=checked]:bg-color-fill-primary', 'data-[state=checked]:bg-color-fill-primary',
'data-[state=checked]:text-label-primary-on-color',
'data-[state=checked]:pressed:bg-color-fill-primary-pressed', 'data-[state=checked]:pressed:bg-color-fill-primary-pressed',
'data-[disabled]:border-border-secondary', 'data-[disabled]:border-border-secondary',
'data-[state=checked]:data-[disabled]:text-label-disabled-on-color',
'outline-0 outline-border-focused focused:outline-[2.5px]', 'outline-0 outline-border-focused focused:outline-[2.5px]',
'overflow-hidden' 'overflow-hidden'
)} )}
> >
<Checkbox.Indicator <Checkbox.Indicator asChild>
className={tw( <AxoSymbol.Icon
'data-[state=checked]:text-label-primary-on-color', symbol="check"
'data-[state=checked]:data-[disabled]:text-label-disabled-on-color' size={variantConfig.iconSize}
)} label={null}
> />
<AxoSymbol.Icon symbol="check" size={14} label={null} />
</Checkbox.Indicator> </Checkbox.Indicator>
</Checkbox.Root> </Checkbox.Root>
); );

View File

@@ -252,6 +252,7 @@ function CheckboxField(props: { label: string }) {
<div className={tw('flex gap-3 py-2.5')}> <div className={tw('flex gap-3 py-2.5')}>
<AxoCheckbox.Root <AxoCheckbox.Root
id={id} id={id}
variant="square"
checked={checked} checked={checked}
onCheckedChange={setChecked} onCheckedChange={setChecked}
/> />