Skip to content

Commit

Permalink
feat: collapse now allows onOpen, onClose, and onToggle props (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
christianblandford committed Jul 13, 2022
1 parent 1efbc39 commit c9deedf
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 4 deletions.
74 changes: 73 additions & 1 deletion src/Collapse/Collapse.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useState } from 'react'
import { Story, Meta } from '@storybook/react'

import Collapse, { CollapseProps } from '.'
Expand Down Expand Up @@ -83,3 +83,75 @@ export const CustomColorsWithFocusCheckbox: Story<CollapseProps> = (args) => {
</Collapse>
)
}

export const HandlingEvents: Story<CollapseProps> = (args) => {
const [isOpen, setIsOpen] = useState(false)

const handleToggle = () => {
console.log('toggled!')
}

const handleOpen = () => {
setIsOpen(true)
}

const handleClose = () => {
setIsOpen(false)
}

return (
<div>
<span>Checkbox is {isOpen ? 'open' : 'closed'}.</span>
<Collapse
{...args}
className="group"
onClose={handleClose}
onOpen={handleOpen}
onToggle={handleToggle}
>
<Collapse.Title className="bg-primary text-primary-content peer-checked:bg-secondary peer-checked:text-secondary-content">
Click me to show/hide content
</Collapse.Title>
<Collapse.Content className="bg-primary text-primary-content peer-checked:bg-secondary peer-checked:text-secondary-content">
<p>tabindex="0" attribute is necessary to make the div focusable</p>
</Collapse.Content>
</Collapse>
</div>
)
}

export const CheckboxEvents: Story<CollapseProps> = (args) => {
const [isOpen, setIsOpen] = useState(false)
const handleToggle = () => {
console.log('toggled!')
}

const handleOpen = () => {
setIsOpen(true)
}

const handleClose = () => {
setIsOpen(false)
}

return (
<div>
<span>Checkbox is {isOpen ? 'open' : 'closed'}.</span>
<Collapse
{...args}
className="group"
onClose={handleClose}
onOpen={handleOpen}
onToggle={handleToggle}
checkbox
>
<Collapse.Title className="bg-primary text-primary-content peer-checked:bg-secondary peer-checked:text-secondary-content">
Click me to show/hide content
</Collapse.Title>
<Collapse.Content className="bg-primary text-primary-content peer-checked:bg-secondary peer-checked:text-secondary-content">
<p>tabindex="0" attribute is necessary to make the div focusable</p>
</Collapse.Content>
</Collapse>
</div>
)
}
57 changes: 54 additions & 3 deletions src/Collapse/Collapse.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { MutableRefObject, useEffect, useRef } from 'react'
import clsx from 'clsx'
import { twMerge } from 'tailwind-merge'

Expand All @@ -12,11 +12,25 @@ export type CollapseProps = React.HTMLAttributes<HTMLDivElement> &
checkbox?: boolean
icon?: 'arrow' | 'plus'
open?: boolean
onOpen?: () => void
onClose?: () => void
onToggle?: () => void
}

const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>(
(
{ children, checkbox, icon, open, dataTheme, className, ...props },
{
children,
checkbox,
icon,
open,
dataTheme,
className,
onOpen,
onClose,
onToggle,
...props
},
ref
): JSX.Element => {
const classes = twMerge(
Expand All @@ -29,6 +43,34 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>(
})
)

const checkboxRef = useRef<HTMLInputElement>(null)

// Handle events for checkbox changes
const handleCheckboxChange = () => {
if (onToggle) {
onToggle()
}
if (onOpen && checkboxRef.current?.checked) {
onOpen()
} else if (onClose && !checkboxRef.current?.checked) {
onClose()
}
}

// Handle blur events, specifically handling open/close for non checkbox types
const handleBlur = (event: React.FocusEvent<HTMLDivElement, Element>) => {
if (!checkbox && onToggle) onToggle()
if (!checkbox && onClose) onClose()
if (props.onBlur) props.onBlur(event)
}

// Handle focus events, specifically handling open/close for non checkbox types
const handleFocus = (event: React.FocusEvent<HTMLDivElement, Element>) => {
if (!checkbox && onToggle) onToggle()
if (!checkbox && onOpen) onOpen()
if (props.onFocus) props.onFocus(event)
}

return (
<div
aria-expanded={open}
Expand All @@ -37,8 +79,17 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>(
tabIndex={0}
data-theme={dataTheme}
className={classes}
onBlur={handleBlur}
onFocus={handleFocus}
>
{checkbox && <input type="checkbox" className="peer" />}
{checkbox && (
<input
type="checkbox"
className="peer"
ref={checkboxRef}
onChange={handleCheckboxChange}
/>
)}
{children}
</div>
)
Expand Down

0 comments on commit c9deedf

Please sign in to comment.