]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip(vapor): simplified builtin directive v-show
authorEvan You <evan@vuejs.org>
Fri, 31 Jan 2025 14:18:32 +0000 (22:18 +0800)
committerEvan You <evan@vuejs.org>
Fri, 31 Jan 2025 14:29:51 +0000 (22:29 +0800)
16 files changed:
packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vShow.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vModel.spec.ts
packages/compiler-vapor/src/generators/directive.ts
packages/compiler-vapor/src/generators/operation.ts
packages/compiler-vapor/src/generators/vModel.ts [new file with mode: 0644]
packages/compiler-vapor/src/generators/vShow.ts [new file with mode: 0644]
packages/compiler-vapor/src/ir/index.ts
packages/compiler-vapor/src/transforms/transformElement.ts
packages/compiler-vapor/src/transforms/transformSlotOutlet.ts
packages/compiler-vapor/src/transforms/vModel.ts
packages/compiler-vapor/src/transforms/vShow.ts
packages/runtime-dom/src/directives/vShow.ts
packages/runtime-dom/src/index.ts
packages/runtime-vapor/src/directives/vShow.ts [new file with mode: 0644]
packages/runtime-vapor/src/index.ts

index 2d553fcea850a854a72aa9c26905a5d96c09f9b5..dfdee6485a82e771af53e6df2be314a9402ec92e 100644 (file)
@@ -12,20 +12,20 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
 `;
 
 exports[`compile > custom directive > basic 1`] = `
-"import { resolveDirective as _resolveDirective, withDirectives as _withDirectives, template as _template } from 'vue';
+"import { resolveDirective as _resolveDirective, withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const _directive_test = _resolveDirective("test")
   const _directive_hello = _resolveDirective("hello")
   const n0 = t0()
-  _withDirectives(n0, [[_directive_test], [_directive_hello, void 0, void 0, { world: true }]])
+  _withVaporDirectives(n0, [[_directive_test], [_directive_hello, void 0, void 0, { world: true }]])
   return n0
 }"
 `;
 
 exports[`compile > custom directive > component 1`] = `
-"import { resolveComponent as _resolveComponent, resolveDirective as _resolveDirective, createComponentWithFallback as _createComponentWithFallback, withDirectives as _withDirectives, insert as _insert, createIf as _createIf, template as _template } from 'vue';
+"import { resolveComponent as _resolveComponent, resolveDirective as _resolveDirective, createComponentWithFallback as _createComponentWithFallback, withVaporDirectives as _withVaporDirectives, insert as _insert, createIf as _createIf, template as _template } from 'vue';
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
@@ -38,91 +38,91 @@ export function render(_ctx) {
       const n0 = _createIf(() => (true), () => {
         const n3 = t0()
         const n2 = _createComponentWithFallback(_component_Bar)
-        _withDirectives(n2, [[_directive_hello, void 0, void 0, { world: true }]])
+        _withVaporDirectives(n2, [[_directive_hello, void 0, void 0, { world: true }]])
         _insert(n2, n3)
         return n3
       })
       return n0
     }
   }, true)
-  _withDirectives(n4, [[_directive_test]])
+  _withVaporDirectives(n4, [[_directive_test]])
   return n4
 }"
 `;
 
 exports[`compile > directives > custom directive > basic 1`] = `
-"import { withDirectives as _withDirectives, template as _template } from 'vue';
+"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  _withDirectives(n0, [[_ctx.vExample]])
+  _withVaporDirectives(n0, [[_ctx.vExample]])
   return n0
 }"
 `;
 
 exports[`compile > directives > custom directive > binding value 1`] = `
-"import { withDirectives as _withDirectives, template as _template } from 'vue';
+"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg]])
+  _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg]])
   return n0
 }"
 `;
 
 exports[`compile > directives > custom directive > dynamic parameters 1`] = `
