Last active
November 7, 2024 08:35
-
-
Save padcom/f1b0f1528044a07674d3f6063062cfb4 to your computer and use it in GitHub Desktop.
Example how to use `defineModel()` and `useHost()` in Vue.js 3.5 in a custom webcomponent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<!-- | |
First things first, the `:value` cannot be `v-model="value"` because it would | |
break reactivity. It's the same as assigning things directly to `value.value` | |
and as explained below, assigning the value needs to be done through the host | |
element (`host.value = '...'`). | |
Secondly, the `<select>` element emits its own `input` event that bubbles. | |
Unfortunately, the event is disguised under the custom element, and not the | |
`<select>` that actually triggered the value. This is due to the `shadowRoot` | |
being used here. | |
Therefore, to emit the right event at the right time we stop the propagation | |
of `input` event here and then, after the proper value has been updated | |
(as in `host.value`) we emit the `input` event ourselves. | |
--> | |
<select :value @input.stop="update(($event.target as HTMLSelectElement).value)"> | |
<option value="arial">Arial</option> | |
<option value="monospace">monospace</option> | |
</select> | |
</template> | |
<script lang="ts"> | |
import { VueElement } from 'vue' | |
export interface HTMLElementFontInput extends VueElement { | |
value: string | |
} | |
</script> | |
<script lang="ts" setup> | |
import { useHost } from 'vue' | |
// This defines a `value` property on the custom element that is reactive, | |
// but ONLY if accessed through the host element. Setting its value.value = '...' | |
// directly (or value = '...' in the template) breaks reactivity. | |
// That is exactly why we need to use the `host` element to set the new value, | |
// instead using `v-model` on the `<select>`. | |
const value = defineModel<string>('value') | |
const host = useHost() as HTMLElementFontInput | |
function update(newValue: string) { | |
host.value = newValue | |
// The `change` event is the default one GrapesJS listens to in a trait | |
host?.dispatchEvent(new InputEvent('change', { bubbles: true })) | |
} | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function pluginFontSelectTrait(editor: Editor) { | |
try { | |
customElements.define('font-input', defineCustomElement(FontInput)) | |
} catch (e: any) { | |
console.warn('Unable to register webcomponent:', e.message) | |
} | |
editor.TraitManager.addType('font-select', { | |
createInput() { | |
return document.createElement('font-input') as HTMLElementFontInput | |
}, | |
onUpdate({ trait, elInput }) { | |
elInput.value = trait.getValue() | |
}, | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment