Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT Contribution] Plugin Support for vue V-Model integration and event interoperability #1266

Open
1 of 11 tasks
D4RKAR117 opened this issue Sep 11, 2023 · 2 comments
Open
1 of 11 tasks
Labels
enhancement New feature or request

Comments

@D4RKAR117
Copy link

I am interested in helping provide a feature!

Yes

Which generators are impacted?

  • All
  • Angular
  • HTML
  • Qwik
  • React
  • React-Native
  • Solid
  • Stencil
  • Svelte
  • Vue
  • Web components

What problem does this feature solve?

As discussed on #833 and following the investigation and api proposal of @bjufre, ive created a custom plugin for mitosis that does many things to solve event interoperability and prop drilling for vue outputs.

The plugin does 3 main things:

  • Using metadata decorators we can match function props to custom emits without affecting other outputs or the writing of the component as state on the proposal here (Point # 2)
  • Using the related v-model data obtained from metadata and the prop typings of the component we annotate the defineEmits automatically for the component, so we follow the vue guidelines as stated here
  • Using the props typings the plugin improves the type inference for props, using defineProps() like the guidelines of vue suggest instead of the default export props array property that misses the usage of the already bundled Props interface (can be any interface as mitosis handles it using json propsTypeRef property) (Also can work as standalone plugin to improve props of components without v-mode /emit concerns)

Limitations:

  • Only works for vue 3 + typescript +composition api output ATM
  • The props marked as v-model targets will be removed from the normal prop flow so may cause some disparity between frameworks (? but still its the preferred way on vue.

What does the proposed API look like?

I've used in the same project as stated on #1265 to bundle playground testing and the plugin itself so the code of the plugin can be found here.

The mitosis.config.js will look something like this:

/* eslint-disable @typescript-eslint/no-var-requires */
const {  AddVModelPlugin } = require('@d4rkar117/ultimate-components-helpers');
const { resolve } = require('path');

/**
 * @type {import("@builder.io/mitosis").MitosisConfig}
 */
const config = {
	targets: ['vue'],
	files: ['src/components/**/*'],
	options: {
		vue: {
			typescript: true,
			defineComponent: false,
			plugins: [
				() => AddVModelPlugin(),
			],
		},
	},
};

module.exports = config;

The code of the component (I've used the example of the #833 SuperInput jsut for validation ease) can look like this:

import { Show, useMetadata } from '@builder.io/mitosis';

interface Props {
	name: string;
	label: string;
	value: string;
	onUpdateValue: (val: string) => void;
	errorMessage?: string;
}

useMetadata({
	vModel: [
		{
			modelValue: 'value',
			eventConfig: {
				targetPropName: 'onUpdateValue',
				vModelPropName: 'update:modelValue',
			},
		},
	],
});

export default function SuperInputField(props: Props) {
	return (
		<div class='my-super-duper-input-field'>
			<label for={props.name}>{props.label}</label>
			<input
				id={props.name}
				name={props.name}
				value={props.value}
				onChange={event => props.onUpdateValue(event.target.value)}
			/>
			<Show when={props.errorMessage}>
				<p class='form-message danger'>{props.errorMessage}</p>
			</Show>
		</div>
	);
}

and will generate an output like this:

<template>
  <div class="my-super-duper-input-field">
    <label :for="name">{{ label }}</label>
    <input
      :id="name"
      :name="name"
      :value="value"
      @input="$emit('update:modelValue', $event.target.value)"
    />

    <template v-if="errorMessage">
      <p class="form-message danger">{{ errorMessage }}</p>
    </template>
  </div>
</template>

<script lang="ts">
interface Props {
  name: string;
  label: string;
  value: string;
  errorMessage?: string;
}
interface EmitEvents {
  (e: "update:modelValue", val: string): void;
}

const props = defineProps<Props>();
const emit = defineEmits<EmitEvents>();
export default {
  name: "super-input-field",
};
</script>

solving almost entirely the event interoperability

Additional Information

The plugin is pretty basic and may not fulfill 100% of the desired interoperability but can help for the initial structure and maybe the vue improvement from mitosis compiler and the mos common v-model scenarios without destroying the mitosis philosophy of "write once and bundle many"

Any feedback or review is appreciated. This is my first big open source contribution, so I'm open to all suggestions

@D4RKAR117 D4RKAR117 added the enhancement New feature or request label Sep 11, 2023
@D4RKAR117 D4RKAR117 changed the title [FEAT] Plugin Support for vue V-Model integration and event interoperability [FEAT Contribution] Plugin Support for vue V-Model integration and event interoperability Oct 12, 2023
@samijaber
Copy link
Contributor

@D4RKAR117 , I think this is such an amazing initiative. I would love for you to publish this plugin and share it in the github issue. This will encourage people to try and use it. From there, we can gather feedback and see if it tackles all of Mitosis users' pain points!

@D4RKAR117
Copy link
Author

I will try to make a clean one and publish it, holidays hit hard

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants