@v4fire/client
Version:
V4Fire client core library
158 lines (126 loc) • 4.02 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
import * as init from 'core/component/construct';
import { forkMeta } from 'core/component/meta';
import { initProps } from 'core/component/prop';
import type { RenderContext } from 'core/component/render';
import type { CreateElement } from 'core/component/engines';
import { $$, componentOpts } from 'core/component/functional/const';
import { destroyComponent } from 'core/component/functional/helpers';
import type { FunctionalCtx } from 'core/component/interface';
import type { CreateFakeCtxOptions } from 'core/component/functional/interface';
export * from 'core/component/functional/interface';
/**
* Creates the fake context for a functional component is based on the specified parameters
*
* @param createElement - function to create VNode element
* @param renderCtx - render context from VNode
* @param baseCtx - component context that provided the core functionality
* @param [opts] - additional options
*/
export function createFakeCtx<T extends object = FunctionalCtx>(
createElement: CreateElement,
renderCtx: Partial<RenderContext>,
baseCtx: FunctionalCtx,
opts: CreateFakeCtxOptions
): T {
const
fakeCtx = Object.create(baseCtx),
meta = forkMeta(fakeCtx.meta);
const
{component} = meta,
{parent, children, data: dataOpts} = renderCtx;
let
$options;
if (parent?.$options) {
const {
filters = {},
directives = {},
components = {}
} = parent.$options;
$options = {
filters: Object.create(filters),
directives: Object.create(directives),
components: Object.create(components)
};
} else {
$options = {
filters: {},
directives: {},
components: {}
};
}
if (Object.isDictionary(component)) {
Object.assign($options, Object.reject(component, componentOpts));
Object.assign($options.filters, component.filters);
Object.assign($options.directives, component.directives);
Object.assign($options.components, component.components);
}
if (renderCtx.$options) {
const o = renderCtx.$options;
Object.assign($options, Object.reject(o, componentOpts));
Object.assign($options.filters, o.filters);
Object.assign($options.directives, o.directives);
Object.assign($options.components, o.components);
}
fakeCtx.unsafe = fakeCtx;
fakeCtx.children = Object.isArray(children) ? children : [];
fakeCtx.$parent = parent;
fakeCtx.$root = renderCtx.$root ?? parent?.$root ?? fakeCtx;
fakeCtx.$renderEngine = fakeCtx.$root.$renderEngine;
fakeCtx.$options = $options;
fakeCtx.$props = renderCtx.props ?? {};
fakeCtx.$attrs = dataOpts?.attrs ?? {};
fakeCtx.$listeners = renderCtx.listeners ?? dataOpts?.on ?? {};
fakeCtx.$refs = {};
fakeCtx.$slots = {
default: Object.size(children) > 0 ? children : undefined,
...renderCtx.slots?.()
};
fakeCtx.$scopedSlots = {
...Object.isFunction(renderCtx.scopedSlots) ? renderCtx.scopedSlots() : renderCtx.scopedSlots
};
fakeCtx.$createElement = createElement.bind(fakeCtx);
fakeCtx.$destroy = () => destroyComponent(fakeCtx);
fakeCtx._self = fakeCtx;
fakeCtx._renderProxy = fakeCtx;
fakeCtx._c = fakeCtx.$createElement;
fakeCtx._staticTrees = [];
fakeCtx.$nextTick = (cb?: Function) => {
const
{$async: $a} = fakeCtx;
if (cb) {
$a.setImmediate(cb);
return;
}
return $a.nextTick();
};
fakeCtx.$forceUpdate = () => {
// eslint-disable-next-line @typescript-eslint/unbound-method
if (!Object.isFunction(parent?.$forceUpdate)) {
return;
}
fakeCtx.$async.setImmediate(() => parent!.$forceUpdate(), {
label: $$.forceUpdate
});
};
if (fakeCtx.$root == null) {
fakeCtx.$root = fakeCtx;
}
initProps(fakeCtx, {
from: renderCtx.props,
store: fakeCtx,
saveToStore: opts.initProps
});
init.beforeCreateState(fakeCtx, meta, {
addMethods: true,
implementEventAPI: true
});
init.beforeDataCreateState(fakeCtx, {tieFields: true});
return fakeCtx;
}