Skip to content

Commit

Permalink
Checkbox and CheckboxGroup
Browse files Browse the repository at this point in the history
  • Loading branch information
lerte committed Nov 16, 2024
1 parent 8f30e91 commit 0c5503c
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 19 deletions.
39 changes: 35 additions & 4 deletions apps/docs/src/usages/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,51 @@
import { Checkbox, CheckboxGroup } from 'actify'

import React from 'react'
import React, { useEffect, useState } from 'react'

export default () => {
const [selected, setSelected] = useState(['actify'])

const [isIndeterminate, setIsIndeterminate] = useState(false)
const [allSelected, setAllSelected] = useState(false)

useEffect(() => {
if (selected.length >= 1) {
if (selected.length == 4) {
setIsIndeterminate(false)
setAllSelected(true)
} else {
setAllSelected(false)
setIsIndeterminate(true)
}
} else {
setIsIndeterminate(false)
setAllSelected(false)
}
}, [selected])

return (
<>
<div className="flex flex-wrap gap-4">
<Checkbox isIndeterminate aria-label="isIndeterminate" />
<Checkbox color="primary" defaultSelected>
Primary
</Checkbox>
<Checkbox color="secondary" aria-label="secondary" />
<Checkbox color="tertiary" aria-label="tertiary" />
<Checkbox color="error" aria-label="error" />
</div>
<CheckboxGroup label="Project">
<Checkbox
isIndeterminate={isIndeterminate}
isSelected={allSelected}
onChange={() => {
setSelected(
selected.length == 4
? []
: ['actify', 'ngroker', 'taildoor', 'hugola']
)
}}
>
Check all
</Checkbox>
<CheckboxGroup label="Project" value={selected} onChange={setSelected}>
<Checkbox value="actify">Actify</Checkbox>
<Checkbox value="ngroker">Ngroker</Checkbox>
<Checkbox value="taildoor">Taildoor</Checkbox>
Expand Down
43 changes: 31 additions & 12 deletions packages/actify/src/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,55 @@
'use client'

import {
AriaCheckboxGroupItemProps,
AriaCheckboxProps,
mergeProps,
useCheckbox,
useFocusRing
} from 'react-aria'
import { CheckboxGroupState, useToggleState } from 'react-stately'
import React, { useId } from 'react'
import { useCheckboxGroup, useCheckboxGroupItem } from 'react-aria'

import { CheckboxGroupContext } from './CheckboxGroup'
import { FocusRing } from './../FocusRing'
import { Label } from './../Label'
import { Ripple } from './../Ripple'
import clsx from 'clsx'
import styles from './checkbox.module.css'
import { useToggleState } from 'react-stately'

type CheckboxProps = {
interface CheckboxProps extends AriaCheckboxProps {
ref?: React.RefObject<HTMLInputElement>
color?: 'primary' | 'secondary' | 'tertiary' | 'error'
} & AriaCheckboxProps
}

const Checkbox = (props: CheckboxProps) => {
const { id, isDisabled } = props
const _id = `actify-checkbox${useId()}`
const _inputRef = React.useRef(null)

const state = useToggleState(props)
const inputRef = React.useRef(null)
const { id = _id, ref: inputRef = _inputRef } = props

const { inputProps } = useCheckbox(props, state, inputRef)
const { isFocusVisible, focusProps } = useFocusRing()
const groupState = React.useContext(CheckboxGroupContext)
const toggleState = useToggleState(props)

const state = groupState ?? toggleState

const isSelected = state.isSelected && !props.isIndeterminate
const { inputProps } = groupState
? useCheckboxGroupItem(
props as AriaCheckboxGroupItemProps,
state as CheckboxGroupState,
inputRef
)
: useCheckbox(props, toggleState, inputRef)

const checkboxId = id || `actify-checkbox${useId()}`
const isSelected = groupState
? (state as CheckboxGroupState).isSelected(props.value as string)
: state.isSelected && !props.isIndeterminate
const isDisabled = groupState
? (state as CheckboxGroupState).isDisabled
: props.isDisabled

const { isFocusVisible, focusProps } = useFocusRing()

return (
<Label
Expand All @@ -42,8 +61,8 @@ const Checkbox = (props: CheckboxProps) => {
<div role="presentation" className={styles['checkbox']}>
<div className={styles['container']}>
<input
id={id}
ref={inputRef}
id={checkboxId}
role="checkbox"
className={styles['input']}
{...mergeProps(inputProps, focusProps)}
Expand Down Expand Up @@ -74,7 +93,7 @@ const Checkbox = (props: CheckboxProps) => {
/>
)}
<Ripple
id={checkboxId}
id={id}
disabled={isDisabled}
style={{
width: '40px',
Expand Down
5 changes: 2 additions & 3 deletions packages/actify/src/components/Checkbox/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import { Label } from '../Label'
import React from 'react'
import { useCheckboxGroup } from 'react-aria'

const CheckboxGroupContext = React.createContext<CheckboxGroupState | null>(
null
)
export const CheckboxGroupContext =
React.createContext<CheckboxGroupState | null>(null)

interface Props extends CheckboxGroupProps {
children?: React.ReactNode
Expand Down

0 comments on commit 0c5503c

Please sign in to comment.