-
-
Notifications
You must be signed in to change notification settings - Fork 35
/
primitive.ts
104 lines (87 loc) · 3.09 KB
/
primitive.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
102
103
104
import type { DefineComponent, FunctionalComponent, IntrinsicElementAttributes, VNodeRef } from 'vue'
import { defineComponent, h, onMounted } from 'vue'
/* -------------------------------------------------------------------------------------------------
* Primitive
* ----------------------------------------------------------------------------------------------- */
const NODES = [
'a',
'button',
'div',
'form',
'h2',
'h3',
'img',
'input',
'label',
'li',
'nav',
'ol',
'p',
'span',
'svg',
'ul',
] as const
type ElementConstructor<P> =
| (new () => { $props: P })
| ((props: P, ...args: any) => FunctionalComponent<any, any>)
// extends keyof JSX.IntrinsicElements | ElementConstructor<any>
type ComponentProps<T extends keyof JSX.IntrinsicElements | ElementConstructor<any>> =
T extends ElementConstructor<infer P>
? P
: T extends keyof JSX.IntrinsicElements
? JSX.IntrinsicElements[T]
: {}
type ComponentType<T = {}> = DefineComponent<T> | FunctionalComponent<T>
type ComponentPropsWithoutRef<T extends ElementType> = PropsWithoutRef<
ComponentProps<T>
>
type ElementType<P = any> = {
[K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] ? K : never
}[keyof JSX.IntrinsicElements] |
ComponentType<P>
type PropsWithoutRef<P> = P extends any ? ('ref' extends keyof P ? Pick<P, Exclude<keyof P, 'ref'>> : P) : P
type PropsWithRef<P> =
'ref' extends keyof P
? P extends { ref?: infer R | undefined }
? string extends R
// TODO: ref dynamic `IntrinsicElements` support
? PropsWithoutRef<P> & { ref?: VNodeRef | undefined }
: any
: any
: any
type VueComponentPropsWithRef<T extends ElementType> =
T extends new () => { $props: infer P }
// TODO: ref dynamic `IntrinsicElements` support, `VNodeRef` dont support T
? PropsWithoutRef<P> & { ref?: VNodeRef | undefined }
: PropsWithRef<ComponentProps<T>>
type Primitives = { [E in typeof NODES[number]]: PrimitiveDefineComponent<E> }
type PrimitivePropsWithRef<E extends ElementType> = VueComponentPropsWithRef<E> & {
asChild?: boolean
}
type ElementRef<T extends keyof JSX.IntrinsicElements | ElementConstructor<any>> =
T extends PrimitiveDefineComponent<infer E>
? E extends keyof IntrinsicElementAttributes
? IntrinsicElementAttributes[E]
: never
: never
interface PrimitiveDefineComponent<E extends ElementType> extends DefineComponent<PrimitivePropsWithRef<E>> {}
const Primitive = NODES.reduce((primitive, node) => {
const Node = defineComponent<PrimitivePropsWithRef<typeof node>>({
name: `Primitive${node}`,
inheritAttrs: false,
setup(props, { attrs, slots }) {
onMounted(() => {
(window as any)[Symbol.for('oku-ui')] = true
})
const Tag: any = props.asChild ? 'slot' : node
return () => props.asChild ? slots.default?.() : h(Tag, { ...attrs }, slots.default?.())
},
})
return { ...primitive, [node]: Node }
}, {} as Primitives)
const OkuPrimitive = Primitive
export {
OkuPrimitive,
Primitive,
}
export type { ComponentPropsWithoutRef, ElementRef }