Skip to content
This repository was archived by the owner on Sep 20, 2024. It is now read-only.

Commit 0cf2170

Browse files
feat(use-disclosure): build composable
1 parent 3224e15 commit 0cf2170

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { computed, HTMLAttributes, ref, watchEffect } from "vue"
2+
import { useId } from "./use-id"
3+
4+
export interface UseDisclosureProps {
5+
isOpen?: boolean
6+
defaultIsOpen?: boolean
7+
onClose?(): void
8+
onOpen?(): void
9+
id?: string
10+
}
11+
12+
export function useDisclosure(props: UseDisclosureProps = {}) {
13+
const {
14+
isOpen: isOpenProp,
15+
onClose: handleClose,
16+
onOpen: handleOpen,
17+
id: idProp,
18+
defaultIsOpen,
19+
} = props
20+
21+
const isOpenState = ref(defaultIsOpen || false)
22+
23+
const isOpen = ref<boolean>()
24+
25+
const isControlled = isOpenProp !== undefined
26+
27+
const uid = useId().value
28+
const id = computed(() => idProp ?? `disclosure-${uid}`)
29+
30+
const onClose = () => {
31+
if (!isControlled) {
32+
isOpenState.value = false
33+
}
34+
handleClose?.()
35+
}
36+
37+
const onOpen = () => {
38+
if (!isControlled) {
39+
isOpenState.value = true
40+
}
41+
handleOpen?.()
42+
}
43+
44+
const onToggle = () => (isOpen.value ? onClose() : onOpen())
45+
46+
/**
47+
* Ref object containing the HTML attributes for the button that
48+
* is triggering the disclosure state
49+
*
50+
* `NOTE:` Pass this to the v-bind of the element.
51+
*
52+
* i.e. `v-bind='buttonProps'`
53+
*/
54+
const buttonProps = ref<HTMLAttributes>()
55+
56+
/**
57+
* Ref object containing the HTML attributes for the element that
58+
* is being effected by the disclosure state.
59+
*
60+
* `NOTE:` Pass this to the v-bind of the element.
61+
*
62+
* i.e. `v-bind='disclosureProps'`
63+
*/
64+
const disclosureProps = ref<HTMLAttributes>()
65+
66+
watchEffect(() => {
67+
isOpen.value = isOpenProp !== undefined ? isOpenProp : isOpenState.value
68+
69+
buttonProps.value = {
70+
"aria-expanded": isOpen.value,
71+
"aria-controls": id.value,
72+
onClick() {
73+
onToggle()
74+
},
75+
}
76+
77+
disclosureProps.value = {
78+
hidden: !isOpen.value,
79+
id: id.value,
80+
}
81+
})
82+
83+
return {
84+
isOpen: isOpen.value,
85+
onOpen,
86+
onClose,
87+
onToggle,
88+
isControlled,
89+
buttonProps,
90+
disclosureProps,
91+
}
92+
}

0 commit comments

Comments
 (0)