-
-
Notifications
You must be signed in to change notification settings - Fork 35
/
BubbleInput.ts
101 lines (88 loc) · 2.49 KB
/
BubbleInput.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import type { ElementType, MergeProps } from '@oku-ui/primitive'
import { useForwardRef, usePrevious, useSize } from '@oku-ui/use-composable'
import type {
CSSProperties,
Ref,
} from 'vue'
import {
defineComponent,
h,
onMounted,
ref,
toRefs,
watchEffect,
} from 'vue'
const BUBBLE_INPUT = 'OkuBubbleInput'
type InputElement = ElementType<'input'>
export type _BubbleInputEl = HTMLInputElement
interface BubbleInputProps extends Omit<InputElement, 'checked'> {
checked: boolean
control: HTMLElement | null
bubbles: boolean
}
export const BubbleInput = defineComponent({
name: BUBBLE_INPUT,
inheritAttrs: false,
props: {
checked: {
type: Boolean,
default: undefined,
},
bubbles: {
type: Boolean,
default: undefined,
},
control: {
type: Object,
required: undefined,
},
},
setup(props, { attrs }) {
const { control, checked, bubbles } = toRefs(props)
const { ...inputAttrs } = attrs as InputElement
const inputRef = ref<HTMLInputElement | null>(null)
const prevChecked = usePrevious(checked)
const controlSize = useSize(control as Ref<HTMLElement>)
const forwardedRef = useForwardRef()
onMounted(() => {
watchEffect(() => {
const input = inputRef.value!
const inputProto = window.HTMLInputElement.prototype
const descriptor = Object.getOwnPropertyDescriptor(
inputProto,
'checked',
) as PropertyDescriptor
const setChecked = descriptor.set
if (prevChecked.value !== checked.value && setChecked) {
const event = new Event('click', { bubbles: bubbles.value })
setChecked.call(input, checked.value)
input.dispatchEvent(event)
}
})
})
const originalReturn = () =>
h('input', {
'type': 'checkbox',
'aria-hidden': true,
'defaultChecked': checked.value,
// TODO: 'value': inputAttrs.value does not work
...inputAttrs,
'tabindex': -1,
'ref': forwardedRef,
'style': {
...((inputAttrs.style as CSSProperties) || {}),
...controlSize.value,
position: 'absolute',
pointerEvents: 'none',
opacity: 0,
margin: 0,
},
})
return originalReturn
},
})
type _BubbleInput = MergeProps<BubbleInputProps, InputElement>
const OkuBubbleInput = BubbleInput as typeof BubbleInput &
(new () => { $props: _BubbleInput })
export { OkuBubbleInput }
export type { BubbleInputProps }