diff --git a/packages/babel-plugin-jsx/README.md b/packages/babel-plugin-jsx/README.md
index ee375d9a..0b497c36 100644
--- a/packages/babel-plugin-jsx/README.md
+++ b/packages/babel-plugin-jsx/README.md
@@ -243,24 +243,29 @@ h(A, {
#### custom directive
-Recommended when using string arguments
-
```jsx
const App = {
- directives: { custom: customDirective },
+ directives: { custom: vCustom },
setup() {
- return () => ;
+ return () => ;
},
};
```
+Directive names will resolve a variable matching `/v[A-Z]/` first, `options.directives` is only needed to prevent the import from being reported as unused.
+
+Arguments and modifiers can be added as an array:
+
```jsx
-const App = {
- directives: { custom: customDirective },
- setup() {
- return () => ;
- },
-};
+// same as v-custom:arg.a.b="val" in a .vue file
+
+```
+
+Or arguments as part of the attribute name:
+
+```jsx
+
+
```
### Slot
diff --git a/packages/babel-plugin-jsx/src/parseDirectives.ts b/packages/babel-plugin-jsx/src/parseDirectives.ts
index ba23fb09..f526a8a7 100644
--- a/packages/babel-plugin-jsx/src/parseDirectives.ts
+++ b/packages/babel-plugin-jsx/src/parseDirectives.ts
@@ -1,6 +1,6 @@
import * as t from '@babel/types';
import { type NodePath } from '@babel/traverse';
-import { createIdentifier } from './utils';
+import { camelize, capitalize, createIdentifier } from './utils';
import type { State } from './interface';
export type Tag =
@@ -184,11 +184,14 @@ const resolveDirective = (
}
return modelToUse;
}
- const referenceName =
- 'v' + directiveName[0].toUpperCase() + directiveName.slice(1);
- if (path.scope.references[referenceName]) {
- return t.identifier(referenceName);
- }
+ const referenceName = 'v' + capitalize(camelize(directiveName));
+ let scope = path.scope;
+ do {
+ if (scope.references[referenceName]) {
+ return t.identifier(referenceName);
+ }
+ scope = scope.parent;
+ } while (scope);
return t.callExpression(createIdentifier(state, 'resolveDirective'), [
t.stringLiteral(directiveName),
]);
diff --git a/packages/babel-plugin-jsx/src/utils.ts b/packages/babel-plugin-jsx/src/utils.ts
index bc64ab58..aeee96dd 100644
--- a/packages/babel-plugin-jsx/src/utils.ts
+++ b/packages/babel-plugin-jsx/src/utils.ts
@@ -254,6 +254,14 @@ const onRE = /^on[^a-z]/;
export const isOn = (key: string) => onRE.test(key);
+const camelizeRE = /-(\w)/g;
+export const camelize = (str: string): string => {
+ return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
+};
+export const capitalize = (str: T): Capitalize => {
+ return (str.charAt(0).toUpperCase() + str.slice(1)) as Capitalize;
+};
+
const mergeAsArray = (
existing: t.ObjectProperty,
incoming: t.ObjectProperty
diff --git a/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap b/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap
index c4c2f986..1e59a664 100644
--- a/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap
+++ b/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap
@@ -63,6 +63,12 @@ _createVNode(_Fragment, null, [_withDirectives(_createVNode(_resolveComponent("A
}]])]);"
`;
+exports[`directive in outer scope > directive in outer scope 1`] = `
+"import { resolveComponent as _resolveComponent, createVNode as _createVNode, withDirectives as _withDirectives } from "vue";
+const vXxx = {};
+() => _withDirectives(_createVNode(_resolveComponent("A"), null, null, 512), [[vXxx]]);"
+`;
+
exports[`directive in scope > directive in scope 1`] = `
"import { resolveComponent as _resolveComponent, createVNode as _createVNode, withDirectives as _withDirectives } from "vue";
const vXxx = {};
diff --git a/packages/babel-plugin-jsx/test/snapshot.test.ts b/packages/babel-plugin-jsx/test/snapshot.test.ts
index 00e92c9c..c3b80529 100644
--- a/packages/babel-plugin-jsx/test/snapshot.test.ts
+++ b/packages/babel-plugin-jsx/test/snapshot.test.ts
@@ -162,6 +162,15 @@ const transpile = (source: string, options: VueJSXPluginOptions = {}) =>
`,
},
+ {
+ name: 'directive in outer scope',
+ from: `
+ const vXxx = {};
+ () => (
+
+ );
+ `,
+ },
{
name: 'vModels',
from: '',