core: add new fields to MitosisComponent type: custom directives
- Dominant language
- TypeScript
- Stars
- 14.4k
- Forks
- 671
- PR merge metrics
- No merged PRs in 30d
Description
## What
Add a `directives` field to the component JSON output, that accepts custom directives.
## Why?
I realize that not all frameworks support directives, but some of them do. You could argue that the better solution would be to implement shared functionality somewhere else, (which may be true, depending on your use case), but sometimes the features you are looking for are already implemented in a package that provides a custom directive:
Example - Drag & Drop directive:
[Vue](https://github.com/hilongjw/vue-dragging)
[Angular](https://material.angular.io/cdk/drag-drop/overview)
[Svelte](https://github.com/isaacHagoel/svelte-dnd-action)
# How?
Since custom directives are usually registered at the application level, defining and registering directives can be handled outside of Mitosis. All Mitosis needs to do is have a special syntax to mark Node attributes as a directive. i.e.
Input (Mitosis Component)
```jsx
export default function MyComponent(props) {
return (
Some Content
);
}
```
Output (Vue)
```vue
Some content
```
Output (Svelte)
```svelte
Some content
```
Output (JSON)
```json
{
"@type": "@builder.io/mitosis/component",
"imports": [],
"exports": {},
"inputs": [],
"meta": {},
"refs": {},
"state": {},
"children": [
{
"@type": "@builder.io/mitosis/node",
"name": "div",
"meta": {},
"scope": {},
"properties": {
"class": "example"
},
"bindings": {},
"directives": {
"draggable": {}
},
"children": [
{
"@type": "@builder.io/mitosis/node",
"name": "div",
"meta": {},
"scope": {},
"properties": {
"_text": "\n Some Content\n "
},
"bindings": {},
"children": []
}
]
}
],
"hooks": {},
"context": {
"get": {},
"set": {}
},
"name": "MyComponent",
"subComponents": []
}
```
## Challenges
I realize that React doesn't allow directives, which by proxy means that AFAIK there isn't a standard for using custom directives in JSX. However, I know the BuilderIO team is smart, and I'm certain you could find a clever way to figure out how to make it happen.
Framework Examples
Vue 3 (Composition API)
```vue
// enables v-focus in templates
const vFocus = {
mounted: (el) => el.focus()
}
```
Vue 3 (Options API)
```vue
export default {
setup() {
/*...*/
},
directives: {
// enables v-focus in template
focus: {
/* ... */
}
}
}
```
Svelte
```svelte
export let bar;
function foo(node, bar) {
// the node has been mounted in the DOM
return {
update(bar) {
// the value of `bar` has changed
},
destroy() {
// the node has been removed from the DOM
}
};
}
```
Alpine.js (Not currently supported by Mitosis)
```html
Alpine.directive('uppercase', el => {
el.textContent = el.textContent.toUpperCase()
})
Hello World!
```
Contributor guide
Research direction
Locate the MitosisComponent type and the component JSON output path, then compare the proposed directives field with the shown properties and bindings structure. Trace how JSX node attributes reach Vue, Svelte, and Angular outputs; done means the syntax, JSON representation, and supported framework output behavior are defined consistently.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, react, typescript
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100