mitosis icon indicating copy to clipboard operation
mitosis copied to clipboard

Generation of Vue 2 classes could possibly avoid _classStringToObject

Open euoia opened this issue 2 years ago • 1 comments

I am interested in helping provide a fix!

Yes

Which generators are impacted?

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

Reproduction case

https://mitosis.builder.io/?outputTab=G4VwpkA%3D&inputTab=M4NwpgNgLmQ%3D&code=DwZwxgTglgDgLgPgFAAIUFMAeMD2E4oA26BAJlCAIYBGxpKAvCgGaWEjoDcqRJLOYAK4hGKOBEFckwAPTho8ZNKgA7GIIJhClECAYAiZngC2AWlXq4%2BlFp0gAXOSq109W7vtGhImQiA%3D

Expected Behaviour

The Vue 2 output in the the Class Directive example uses minimal Vue code, e.g.

<input
    class="form-input"
    :class="{disabled: disabled, focus: focus}"
/>

Actual Behaviour

The Vue 2 output in the Class Directive uses code which is quite verbose, converting a string into a class with a _classStringToObject helper:

  <input
    :class="
      _classStringToObject(
        `form-input ${disabled ? 'disabled' : ''} ${focus ? 'focus' : ''}`
      )
    "
  />

Additional Information

No response

euoia avatar Dec 14 '22 21:12 euoia

That's because this is the only way that the JSX syntax works: it has a class string prop that concatenates everything: see example

You're right that for the Svelte syntax, and certain simpler cases, we could do away with _classStringToObject(). I am always open to improving the compiler if it means removing injected code such as this helper.

This would be a fairly involved task however...the class binding is stored in the Mitosis JSON as a string:

      "bindings": {
        "class": {
          "code": "`form-input ${props.disabled ? \"disabled\" : \"\"} ${state.focus ? \"focus\" : \"\"}`"
        }
      },

That is the case for both the JSX and Svelte syntaxes. Now, since the Svelte syntax already supports providing separate class bindings, it would be very easy the JSON output of that to something like (very pseudo-code-ish syntax):

      "bindings": {
        "class": [{
          "code": "form-input",
        }, {
          "object": "props.disabled",
        }, {
          "object": "state.focus",
        }]
      },

and then have the Vue generator (and other generators) provide a cleaner output for it.

However, I don't see how we can improve that for the JSX output without introducing a new syntax to support a class object, e.g.:

import { useStore } from "@builder.io/mitosis";

export default function MyComponent(props) {
  const state = useStore({ focus: true });

  return (
    <input
      class="form-input"
      class={{
        disabled: props.disabled,
        focus: state.focus
      }}
    />
  );
}

But I'd have to think a bit more through:

  • whether we want to introduce such a new syntax
  • how exactly this syntax should look like (multiple classes? class and classObj or something?)
  • what edge cases might exist when building complex class strings

samijaber avatar Dec 19 '22 19:12 samijaber