wip(vapor): custom directives

This commit is contained in:
Evan You 2025-02-08 21:32:16 +08:00
parent cd93dad4d9
commit 8549a243a5
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
4 changed files with 51 additions and 5 deletions

View File

@ -57,7 +57,6 @@ function genCustomDirectives(
return [
NEWLINE,
// @ts-expect-error
...genCall(helper('withVaporDirectives'), element, directives),
]

View File

@ -0,0 +1,36 @@
import type { DirectiveModifiers } from '@vue/runtime-dom'
import type { VaporComponentInstance } from '../component'
import { renderEffect } from '../renderEffect'
// !! vapor directive is different from vdom directives
export type VaporDirective = (
node: Element | VaporComponentInstance,
value?: () => any,
argument?: string,
modifiers?: DirectiveModifiers,
) => (() => void) | void
type DirectiveArguments = Array<
| [VaporDirective | undefined]
| [VaporDirective | undefined, () => any]
| [VaporDirective | undefined, () => any, argument: string]
| [
VaporDirective | undefined,
value: () => any,
argument: string,
modifiers: DirectiveModifiers,
]
>
export function withVaporDirectives(
node: Element | VaporComponentInstance,
dirs: DirectiveArguments,
): void {
// TODO handle custom directive on component
for (const [dir, value, argument, modifiers] of dirs) {
if (dir) {
const ret = dir(node, value, argument, modifiers)
if (ret) renderEffect(ret)
}
}
}

View File

@ -1,4 +1,5 @@
import {
currentInstance,
onMounted,
vModelCheckboxInit,
vModelCheckboxUpdate,
@ -26,12 +27,20 @@ type VaporModelDirective<
modifiers?: { [key in Modifiers]?: true },
) => void
function ensureMounted(cb: () => void) {
if (currentInstance!.isMounted) {
cb()
} else {
onMounted(cb)
}
}
export const applyTextModel: VaporModelDirective<
HTMLInputElement | HTMLTextAreaElement,
'trim' | 'number' | 'lazy'
> = (el, get, set, { trim, number, lazy } = {}) => {
vModelTextInit(el, trim, number, lazy, set)
onMounted(() => {
ensureMounted(() => {
let value: any
renderEffect(() => {
vModelTextUpdate(el, value, (value = get()), trim, number, lazy)
@ -45,7 +54,7 @@ export const applyCheckboxModel: VaporModelDirective<HTMLInputElement> = (
set,
) => {
vModelCheckboxInit(el, set)
onMounted(() => {
ensureMounted(() => {
let value: any
renderEffect(() => {
vModelCheckboxUpdate(
@ -64,7 +73,7 @@ export const applyRadioModel: VaporModelDirective<HTMLInputElement> = (
set,
) => {
addEventListener(el, 'change', () => set(vModelGetValue(el)))
onMounted(() => {
ensureMounted(() => {
let value: any
renderEffect(() => {
if (value !== (value = get())) {
@ -79,7 +88,7 @@ export const applySelectModel: VaporModelDirective<
'number'
> = (el, get, set, modifiers) => {
vModelSelectInit(el, get(), modifiers && modifiers.number, set)
onMounted(() => {
ensureMounted(() => {
renderEffect(() => vModelSetSelected(el, traverse(get())))
})
}

View File

@ -2,6 +2,7 @@
export { createVaporApp } from './apiCreateApp'
export { defineVaporComponent } from './apiDefineComponent'
export { vaporInteropPlugin } from './vdomInterop'
export type { VaporDirective } from './directives/custom'
// compiler-use only
export { insert, prepend, remove } from './block'
@ -39,3 +40,4 @@ export {
applySelectModel,
applyDynamicModel,
} from './directives/vModel'
export { withVaporDirectives } from './directives/custom'