-"import { withDirectives as _withDirectives, template as _template } from 'vue';
+"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg, _ctx.foo]])
+  _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg, _ctx.foo]])
   return n0
 }"
 `;
 
 exports[`compile > directives > custom directive > modifiers 1`] = `
-"import { withDirectives as _withDirectives, template as _template } from 'vue';
+"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg, void 0, { bar: true }]])
+  _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg, void 0, { bar: true }]])
   return n0
 }"
 `;
 
 exports[`compile > directives > custom directive > modifiers w/o binding 1`] = `
-"import { withDirectives as _withDirectives, template as _template } from 'vue';
+"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  _withDirectives(n0, [[_ctx.vExample, void 0, void 0, { "foo-bar": true }]])
+  _withVaporDirectives(n0, [[_ctx.vExample, void 0, void 0, { "foo-bar": true }]])
   return n0
 }"
 `;
 
 exports[`compile > directives > custom directive > static parameters 1`] = `
-"import { withDirectives as _withDirectives, template as _template } from 'vue';
+"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg, "foo"]])
+  _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg, "foo"]])
   return n0
 }"
 `;
 
 exports[`compile > directives > custom directive > static parameters and modifiers 1`] = `
-"import { withDirectives as _withDirectives, template as _template } from 'vue';
+"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  _withDirectives(n0, [[_ctx.vExample, () => _ctx.msg, "foo", { bar: true }]])
+  _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg, "foo", { bar: true }]])
   return n0
 }"
 `;
index 07b8d05b1107f65bcb092dd64ef8f8ec0f203f6e..f595da5ef8f964f9f83a2647e330a02ead268b85 100644 (file)
@@ -1,12 +1,12 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`compiler: v-show transform > simple expression 1`] = `
-"import { vShow as _vShow, withDirectives as _withDirectives, template as _template } from 'vue';
+"import { applyVShow as _applyVShow, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
-  _withDirectives(n0, [[_vShow, () => _ctx.foo]])
+  _applyVShow(n0, () => (_ctx.foo))
   return n0
 }"
 `;
index 560bc37b9738b42ad782be1ac17f812f9333eb71..1b3d47f3fa00ab16503fe04eb0f4072bde0be5d8 100644 (file)
@@ -14,7 +14,7 @@ const compileWithVModel = makeCompile({
   },
 })
 
-describe('compiler: vModel transform', () => {
+describe.todo('compiler: vModel transform', () => {
   test('should support simple expression', () => {
     const { code, helpers } = compileWithVModel('<input v-model="model" />')
     expect(code).toMatchSnapshot()
index ae75a273e3e257692edbfc61441f1df61b7a18d3..6321ad216f8f74a35a03728c0284ffd7701a8be3 100644 (file)
@@ -14,39 +14,64 @@ import {
   genCall,
   genMulti,
 } from './utils'
-import {
-  IRNodeTypes,
-  type OperationNode,
-  type WithDirectiveIRNode,
-} from '../ir'
+import { type DirectiveIRNode, IRNodeTypes, type OperationNode } from '../ir'
+import { genVShow } from './vShow'
+import { genVModel } from './vModel'
 
+export function genBuiltinDirective(
+  oper: DirectiveIRNode,
+  context: CodegenContext,
+): CodeFragment[] {
+  switch (oper.name) {
+    case 'show':
+      return genVShow(oper, context)
+    case 'model':
+      return genVModel(oper, context)
+    default:
+      return []
+  }
+}
+
+/**
+ * user directives via `withVaporDirectives`
+ * TODO the compiler side is implemented but no runtime support yet
+ * it was removed due to perf issues
+ */
 export function genDirectivesForElement(
   id: number,
   context: CodegenContext,
 ): CodeFragment[] {
-  const dirs = filterDirectives(id, context.block.operation)
-  return dirs.length ? genWithDirective(dirs, context) : []
+  const dirs = filterCustomDirectives(id, context.block.operation)
+  return dirs.length ? genCustomDirectives(dirs, context) : []
 }
 
-export function genWithDirective(
-  opers: WithDirectiveIRNode[],
+function genCustomDirectives(
+  opers: DirectiveIRNode[],
   context: CodegenContext,
 ): CodeFragment[] {
   const { helper } = context
 
   const element = `n${opers[0].element}`
-  const directiveItems = opers.map(genDirective)
+  const directiveItems = opers.map(genDirectiveItem)
   const directives = genMulti(DELIMITERS_ARRAY, ...directiveItems)
 
-  return [NEWLINE, ...genCall(helper('withDirectives'), element, directives)]
+  return [
+    NEWLINE,
+    // @ts-expect-error
+    ...genCall(helper('withVaporDirectives'), element, directives),
+  ]
 
-  function genDirective({
+  function genDirectiveItem({
     dir,
     name,
-    builtin,
     asset,
-  }: WithDirectiveIRNode): CodeFragment[] {
-    const directive = genDirective()
+  }: DirectiveIRNode): CodeFragment[] {
+    const directiveVar = asset
+      ? toValidAssetId(name, 'directive')
+      : genExpression(
+          extend(createSimpleExpression(name, false), { ast: null }),
+          context,
+        )
     const value = dir.exp && ['() => ', ...genExpression(dir.exp, context)]
     const argument = dir.arg && genExpression(dir.arg, context)
     const modifiers = !!dir.modifiers.length && [
@@ -57,24 +82,11 @@ export function genWithDirective(
 
     return genMulti(
       DELIMITERS_ARRAY.concat('void 0') as CodeFragmentDelimiters,
-      directive,
+      directiveVar,
       value,
       argument,
       modifiers,
     )
-
-    function genDirective() {
-      if (builtin) {
-        return helper(name as any)
-      } else if (asset) {
-        return toValidAssetId(name, 'directive')
-      } else {
-        return genExpression(
-          extend(createSimpleExpression(name, false), { ast: null }),
-          context,
-        )
-      }
-    }
   }
 }
 
@@ -87,12 +99,14 @@ export function genDirectiveModifiers(modifiers: string[]): string {
     .join(', ')
 }
 
-function filterDirectives(
+function filterCustomDirectives(
   id: number,
   operations: OperationNode[],
-): WithDirectiveIRNode[] {
+): DirectiveIRNode[] {
   return operations.filter(
-    (oper): oper is WithDirectiveIRNode =>
-      oper.type === IRNodeTypes.WITH_DIRECTIVE && oper.element === id,
+    (oper): oper is DirectiveIRNode =>
+      oper.type === IRNodeTypes.DIRECTIVE &&
+      oper.element === id &&
+      !oper.builtin,
   )
 }
index d8a57edea926da89465273dc6cd748d85d7e0f59..5159348fd160ff59308ec153ef8886235f039f2e 100644 (file)
@@ -19,6 +19,7 @@ import {
 import { genCreateComponent } from './component'
 import { genSlotOutlet } from './slotOutlet'
 import { processExpressions } from './expression'
+import { genBuiltinDirective } from './directive'
 
 export function genOperations(
   opers: OperationNode[],
@@ -68,8 +69,8 @@ export function genOperation(
       return genDeclareOldRef(oper)
     case IRNodeTypes.SLOT_OUTLET_NODE:
       return genSlotOutlet(oper, context)
-    case IRNodeTypes.WITH_DIRECTIVE:
-      return [] // TODO
+    case IRNodeTypes.DIRECTIVE:
+      return genBuiltinDirective(oper, context)
     default:
       const exhaustiveCheck: never = oper
       throw new Error(
diff --git a/packages/compiler-vapor/src/generators/vModel.ts b/packages/compiler-vapor/src/generators/vModel.ts
new file mode 100644 (file)
index 0000000..aab7804
--- /dev/null
@@ -0,0 +1,48 @@
+import type { CodegenContext } from '../generate'
+import type { DirectiveIRNode } from '../ir'
+import type { CodeFragment } from './utils'
+
+export function genVModel(
+  oper: DirectiveIRNode,
+  context: CodegenContext,
+): CodeFragment[] {
+  return []
+}
+
+import { camelize } from '@vue/shared'
+import { genExpression } from './expression'
+import type { SetModelValueIRNode } from '../ir'
+import { NEWLINE, genCall } from './utils'
+import type { SimpleExpressionNode } from '@vue/compiler-dom'
+
+export function genSetModelValue(
+  oper: SetModelValueIRNode,
+  context: CodegenContext,
+): CodeFragment[] {
+  const { helper } = context
+  const name = oper.key.isStatic
+    ? [JSON.stringify(`update:${camelize(oper.key.content)}`)]
+    : ['`update:${', ...genExpression(oper.key, context), '}`']
+
+  const handler = genModelHandler(oper.value, context)
+
+  return [
+    NEWLINE,
+    ...genCall(helper('delegate'), `n${oper.element}`, name, handler),
+  ]
+}
+
+export function genModelHandler(
+  value: SimpleExpressionNode,
+  context: CodegenContext,
+): CodeFragment[] {
+  const {
+    options: { isTS },
+  } = context
+
+  return [
+    `() => ${isTS ? `($event: any)` : `$event`} => (`,
+    ...genExpression(value, context, '$event'),
+    ')',
+  ]
+}
diff --git a/packages/compiler-vapor/src/generators/vShow.ts b/packages/compiler-vapor/src/generators/vShow.ts
new file mode 100644 (file)
index 0000000..9a6ccef
--- /dev/null
@@ -0,0 +1,18 @@
+import type { CodegenContext } from '../generate'
+import type { DirectiveIRNode } from '../ir'
+import { genExpression } from './expression'
+import { type CodeFragment, NEWLINE, genCall } from './utils'
+
+export function genVShow(
+  oper: DirectiveIRNode,
+  context: CodegenContext,
+): CodeFragment[] {
+  return [
+    NEWLINE,
+    ...genCall(context.helper('applyVShow'), `n${oper.element}`, [
+      `() => (`,
+      ...genExpression(oper.dir.exp!, context),
+      `)`,
+    ]),
+  ]
+}
index 3af8af961d7d5210d975219c8399c6932641a1d6..f51591f374d9c93717068e114d7d74f8dab352cf 100644 (file)
@@ -31,7 +31,7 @@ export enum IRNodeTypes {
   CREATE_COMPONENT_NODE,
   SLOT_OUTLET_NODE,
 
-  WITH_DIRECTIVE,
+  DIRECTIVE,
   DECLARE_OLD_REF, // consider make it more general
 
   IF,
@@ -183,13 +183,14 @@ export interface PrependNodeIRNode extends BaseIRNode {
   parent: number
 }
 
-export interface WithDirectiveIRNode extends BaseIRNode {
-  type: IRNodeTypes.WITH_DIRECTIVE
+export interface DirectiveIRNode extends BaseIRNode {
+  type: IRNodeTypes.DIRECTIVE
   element: number
   dir: VaporDirectiveNode
   name: string
   builtin?: boolean
   asset?: boolean
+  modelType?: 'text' | 'dynamic' | 'radio' | 'checkbox' | 'select'
 }
 
 export interface CreateComponentIRNode extends BaseIRNode {
@@ -230,7 +231,7 @@ export type OperationNode =
   | CreateTextNodeIRNode
   | InsertNodeIRNode
   | PrependNodeIRNode
-  | WithDirectiveIRNode
+  | DirectiveIRNode
   | IfIRNode
   | ForIRNode
   | CreateComponentIRNode
index 1a1242a7ee6f6187dd4046306c4575e90b6e7a20..5963c14ccec8fb2a41af9a5064b1faef16651c8a 100644 (file)
@@ -381,7 +381,7 @@ function transformProp(
     }
 
     context.registerOperation({
-      type: IRNodeTypes.WITH_DIRECTIVE,
+      type: IRNodeTypes.DIRECTIVE,
       element: context.reference(),
       dir: prop,
       name,
index 5db2e1fcb8b94f822281e840e3247717f6be2de4..a3652cbacd9d55189f57001118d8f30a4f881237 100644 (file)
@@ -13,11 +13,11 @@ import {
 import type { NodeTransform, TransformContext } from '../transform'
 import {
   type BlockIRNode,
+  type DirectiveIRNode,
   DynamicFlag,
   IRNodeTypes,
   type IRProps,
   type VaporDirectiveNode,
-  type WithDirectiveIRNode,
 } from '../ir'
 import { camelize, extend } from '@vue/shared'
 import { newBlock } from './utils'
@@ -85,8 +85,8 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
     irProps = isDynamic ? props : [props]
 
     const runtimeDirective = context.block.operation.find(
-      (oper): oper is WithDirectiveIRNode =>
-        oper.type === IRNodeTypes.WITH_DIRECTIVE && oper.element === id,
+      (oper): oper is DirectiveIRNode =>
+        oper.type === IRNodeTypes.DIRECTIVE && oper.element === id,
     )
     if (runtimeDirective) {
       context.options.onError(
index 11927da74915edc303f3568c2918766dc7b8deb6..e616954ebe5b6dd7f9f6aefe67602a499b372e83 100644 (file)
@@ -14,7 +14,7 @@ import {
   isStaticArgOf,
 } from '@vue/compiler-dom'
 import type { DirectiveTransform } from '../transform'
-import { IRNodeTypes } from '../ir'
+import { type DirectiveIRNode, IRNodeTypes } from '../ir'
 
 export const transformVModel: DirectiveTransform = (dir, node, context) => {
   const { exp, arg } = dir
@@ -79,7 +79,7 @@ export const transformVModel: DirectiveTransform = (dir, node, context) => {
     )
   const { tag } = node
   const isCustomElement = context.options.isCustomElement(tag)
-  let runtimeDirective: string | undefined = 'vModelText'
+  let modelType: DirectiveIRNode['modelType'] | undefined = 'text'
   // TODO let runtimeDirective: VaporHelper | undefined = 'vModelText'
   if (
     tag === 'input' ||
@@ -92,17 +92,17 @@ export const transformVModel: DirectiveTransform = (dir, node, context) => {
       if (type) {
         if (type.type === NodeTypes.DIRECTIVE) {
           // :type="foo"
-          runtimeDirective = 'vModelDynamic'
+          modelType = 'dynamic'
         } else if (type.value) {
           switch (type.value.content) {
             case 'radio':
-              runtimeDirective = 'vModelRadio'
+              modelType = 'radio'
               break
             case 'checkbox':
-              runtimeDirective = 'vModelCheckbox'
+              modelType = 'checkbox'
               break
             case 'file':
-              runtimeDirective = undefined
+              modelType = undefined
               context.options.onError(
                 createDOMCompilerError(
                   DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT,
@@ -119,13 +119,13 @@ export const transformVModel: DirectiveTransform = (dir, node, context) => {
       } else if (hasDynamicKeyVBind(node)) {
         // element has bindings with dynamic keys, which can possibly contain
         // "type".
-        runtimeDirective = 'vModelDynamic'
+        modelType = 'dynamic'
       } else {
         // text type
         __DEV__ && checkDuplicatedValue()
       }
     } else if (tag === 'select') {
-      runtimeDirective = 'vModelSelect'
+      modelType = 'select'
     } else {
       // textarea
       __DEV__ && checkDuplicatedValue()
@@ -139,6 +139,7 @@ export const transformVModel: DirectiveTransform = (dir, node, context) => {
     )
   }
 
+  // TODO this should no longer be needed
   context.registerOperation({
     type: IRNodeTypes.SET_MODEL_VALUE,
     element: context.reference(),
@@ -147,12 +148,13 @@ export const transformVModel: DirectiveTransform = (dir, node, context) => {
     isComponent,
   })
 
-  if (runtimeDirective)
+  if (modelType)
     context.registerOperation({
-      type: IRNodeTypes.WITH_DIRECTIVE,
+      type: IRNodeTypes.DIRECTIVE,
       element: context.reference(),
       dir,
-      name: runtimeDirective,
+      name: 'model',
+      modelType,
       builtin: true,
     })
 
index 0553a3de7117a52249235cb650784a2e30b15206..f1135d6b0a5902f7d9602c00c2d43b2e3ea2b7d0 100644 (file)
@@ -1,4 +1,10 @@
-import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom'
+import {
+  DOMErrorCodes,
+  ElementTypes,
+  ErrorCodes,
+  createCompilerError,
+  createDOMCompilerError,
+} from '@vue/compiler-dom'
 import type { DirectiveTransform } from '../transform'
 import { IRNodeTypes } from '../ir'
 
@@ -8,13 +14,24 @@ export const transformVShow: DirectiveTransform = (dir, node, context) => {
     context.options.onError(
       createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION, loc),
     )
+    return
+  }
+
+  if (node.tagType === ElementTypes.SLOT) {
+    context.options.onError(
+      createCompilerError(
+        ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
+        loc,
+      ),
+    )
+    return
   }
 
   context.registerOperation({
-    type: IRNodeTypes.WITH_DIRECTIVE,
+    type: IRNodeTypes.DIRECTIVE,
     element: context.reference(),
     dir,
-    name: 'vShow',
+    name: 'show',
     builtin: true,
   })
 }
index f8f41bb04d4d0ffbe8d39e68d3312d4848edafc2..2303d8197349aa6b6c11e615722141a41619b008 100644 (file)
@@ -1,8 +1,16 @@
 import type { ObjectDirective } from '@vue/runtime-core'
 
+/**
+ * @internal
+ */
 export const vShowOriginalDisplay: unique symbol = Symbol('_vod')
+/**
+ * @internal
+ */
 export const vShowHidden: unique symbol = Symbol('_vsh')
-
+/**
+ * @internal
+ */
 export interface VShowElement extends HTMLElement {
   // _vod = vue original display
   [vShowOriginalDisplay]: string
index 60c32ce5d309b600f1e8fc582ffb9f086a45a0d3..a23d0cb588bbc0fb1a5b9918f0be50086b30bad8 100644 (file)
@@ -322,3 +322,11 @@ export { patchStyle } from './modules/style'
  * @internal
  */
 export { shouldSetAsProp } from './patchProp'
+/**
+ * @internal
+ */
+export {
+  vShowOriginalDisplay,
+  vShowHidden,
+  type VShowElement,
+} from './directives/vShow'
diff --git a/packages/runtime-vapor/src/directives/vShow.ts b/packages/runtime-vapor/src/directives/vShow.ts
new file mode 100644 (file)
index 0000000..6a21e97
--- /dev/null
@@ -0,0 +1,16 @@
+import {
+  type VShowElement,
+  vShowHidden,
+  vShowOriginalDisplay,
+} from '@vue/runtime-dom'
+import { renderEffect } from '../renderEffect'
+
+export function applyVShow(el: VShowElement, source: () => any): void {
+  el[vShowOriginalDisplay] = el.style.display === 'none' ? '' : el.style.display
+  renderEffect(() => setDisplay(el, source()))
+}
+
+function setDisplay(el: VShowElement, value: unknown): void {
+  el.style.display = value ? el[vShowOriginalDisplay] : 'none'
+  el[vShowHidden] = !value
+}
index e774ffb0f29dc6d2c267ef15e83fb64f564c7ea1..f69d61444bd7c32dcba849ca99fa47dc2bc57bce 100644 (file)
@@ -30,3 +30,4 @@ export {
 } from './apiCreateFor'
 export { createTemplateRefSetter } from './apiTemplateRef'
 export { createDynamicComponent } from './apiCreateDynamicComponent'
+export { applyVShow } from './directives/vShow'