elements icon indicating copy to clipboard operation
elements copied to clipboard

Adding Vue support

Open typed-sigterm opened this issue 1 year ago • 16 comments

While the React integration is released, is there a plan to make a Vue wrapper? If so, would like to help:)

typed-sigterm avatar Oct 14 '24 13:10 typed-sigterm

Hi,

Thank you for your offer!

Is a wrapper even necessary for Vue? In theory, Vue supports web components very well. (Source: https://custom-elements-everywhere.com) But I don't know that's the case in practice. What would be nice to test is whether two-way binding works. I read somewhere the v-model only works with native form inputs. In UI5 Web Components they add "type" attribute to components: https://sap.github.io/ui5-webcomponents/docs/frameworks/Vue/ It seems a bit hacky for me, but it's ok. Shoelace has its own type definition: https://shoelace.style/frameworks/vue#types and a custom directive: https://github.com/shoelace-style/vue-sl-model

An easy to use solution would be great. Or an example project. But I think porting the wrapper library as-is is unnecessary.

bendera avatar Oct 14 '24 17:10 bendera

I've tried for some, but I just didn't manage to perfectly forward vue slots into web component named slots (e.g. into collapsible's actions) 🤔

neko-para avatar Oct 14 '24 17:10 neko-para

I've tried for some, but I just didn't manage to perfectly forward vue slots into web component named slots (e.g. into collapsible's actions) 🤔

Could you provide a reproducible example?

bendera avatar Oct 14 '24 17:10 bendera

I've tried for some, but I just didn't manage to perfectly forward vue slots into web component named slots (e.g. into collapsible's actions) 🤔

Could you provide a reproducible example?

You may check this question. https://stackoverflow.com/questions/75300558/how-to-delegate-content-from-vue-slots-to-web-components-slots

In short, I have to either spread name attribute outside, or use a div to wrap the slot (which breaks the element structure)

neko-para avatar Oct 14 '24 18:10 neko-para

I believe this should be a bug of vue, maybe🤔 I've raised a discussion. Hope a workaround exists.

neko-para avatar Oct 14 '24 18:10 neko-para

Sidebar component definiton:

<script setup lang="ts">
defineProps<{ title: string; }>()
</script>

<template>
  <div class="sidebar">
    <h2>{{ title }}</h2>
    <vscode-collapsible title="Sidebar Collapsible">
      <slot name="content"></slot>
    </vscode-collapsible>
  </div>
</template>

In the consumer component:

<Sidebar title="Sidebar Title">
    <template #content>
      <vscode-badge slot="actions">99</vscode-badge>
      <p>FFFUUU</p>
    </template>
  </Sidebar>

Is this a solution to the case you are struggling with?

bendera avatar Oct 14 '24 20:10 bendera

Yes


@bendera Sorry, I've missed your idea. What you've provided only fowards the default slots, which do work for now. What I'm struggling is to forward into named slots, like the actions slot.

neko-para avatar Oct 15 '24 01:10 neko-para

I've managed to achieve it via jsx.

export function VCollapsible(
    props: {
        description?: string
        open?: boolean
        title?: string
    },
    context: SetupContext<{
        'update:open': [boolean]
    }>
) {
    const defaultSlot = context.slots.default?.() ?? []
    const actionsSlot = (context.slots.actions?.() ?? []).map(vnode => {
        return cloneVNode(vnode, {
            slot: 'actions',
        })
    })

    return (
        <vscode-collapsible
            description={props.description}
            open={props.open}
            title={props.title}
            onVscCollapsibleToggle={(e: VscCollapsibleToggleEvent) => {
                context.emit('update:open', e.detail.open)
            }}
        >
            {[...defaultSlot, ...actionsSlot]}
        </vscode-collapsible>
    )
}

With the help of cloneVNode, I can add the extra slot prop.

neko-para avatar Oct 17 '24 08:10 neko-para

https://kermanx.github.io/reactive-vscode/

hifron avatar Nov 19 '24 16:11 hifron

Two-way binding issues are fixed. Sample app: https://github.com/vscode-elements/examples/tree/91a607e8f87a018e46bb4eeffa06677d708449aa/vue-example

Documentation is coming soon.

bendera avatar Nov 26 '24 23:11 bendera

~~SingleSelect seems not work properly 🤔~~

~~Vue would directly change the elements inside instead of recreating the whole components, thus selection isn't sync.~~ ~~I'm not sure what causes the problem, actually.~~

QQ_1732798058042

      <vscode-option
        v-for="(i, k) in pathList"
        :key="k"
        :selected="i === curPath"
      >
        {{ i }}
      </vscode-option>

Damn, sorry for not carefully checking the example. I'm still using the old way to bind state. After using v-model, things work properly.

neko-para avatar Nov 28 '24 12:11 neko-para

I've met the problem again. I'm trying to set a dynamic description on vscode-option, which just doesn't work. I think it would be caused by the same problem that changing selected faced.

          <vscode-option
            v-for="(i, k) in ipc.context.value.interfaceObj?.controller ?? []"
            :key="k"
            :description="`${i.type}\n${tryStringify(i.type === 'Adb' ? i.adb : i.win32)}`"
          >
            {{ i.name }}
          </vscode-option>

Binding options directly instead of specific them in template could help. But this is such an indirect approach.

        <vscode-single-select
          v-model="currentController"
          :options="controllerOptions"
          :disabled="ipc.context.value.interfaceRefreshing"
        >
        </vscode-single-select>

neko-para avatar Nov 29 '24 08:11 neko-para

I have found Vue integration to work well, however with Volar's strictTemplates and such it's difficult to get TS integration behave. This is what I have come up with:

declare module '@vue/runtime-core' {
  export interface GlobalComponents {
    VscodeTextfield: DefineComponent<{}, { $props: Partial<VscodeTextfield> & { modelValue?: any } & HTMLAttributes }>
    // ...same for others
  }
}

this is very hacky though, would prefer a proper solution.

sample https://github.com/phil294/GitLG/commit/a98057e65dcac9b1da7cd1d33c6712f89a08672e

phil294 avatar May 25 '25 16:05 phil294

Two-way binding issues are fixed. Sample app: https://github.com/vscode-elements/examples/tree/91a607e8f87a018e46bb4eeffa06677d708449aa/vue-example双向绑定问题已修复。示例应用:https://github.com/vscode-elements/examples/tree/91a607e8f87a018e46bb4eeffa06677d708449aa/vue-example

Documentation is coming soon.文档即将发布。

Did it really fix it? I'm using v-model to bind a textfield and it's not working.

AprDeci avatar Sep 15 '25 01:09 AprDeci

@AprDeci Could you create a minimal example in a separate repo? There is a simple app here, and it seems to work. https://github.com/vscode-elements/examples/blob/main/vue-example/src/components/FormDemo.vue

bendera avatar Sep 15 '25 06:09 bendera

@AprDeci Could you create a minimal example in a separate repo? There is a simple app here, and it seems to work.能否在一个单独的仓库中创建一个最小示例?这里有一个简单的应用,看起来可以正常工作。

I created a sandbox that includes two textfield bindings and one regular input binding vscode-element-vmodel-test

AprDeci avatar Sep 15 '25 07:09 AprDeci