vue#h TypeScript Examples
The following examples show how to use
vue#h.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: hexo-init-fail-modal.ts From hexon with GNU General Public License v3.0 | 6 votes |
export default function showHexoInitFailModal(text: string) {
modal.create(
defineComponent({
name: "HErrorInfo",
components: {
HHexoInitFailModal,
HBaseModal,
},
props: {
close: Function,
},
render() {
return h(
HBaseModal,
{
onOnClose: this.close,
},
() => h(HHexoInitFailModal, { text })
)
},
})
)
}
Example #2
Source File: diretive.test.ts From vue-i18n-next with MIT License | 6 votes |
test('object literal', async () => {
const i18n = createI18n({
locale: 'en',
messages: {
en: {
hello: 'hello, {name}!'
},
ja: {
hello: 'こんにちは、{name}!'
}
}
})
const App = defineComponent({
setup() {
// <p v-t="{ path: 'hello', locale: 'ja', args: { name: name.value } }"></p>
const name = ref('kazupon')
const t = resolveDirective('t')
return () => {
return withDirectives(h('p'), [
[t!, { path: 'hello', locale: 'ja', args: { name: name.value } }]
])
}
}
})
const wrapper = await mount(App, i18n)
expect(wrapper.html()).toEqual('<p>こんにちは、kazupon!</p>')
})
Example #3
Source File: diretive.test.ts From vue-i18n-next with MIT License | 6 votes |
test('plural', async () => {
const i18n = createI18n({
locale: 'en',
messages: {
en: {
banana: 'no bananas | {n} banana | {n} bananas'
}
}
})
const App = defineComponent({
setup() {
// <p v-t="{ path: 'banana', choice: 2 }"></p>
const t = resolveDirective('t')
return () => {
return withDirectives(h('p'), [[t!, { path: 'banana', choice: 2 }]])
}
}
})
const wrapper = await mount(App, i18n)
expect(wrapper.html()).toEqual('<p>2 bananas</p>')
})
Example #4
Source File: diretive.test.ts From vue-i18n-next with MIT License | 6 votes |
test('preserve modifier', async () => {
const mockWarn = warn as jest.MockedFunction<typeof warn>
mockWarn.mockImplementation(() => {})
const i18n = createI18n({
locale: 'en',
messages: {
en: {
hello: 'hello!'
}
}
})
const App = defineComponent({
setup() {
// <p v-t.preserve="'hello'"></p>
const t = resolveDirective('t')
return () => {
return withDirectives(h('p'), [[t!, 'hello', '', { preserve: true }]])
}
}
})
await mount(App, i18n)
expect(mockWarn).toHaveBeenCalledTimes(1)
expect(mockWarn.mock.calls[0][0]).toEqual(
getWarnMessage(I18nWarnCodes.NOT_SUPPORTED_PRESERVE)
)
})
Example #5
Source File: Translation.test.ts From vue-i18n-next with MIT License | 6 votes |
test('component', async () => {
const i18n = createI18n({
locale: 'en',
messages
})
const MyComponent = defineComponent({
setup(props, context: SetupContext) {
return (): VNodeChild => h('p', context.slots.default!())
}
})
const App = defineComponent({
data: () => ({ MyComponent }),
template: `
<i18n-t :tag="MyComponent" class="name" keypath="message.named">
<template #name>
<span>kazupon</span>
</template>
</i18n-t>
`
})
const wrapper = await mount(App, i18n)
expect(wrapper.html()).toEqual(
`<p class="name">hello, <span>kazupon</span>!</p>`
)
})
Example #6
Source File: NumberFormat.test.ts From vue-i18n-next with MIT License | 6 votes |
test('component', async () => {
const i18n = createI18n({
locale: 'en-US',
numberFormats
})
const MyComponent = defineComponent({
setup(props, context: SetupContext) {
return (): VNodeChild => h('span', context.slots.default!())
}
})
const App = defineComponent({
data: () => ({ MyComponent }),
template: `
<i18n-n :tag="MyComponent" :value="100"></i18n-n>
<i18n-n :tag="MyComponent" :value="100" format="currency"></i18n-n>
<i18n-n :tag="MyComponent" :value="100" format="currency" locale="ja-JP"></i18n-n>
`
})
const wrapper = await mount(App, i18n)
expect(wrapper.html()).toEqual(
`<span>100</span><span>$100.00</span><span>¥100</span>`
)
})
Example #7
Source File: DatetimeFormat.test.ts From vue-i18n-next with MIT License | 6 votes |
test('component', async () => {
const i18n = createI18n({
locale: 'en-US',
datetimeFormats
})
const MyComponent = defineComponent({
setup(props, context: SetupContext) {
return (): VNodeChild => h('span', context.slots.default!())
}
})
const App = defineComponent({
data: () => ({ MyComponent }),
template: `
<i18n-d :tag="MyComponent" :value="new Date()"></i18n-d>
<i18n-d :tag="MyComponent" :value="new Date()" format="long"></i18n-d>
<i18n-d
:tag="MyComponent"
:value="new Date()"
format="long"
locale="ja-JP-u-ca-japanese"
></i18n-d>
`
})
const wrapper = await mount(App, i18n)
expect(wrapper.html().includes('span')).toBeTruthy()
})
Example #8
Source File: diretive.test.ts From vue-i18n-next with MIT License | 6 votes |
test('legacy mode', async () => {
const i18n = createI18n({
legacy: true,
locale: 'en',
messages: {
en: {
hello: 'hello!'
}
}
})
const App = defineComponent({
setup() {
// <p v-t="'hello'"></p>
const t = resolveDirective('t')
return () => {
return withDirectives(h('p'), [[t!, 'hello']])
}
}
})
const wrapper = await mount(App, i18n)
expect(wrapper.html()).toEqual('<p>hello!</p>')
})
Example #9
Source File: helper.ts From vue-i18n-next with MIT License | 6 votes |
function compileSlot(template: string) {
const codegen = compile(template, {
mode: 'function',
hoistStatic: true,
prefixIdentifiers: true
})
const render = new Function('Vue', codegen.code)(runtimeDom)
const ToRender = defineComponent({
inheritAttrs: false,
setup(props, { attrs }) {
return { ...attrs }
},
render
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (propsData: any) => h(ToRender, { ...propsData })
}
Example #10
Source File: ssr.test.ts From vue-i18n-next with MIT License | 6 votes |
test('composition mode', async () => {
const i18n = createI18n({
legacy: false,
locale: 'en',
messages: {}
})
const App = defineComponent({
setup() {
const { t } = useI18n({
locale: 'ja',
inheritLocale: false,
messages: {
ja: { hello: 'こんにちは!' },
en: { hello: 'hello!' }
}
})
return () => h('p', t('hello'))
}
})
const app = createSSRApp(App)
app.use(i18n)
expect(await renderToString(app)).toMatch(`<p>こんにちは!</p>`)
})
Example #11
Source File: ssr.test.ts From vue-i18n-next with MIT License | 6 votes |
test('legacy mode', async () => {
const i18n = createI18n({
locale: 'ja',
messages: {
ja: { hello: 'こんにちは!' },
en: { hello: 'hello!' }
}
})
// NOTE: template: `<p>{{ $t('hello') }}</p>`
const App = () => h('p', i18n.global.t('hello'))
const app = createSSRApp(App)
app.use(i18n)
expect(await renderToString(app)).toMatch(`<p>こんにちは!</p>`)
})
Example #12
Source File: ssr.test.ts From vue-i18n-next with MIT License | 6 votes |
test('component: i18n-t', async () => {
const i18n = createI18n({
legacy: false,
locale: 'en',
messages: {}
})
const App = defineComponent({
setup() {
useI18n({
locale: 'ja',
inheritLocale: false,
messages: {
ja: { hello: 'こんにちは!' },
en: { hello: 'hello!' }
}
})
return () => h(resolveComponent('i18n-t'), { tag: 'p', keypath: 'hello' })
}
// template: `<i18n-t tag="p" keypath="hello"/>`
})
const app = createSSRApp(App)
app.use(i18n)
expect(await renderToString(app)).toMatch(`<p>こんにちは!</p>`)
})
Example #13
Source File: app.ts From vite-plugin-ssr with MIT License | 6 votes |
function createApp(pageContext: PageContext) {
const { Page, pageProps } = pageContext
const PageWithLayout = defineComponent({
render() {
return h(
PageShell,
{},
{
default() {
return h(Page, pageProps || {})
},
},
)
},
})
const app = createSSRApp(PageWithLayout)
// Make `pageContext` available from any Vue component
setPageContext(app, pageContext)
return app
}
Example #14
Source File: diretive.test.ts From vue-i18n-next with MIT License | 5 votes |
describe('basic', () => {
test('literal', async () => {
const i18n = createI18n({
locale: 'en',
messages: {
en: {
hello: 'hello!'
}
}
})
const App = defineComponent({
setup() {
// <p v-t="'hello'"></p>
const t = resolveDirective('t')
return () => {
return withDirectives(h('p'), [[t!, 'hello']])
}
}
})
const wrapper = await mount(App, i18n)
expect(wrapper.html()).toEqual('<p>hello!</p>')
})
test('binding', async () => {
const i18n = createI18n({
locale: 'en',
messages: {
en: {
hello: 'hello!'
}
}
})
const App = defineComponent({
setup() {
// <p v-t="msg"></p>
const msg = ref('hello')
const t = resolveDirective('t')
return () => {
return withDirectives(h('p'), [[t!, msg.value]])
}
}
})
const wrapper = await mount(App, i18n)
expect(wrapper.html()).toEqual('<p>hello!</p>')
})
})
Example #15
Source File: diretive.test.ts From vue-i18n-next with MIT License | 5 votes |
describe('errors', () => {
let org: any // eslint-disable-line @typescript-eslint/no-explicit-any
let spy: any // eslint-disable-line @typescript-eslint/no-explicit-any
beforeEach(() => {
org = console.warn
spy = jest.fn()
console.warn = spy
})
afterEach(() => {
console.warn = org
})
test(errorMessages[I18nErrorCodes.REQUIRED_VALUE], async () => {
const i18n = createI18n({
locale: 'en',
messages: {
en: {
hello: 'hello!'
}
}
})
const App = defineComponent({
setup() {
// <p v-t="{ locale: 'ja' }"></p>
const t = resolveDirective('t')
return () => {
return withDirectives(h('p'), [[t!, { locale: 'ja' }]])
}
}
})
let error: Error | null = null
try {
await mount(App, i18n)
} catch (e) {
error = e
}
expect(error!.message).toEqual(
format(errorMessages[I18nErrorCodes.REQUIRED_VALUE], 'path')
)
})
test(errorMessages[I18nErrorCodes.INVALID_VALUE], async () => {
const i18n = createI18n({
locale: 'en',
messages: {
en: {
hello: 'hello!'
}
}
})
const App = defineComponent({
setup() {
// <p v-t="1"></p>
const t = resolveDirective('t')
return () => withDirectives(h('p'), [[t!, 1]])
}
})
let error: Error | null = null
try {
await mount(App, i18n)
} catch (e) {
error = e
}
expect(error!.message).toEqual(errorMessages[I18nErrorCodes.INVALID_VALUE])
})
})
Example #16
Source File: wc.test.ts From vue-i18n-next with MIT License | 5 votes |
test('basic', async () => {
const i18n = createI18n<false>({
legacy: false,
locale: 'en',
messages: {
en: {
hello: 'hello web components!'
},
ja: {
hello: 'こんにちは Web コンポーネント!'
}
}
})
const Provider = defineCustomElement({
setup() {
provide(I18nInjectionKey, i18n)
return () => h('my-consumer')
}
})
customElements.define('my-provider', Provider)
const Consumer = defineCustomElement({
setup() {
const { t } = useI18n()
return () => h('div', t('hello'))
}
})
customElements.define('my-consumer', Consumer)
container.innerHTML = `<my-provider></my-provider>`
await nextTick()
const provider = container.childNodes[0] as VueElement
const consumer = provider.shadowRoot!.childNodes[0] as VueElement
expect(consumer.shadowRoot!.innerHTML).toBe(
`<div>hello web components!</div>`
)
i18n.global.locale.value = 'ja'
await nextTick()
expect(consumer.shadowRoot!.innerHTML).toBe(
`<div>こんにちは Web コンポーネント!</div>`
)
})
Example #17
Source File: wc.test.ts From vue-i18n-next with MIT License | 5 votes |
test('custom blocks', async () => {
const i18n = createI18n<false>({
legacy: false,
locale: 'en',
messages: {
en: {
hello: 'hello web components!'
},
ja: {
hello: 'こんにちは Web コンポーネント!'
}
}
})
const Provider = defineCustomElement({
setup() {
provide(I18nInjectionKey, i18n)
return () => h('my-child-block')
}
})
customElements.define('my-provider-block', Provider)
const Child = defineCustomElement({
setup() {
const instance = getCurrentInstance()
if (instance == null) {
throw new Error()
}
const options = instance.type as ComponentOptions
options.__i18n = [
{
locale: 'en',
resource: { foo: 'foo!' }
},
{
locale: 'ja',
resource: { foo: 'ふー!' }
}
]
const { t } = useI18n({
inheritLocale: true,
useScope: 'local'
})
return () => h('div', t('foo'))
}
})
customElements.define('my-child-block', Child)
container.innerHTML = `<my-provider-block></my-provider-block>`
await nextTick()
const provider = container.childNodes[0] as VueElement
const child = provider.shadowRoot!.childNodes[0] as VueElement
expect(child.shadowRoot!.innerHTML).toBe(`<div>foo!</div>`)
i18n.global.locale.value = 'ja'
await nextTick()
expect(child.shadowRoot!.innerHTML).toBe(`<div>ふー!</div>`)
})
Example #18
Source File: component.ts From vue3-gettext with MIT License | 5 votes |
Component = defineComponent({
// eslint-disable-next-line vue/multi-word-component-names, vue/component-definition-name-casing
name: "translate",
props: {
tag: {
type: String,
default: "span",
},
// Always use v-bind for dynamically binding the `translateN` prop to data on the parent,
// i.e.: `:translate-n`.
translateN: {
type: Number,
default: null,
},
translatePlural: {
type: String,
default: null,
},
translateContext: {
type: String,
default: null,
},
translateParams: {
type: Object,
default: null,
},
translateComment: {
type: String,
default: null,
},
},
setup(props, context) {
const isPlural = props.translateN !== undefined && props.translatePlural !== undefined;
if (!isPlural && (props.translateN || props.translatePlural)) {
throw new Error(
`\`translate-n\` and \`translate-plural\` attributes must be used together: ${
context.slots.default?.()[0]?.children
}.`,
);
}
const root = ref<HTMLElement>();
const plugin = useGettext();
const msgid = ref<string | null>(null);
onMounted(() => {
if (!msgid.value && root.value) {
msgid.value = root.value.innerHTML.trim();
}
});
const translation = computed(() => {
const translatedMsg = translate(plugin).getTranslation(
msgid.value!,
props.translateN,
props.translateContext,
isPlural ? props.translatePlural : null,
plugin.current,
);
return interpolate(plugin)(translatedMsg, props.translateParams, undefined, getCurrentInstance()?.parent);
});
// The text must be wraped inside a root HTML element, so we use a <span> by default.
return () => {
if (!msgid.value) {
return h(props.tag, { ref: root }, context.slots.default ? context.slots.default() : "");
}
return h(props.tag, { ref: root, innerHTML: translation.value });
};
},
})
Example #19
Source File: utils.ts From vue3-datagrid with MIT License | 5 votes |
defineContainer = <Props>(name: string, [...componentProps]: string[] = [], componentOptions: ComponentOptions = {}) => {
const { modelProp, modelUpdateEvent } = componentOptions;
/**
* Create a Vue component wrapper around a Web Component.
* Note: The `props` here are not all properties on a component.
* They refer to whatever properties are set on an instance of a component.
*/
const Container = defineComponent<Props & InputProps>((props, { attrs, slots, emit }) => {
let modelPropValue = (props as any)[modelProp];
const containerRef = ref<HTMLElement>();
const classes = new Set(getComponentClasses(attrs.class));
const onVnodeBeforeMount = (vnode: VNode) => {
// Add a listener to tell Vue to update the v-model
if (vnode.el) {
vnode.el.addEventListener(modelUpdateEvent.toLowerCase(), (e: Event) => {
modelPropValue = (e?.target as any)[modelProp];
emit(UPDATE_VALUE_EVENT, modelPropValue);
/**
* We need to emit the change event here
* rather than on the web component to ensure
* that any v-model bindings have been updated.
* Otherwise, the developer will listen on the
* native web component, but the v-model will
* not have been updated yet.
*/
emit(modelUpdateEvent, e);
e.stopImmediatePropagation();
});
}
};
const currentInstance = getCurrentInstance();
const hasRouter = currentInstance?.appContext?.provides[NAV_MANAGER];
const navManager: NavManager | undefined = hasRouter ? inject(NAV_MANAGER) : undefined;
const handleRouterLink = (ev: Event) => {
const { routerLink } = props as any;
if (!routerLink) return;
const routerProps = Object.keys(props).filter(p => p.startsWith(ROUTER_PROP_REFIX));
if (navManager !== undefined) {
let navigationPayload: any = { event: ev };
routerProps.forEach(prop => {
navigationPayload[prop] = (props as any)[prop];
});
navManager.navigate(navigationPayload);
} else {
console.warn('Tried to navigate, but no router was found. Make sure you have mounted Vue Router.');
}
}
return () => {
getComponentClasses(attrs.class).forEach(value => {
classes.add(value);
});
const oldClick = (props as any).onClick;
const handleClick = (ev: Event) => {
if (oldClick !== undefined) {
oldClick(ev);
}
if (!ev.defaultPrevented) {
handleRouterLink(ev);
}
}
let propsToAdd = {
ref: containerRef,
class: getElementClasses(containerRef, classes),
onClick: handleClick,
onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
};
for (const [prop, value] of Object.entries(props)) {
if (value !== EMPTY_SENTINEL) {
propsToAdd[prop] = value;
}
}
if (modelProp) {
propsToAdd = {
...propsToAdd,
[modelProp]: props.modelValue !== EMPTY_SENTINEL ? props.modelValue : modelPropValue
}
}
return h(name, propsToAdd, slots.default && slots.default());
}
});
Container.displayName = name;
componentProps.push(ROUTER_LINK_VALUE);
if (modelProp) {
componentProps.push(MODEL_VALUE);
Container.emits = [UPDATE_VALUE_EVENT, modelUpdateEvent];
}
Container.props = {};
for (const componentProp of componentProps) {
Container.props[componentProp] = { default: EMPTY_SENTINEL };
}
return Container;
}
Example #20
Source File: RouteLayoutSource.ts From convue with MIT License | 5 votes |
export function createRouterLayout(
resolve: (layoutName: string) => Promise<Component | { default: Component }>,
) {
return defineComponent({
name: 'RouterLayout',
async beforeRouteEnter(to, _from, next) {
const name = to.meta.layout || 'default'
const layoutComp = name
? ((await resolve(name)) as any).default
: undefined
next((vm: any) => {
vm.layoutName = name
if (name && layoutComp)
vm.layouts[name] = layoutComp
})
},
async beforeRouteUpdate(to, _from, next) {
try {
const name = to.meta.layout || 'default'
if (name && !this.layouts[name])
this.layouts[name] = ((await resolve(name)) as any).default
this.layoutName = name
next()
}
catch (error) {
next(error)
}
},
data() {
return {
layoutName: undefined as string | undefined,
layouts: shallowReactive(
Object.create(null) as Record<string, Component>,
),
}
},
render(): VNode {
const layout = this.layoutName && this.layouts[this.layoutName]
if (!layout)
return h('span')
return h(layout as ConcreteComponent, {
key: this.layoutName,
})
},
})
}
Example #21
Source File: Translation.test.ts From vue-i18n-next with MIT License | 5 votes |
test('message resolver', async () => {
const fn = jest.fn()
const mockMessageResolver = fn as jest.MockedFunction<MessageResolver>
mockMessageResolver.mockImplementation(
(obj: unknown, path: Path): PathValue => {
const msg = (obj as any)[path] // eslint-disable-line @typescript-eslint/no-explicit-any
return msg != null ? msg : null
}
)
const en = {
'message.named': 'hello, {name}!'
}
const i18n = createI18n({
locale: 'en',
messageResolver: fn,
messages: { en }
})
const MyComponent = defineComponent({
setup(props, context: SetupContext) {
return (): VNodeChild => h('p', context.slots.default!())
}
})
const App = defineComponent({
data: () => ({ MyComponent }),
template: `
<i18n-t :tag="MyComponent" class="name" keypath="message.named">
<template #name>
<span>kazupon</span>
</template>
</i18n-t>
`
})
const wrapper = await mount(App, i18n)
expect(wrapper.html()).toEqual(
`<p class="name">hello, <span>kazupon</span>!</p>`
)
expect(mockMessageResolver).toHaveBeenCalledTimes(1)
expect(mockMessageResolver.mock.calls[0][0]).toEqual(en)
expect(mockMessageResolver.mock.calls[0][1]).toEqual('message.named')
})
Example #22
Source File: formatRenderer.ts From vue-i18n-next with MIT License | 5 votes |
export function renderFormatter<
Props extends FormattableProps<Value, Format>,
Value,
Format extends FormatOverrideOptions,
Arg extends FormatOptions,
Return extends FormatPartReturn
>(
props: Props,
context: SetupContext,
slotKeys: string[],
partFormatter: (...args: unknown[]) => string | Return[]
): RenderFunction {
const { slots, attrs } = context
return (): VNodeChild => {
const options = { part: true } as Arg
let overrides = {} as FormatOverrideOptions
if (props.locale) {
options.locale = props.locale
}
if (isString(props.format)) {
options.key = props.format
} else if (isObject(props.format)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (isString((props.format as any).key)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
options.key = (props.format as any).key
}
// Filter out number format options only
overrides = Object.keys(props.format).reduce((options, prop) => {
return slotKeys.includes(prop)
? assign({}, options, { [prop]: (props.format as any)[prop] }) // eslint-disable-line @typescript-eslint/no-explicit-any
: options
}, {})
}
const parts = partFormatter(...[props.value, options, overrides])
let children = [options.key] as VNodeArrayChildren
if (isArray(parts)) {
children = parts.map((part, index) => {
const slot = slots[part.type]
const node = slot
? slot({ [part.type]: part.value, index, parts })
: [part.value]
if (isVNode(node)) {
node[0].key = `${part.type}-${index}`
}
return node
})
} else if (isString(parts)) {
children = [parts]
}
const assignedAttrs = assign({}, attrs)
const tag =
isString(props.tag) || isObject(props.tag)
? props.tag
: getFragmentableTag('span')
return h(tag, assignedAttrs, children)
}
}
Example #23
Source File: Translation.ts From vue-i18n-next with MIT License | 5 votes |
Translation = /* #__PURE__*/ /* defineComponent */ {
/* eslint-disable */
name: 'i18n-t',
props: assign(
{
keypath: {
type: String,
required: true
},
plural: {
type: [Number, String],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
validator: (val: any): boolean => isNumber(val) || !isNaN(val)
}
},
baseFormatProps
),
/* eslint-enable */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setup(props: any, context: any): any {
const { slots, attrs } = context
// NOTE: avoid https://github.com/microsoft/rushstack/issues/1050
const i18n =
props.i18n ||
(useI18n({
useScope: props.scope as 'global' | 'parent',
__useComponent: true
}) as Composer & ComposerInternal)
const keys = Object.keys(slots).filter(key => key !== '_')
return (): VNodeChild => {
const options = {} as TranslateOptions
if (props.locale) {
options.locale = props.locale
}
if (props.plural !== undefined) {
options.plural = isString(props.plural) ? +props.plural : props.plural
}
const arg = getInterpolateArg(context, keys)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children = (i18n as any)[TransrateVNodeSymbol](
props.keypath,
arg,
options
)
const assignedAttrs = assign({}, attrs)
const tag =
isString(props.tag) || isObject(props.tag)
? props.tag
: getFragmentableTag('span')
return h(tag, assignedAttrs, children)
}
}
}
Example #24
Source File: utils.ts From elements with MIT License | 5 votes |
defineContainer = <Props>(
name: string,
defineCustomElement: any,
componentProps: string[] = [],
modelProp?: string,
modelUpdateEvent?: string,
externalModelUpdateEvent?: string
) => {
/**
* Create a Vue component wrapper around a Web Component.
* Note: The `props` here are not all properties on a component.
* They refer to whatever properties are set on an instance of a component.
*/
if (defineCustomElement !== undefined) {
defineCustomElement();
}
const Container = defineComponent<Props & InputProps>((props: any, { attrs, slots, emit }) => {
let modelPropValue = props[modelProp];
const containerRef = ref<HTMLElement>();
const classes = new Set(getComponentClasses(attrs.class));
const onVnodeBeforeMount = (vnode: VNode) => {
// Add a listener to tell Vue to update the v-model
if (vnode.el) {
const eventsNames = Array.isArray(modelUpdateEvent) ? modelUpdateEvent : [modelUpdateEvent];
eventsNames.forEach((eventName: string) => {
vnode.el.addEventListener(eventName.toLowerCase(), (e: Event) => {
modelPropValue = (e as CustomEvent).detail;
emit(UPDATE_VALUE_EVENT, modelPropValue);
/**
* We need to emit the change event here
* rather than on the web component to ensure
* that any v-model bindings have been updated.
* Otherwise, the developer will listen on the
* native web component, but the v-model will
* not have been updated yet.
*/
if (externalModelUpdateEvent) {
emit(externalModelUpdateEvent, e);
}
});
});
}
};
const currentInstance = getCurrentInstance();
const hasRouter = currentInstance?.appContext?.provides[NAV_MANAGER];
const navManager: NavManager | undefined = hasRouter ? inject(NAV_MANAGER) : undefined;
const handleRouterLink = (ev: Event) => {
const { routerLink } = props;
if (routerLink === EMPTY_PROP) return;
if (navManager !== undefined) {
let navigationPayload: any = { event: ev };
for (const key in props) {
const value = props[key];
if (props.hasOwnProperty(key) && key.startsWith(ROUTER_PROP_PREFIX) && value !== EMPTY_PROP) {
navigationPayload[key] = value;
}
}
navManager.navigate(navigationPayload);
} else {
console.warn('Tried to navigate, but no router was found. Make sure you have mounted Vue Router.');
}
}
return () => {
modelPropValue = props[modelProp];
getComponentClasses(attrs.class).forEach(value => {
classes.add(value);
});
const oldClick = props.onClick;
const handleClick = (ev: Event) => {
if (oldClick !== undefined) {
oldClick(ev);
}
if (!ev.defaultPrevented) {
handleRouterLink(ev);
}
}
let propsToAdd: any = {
ref: containerRef,
class: getElementClasses(containerRef, classes),
onClick: handleClick,
onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
};
/**
* We can use Object.entries here
* to avoid the hasOwnProperty check,
* but that would require 2 iterations
* where as this only requires 1.
*/
for (const key in props) {
const value = props[key];
if (props.hasOwnProperty(key) && value !== EMPTY_PROP) {
propsToAdd[key] = value;
}
}
if (modelProp) {
/**
* If form value property was set using v-model
* then we should use that value.
* Otherwise, check to see if form value property
* was set as a static value (i.e. no v-model).
*/
if (props[MODEL_VALUE] !== EMPTY_PROP) {
propsToAdd = {
...propsToAdd,
[modelProp]: props[MODEL_VALUE]
}
} else if (modelPropValue !== EMPTY_PROP) {
propsToAdd = {
...propsToAdd,
[modelProp]: modelPropValue
}
}
}
return h(name, propsToAdd, slots.default && slots.default());
}
});
Container.displayName = name;
Container.props = {
[ROUTER_LINK_VALUE]: DEFAULT_EMPTY_PROP
};
componentProps.forEach(componentProp => {
Container.props[componentProp] = DEFAULT_EMPTY_PROP;
});
if (modelProp) {
Container.props[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent];
}
return Container;
}
Example #25
Source File: FormKit.ts From formkit with MIT License | 5 votes |
FormKit = defineComponent({
props,
emits: {
/* eslint-disable @typescript-eslint/no-unused-vars */
input: (_value: any, _node: FormKitNode) => true,
inputRaw: (_value: any, _node: FormKitNode) => true,
'update:modelValue': (_value: any) => true,
node: (node: FormKitNode) => !!node,
submit: (_data: FormKitGroupValue, _node: FormKitNode) => true,
submitRaw: (_event: Event, _node: FormKitNode) => true,
/* eslint-enable @typescript-eslint/no-unused-vars */
},
inheritAttrs: false,
setup(props, context) {
const node = useInput(props, context)
if (!node.props.definition) error(600, node)
if (node.props.definition.component) {
return () =>
h(
node.props.definition?.component as any,
{
context: node.context,
},
{ ...context.slots }
)
}
const schema = ref<FormKitSchemaCondition | FormKitSchemaNode[]>([])
const generateSchema = () => {
const schemaDefinition = node.props?.definition?.schema
if (!schemaDefinition) error(601, node)
schema.value =
typeof schemaDefinition === 'function'
? schemaDefinition({ ...props.sectionsSchema })
: schemaDefinition
}
generateSchema()
// If someone emits the schema event, we re-generate the schema
node.on('schema', generateSchema)
context.emit('node', node)
const library = node.props.definition.library as
| Record<string, ConcreteComponent>
| undefined
// Expose the FormKitNode to template refs.
context.expose({ node })
return () =>
h(
FormKitSchema,
{ schema: schema.value, data: node.context, library },
{ ...context.slots }
)
},
})
Example #26
Source File: form.spec.ts From formkit with MIT License | 5 votes |
describe('form structure', () => {
it('renders a form with a button', () => {
const wrapper = mount(FormKit, {
props: {
type: 'form',
name: 'test_form',
id: 'foo',
submitAttrs: {
id: 'button',
},
},
slots: {
default: () => h('h1', 'in the form'),
},
...global,
})
expect(wrapper.html())
.toEqual(`<form id="foo" class="formkit-form" name="test_form">
<h1>in the form</h1>
<!---->
<div class="formkit-actions">
<div class="formkit-outer" data-type="submit">
<!---->
<div class="formkit-wrapper"><button type="submit" class="formkit-input" name="submit_1" id="button">
<!---->Submit
<!---->
</button></div>
<!---->
</div>
</div>
</form>`)
})
it('outputs the id of the form', () => {
const id = token()
const wrapper = mount(FormKit, {
props: {
type: 'form',
id,
},
...global,
})
expect(wrapper.find('form').attributes('id')).toBe(id)
})
})
Example #27
Source File: app.ts From vite-plugin-ssr with MIT License | 5 votes |
function createApp(pageContext: PageContext) {
const { Page } = pageContext
let rootComponent: Component
const PageWithWrapper = defineComponent({
data: () => ({
Page: markRaw(Page),
pageProps: markRaw(pageContext.pageProps || {}),
}),
created() {
rootComponent = this
},
render() {
return h(
PageShell,
{},
{
default: () => {
return h(this.Page, this.pageProps)
},
},
)
},
})
const app = createSSRApp(PageWithWrapper)
// We use `app.changePage()` to do Client Routing, see `_default.page.client.js`
objectAssign(app, {
changePage: (pageContext: PageContext) => {
Object.assign(pageContextReactive, pageContext)
rootComponent.Page = markRaw(pageContext.Page)
rootComponent.pageProps = markRaw(pageContext.pageProps || {})
},
})
// When doing Client Routing, we mutate pageContext (see usage of `app.changePage()` in `_default.page.client.js`).
// We therefore use a reactive pageContext.
const pageContextReactive = reactive(pageContext)
// Make `pageContext` accessible from any Vue component
setPageContext(app, pageContextReactive)
return app
}
Example #28
Source File: index.ts From vue3-echarts with MIT License | 5 votes |
render() {
return h('div', { class: 'vue-echarts' });
}
Example #29
Source File: index.spec.ts From css-render with MIT License | 4 votes |
describe('ssr', () => {
describe('render to string', () => {
const Child = defineComponent({
setup () {
c('div', {
color: 'red'
}).mount({
id: 'mount-id',
ssr: useSsrAdapter()
})
},
render () {
return h('div', null, 'Child')
}
})
const App = defineComponent({
render () {
return h(Child)
}
})
const app = createSSRApp(App)
const { collect } = setup(app)
it('should work', (done) => {
renderToString(app).then((v) => {
expect(collect() + v).toMatchSnapshot()
done()
})
})
})
describe('useSsrAdapter', () => {
const Child = defineComponent({
setup () {
c('div', {
color: 'red'
}).mount({
id: 'mount-id',
ssr: useSsrAdapter()
})
},
render () {
return h('div', null, 'Child')
}
})
const App = defineComponent({
render () {
return h(Child)
}
})
const app = createSSRApp(App)
const { collect } = setup(app)
it('should work', (done) => {
renderToString(app).then((v) => {
expect(collect() + v).toMatchSnapshot()
done()
})
})
})
// uncomment after vue fixes the stream ssr bug
// describe('render to stream', () => {
// it('should work', (done) => {
// const app = createSSRApp({
// render () {
// return [
// h(Foo),
// h(Suspense, null, {
// default: () => h(Bar),
// ssFallback: () => 'suspense'
// }),
// h(Foo)
// ]
// }
// })
// const Foo = {
// setup () {
// c('div', {
// color: 'foo'
// }).mount({
// id: 'foo',
// ssr: ssrAdapter
// })
// },
// render: () => h('div', 'foo')
// }
// const Bar = {
// async setup () {
// c('div', {
// color: 'bar'
// }).mount({
// id: 'bar',
// ssr: ssrAdapter
// })
// await new Promise((resolve) => setTimeout(resolve, 1000))
// },
// render: () => {
// return [h('div', 'bar'), h(Foo)]
// }
// }
// const { collect } = setup(app)
// const rs = renderToStream(app)
// let html = ''
// rs.on('data', (chunk) => {
// html += `${collect()}\n${chunk.toString() as string}`
// })
// rs.on('end', () => {
// expect(html).toMatchSnapshot()
// done()
// })
// })
// })
})