Adding Vue support
While the React integration is released, is there a plan to make a Vue wrapper? If so, would like to help:)
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.
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) 🤔
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?
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)
I believe this should be a bug of vue, maybe🤔 I've raised a discussion. Hope a workaround exists.
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?
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.
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.
https://kermanx.github.io/reactive-vscode/
Two-way binding issues are fixed. Sample app: https://github.com/vscode-elements/examples/tree/91a607e8f87a018e46bb4eeffa06677d708449aa/vue-example
Documentation is coming soon.
~~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.~~
<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.
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>
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
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 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
@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