diff --git a/src/lib/LifeCycle/index.ts b/src/lib/LifeCycle/index.ts index d8a6ee9..0a1731f 100644 --- a/src/lib/LifeCycle/index.ts +++ b/src/lib/LifeCycle/index.ts @@ -12,7 +12,7 @@ import { renderHtmlTagObjectsToFragment, renderHtmlTagObjectToHtmlElement, } from '@/utils/htmlTag'; -import { MagicOptions, Module, ModuleType } from '../../'; +import { MagicOptions, Module, ModuleType, MagicInstanceType } from '../../'; import heap from '../Heap'; import { Hook } from './Hook'; @@ -20,6 +20,10 @@ export enum MagicHooks { beforeOptionsInit = 'beforeOptionsInit', alterHTMLTags = 'alterHTMLTags', beforeElementDefinition = 'beforeElementDefinition', + boforeBootstrap = 'boforeBootstrap', + beforeMount = 'beforeMount', + beforeUpdated = 'beforeUpdated', + boforeUnmount = 'boforeUnmount', } const hooks = Object.values(MagicHooks); @@ -48,9 +52,11 @@ export interface AttributeUpdateConfigType { newValue: unknown; } +export type LifeCycleType> = LifeCycle | MagicInstanceType; + export type LifeCycleHookType> = Record< MagicHooks, - Hook, LifeCycle> + Hook, LifeCycleType> >; interface IBuildFragmentOutput { @@ -126,7 +132,7 @@ export default class LifeCycle> { private generateCustomElement = () => { // eslint-disable-next-line @typescript-eslint/no-this-alias - const { options, module, buildFragment } = this; + const { options, module, buildFragment, hooks } = this; return class CustomElement extends CustomElementType { public attributesObj: Props = {} as Props; public webComponentsIns: ShadowRoot | HTMLElement; @@ -140,7 +146,9 @@ export default class LifeCycle> { constructor() { super(); this.webComponentsIns = options.shadow ? this.attachShadow({ mode: 'open' }) : this; - module.bootstrap && module.bootstrap(this); + hooks.boforeBootstrap.call(this).then(() => { + module.bootstrap && module.bootstrap(this); + }); } connectedCallback() { @@ -148,11 +156,11 @@ export default class LifeCycle> { this.contentWrapper = contentWrapper; this.htmlTagFragment = htmlTagFragment; this.webComponentsIns.appendChild(this.htmlTagFragment); - module.mount(this.contentWrapper, this.attributesObj, this); + hooks.beforeMount.call(this).then(() => module.mount(this.contentWrapper, this.attributesObj, this)); } disconnectedCallback() { - module.unmount && module.unmount(this, this.contentWrapper); + hooks.boforeUnmount.call(this).then(() => module.unmount && module.unmount(this, this.contentWrapper)); } attributeChangedCallback(attributeName: keyof Props, _oldValue: string, newValue: string) { @@ -162,14 +170,16 @@ export default class LifeCycle> { const propsValue = heap.getPropsValue(attributeName, newValue, options.propTypes); const prevValue = this.attributesObj[attributeName]; this.attributesObj[attributeName] = propsValue; - (attributeName in oldAttributesObj ? module.updated : module.firstUpdated)?.( - attributeName, - propsValue, - this.contentWrapper, - this.attributesObj, - this, - prevValue, - ); + hooks.beforeUpdated.call(this).then(() => { + (attributeName in oldAttributesObj ? module.updated : module.firstUpdated)?.( + attributeName, + propsValue, + this.contentWrapper, + this.attributesObj, + this, + prevValue, + ); + }); } }; }; diff --git a/tests/magic.spec.ts b/tests/magic.spec.ts index d547c8a..08a51bf 100644 --- a/tests/magic.spec.ts +++ b/tests/magic.spec.ts @@ -4,8 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -import magic, { useProps, isModuleRegistered, MagicInstanceType } from '@/index'; -import LifeCycle from '@/lib/LifeCycle'; +import magic, { useProps, isModuleRegistered, MagicInstanceType, LifeCycle } from '@/index'; const componentTag = 'my-component'; const shadowComponentTag = 'my-component-shadow'; @@ -168,25 +167,41 @@ describe('test magic', () => { }); test('test plugins', (done) => { - interface testLifeCycleType extends LifeCycle> { - test: number; - } + type testLifeCycle = LifeCycle & { test: number }; + type testMagicInstanceType = MagicInstanceType & { test: number }; const test = 1; class MagicPlugin { - apply(lifeCycle: LifeCycle>) { - lifeCycle.hooks.beforeOptionsInit.tap((lifeCycle: testLifeCycleType) => { + apply(lifeCycle: LifeCycle) { + lifeCycle.hooks.beforeOptionsInit.tap((lifeCycle: testLifeCycle) => { expect(lifeCycle.test).toBeUndefined(); }); lifeCycle.hooks.alterHTMLTags.tap([ - (lifeCycle: testLifeCycleType) => { + (lifeCycle: testLifeCycle) => { lifeCycle.test = test; }, - (lifeCycle: testLifeCycleType) => { + (lifeCycle: testLifeCycle) => { expect(lifeCycle.test).toBe(test); }, ]); - lifeCycle.hooks.beforeElementDefinition.tap((lifeCycle: testLifeCycleType) => { + lifeCycle.hooks.beforeElementDefinition.tap((lifeCycle: testLifeCycle) => { expect(lifeCycle.test).toBe(test); + }); + lifeCycle.hooks.boforeBootstrap.tap((magicInstance: testMagicInstanceType) => { + expect(magicInstance.test).toBeUndefined(); + }); + lifeCycle.hooks.beforeMount.tap([ + (magicInstance: testMagicInstanceType) => { + magicInstance.test = test; + }, + (magicInstance: testMagicInstanceType) => { + expect(magicInstance.test).toBe(test); + }, + ]); + lifeCycle.hooks.beforeUpdated.tap((magicInstance: testMagicInstanceType) => { + expect(magicInstance.test).toBe(test); + }); + lifeCycle.hooks.boforeUnmount.tap((magicInstance: testMagicInstanceType) => { + expect(magicInstance.test).toBe(test); done(); }); }