Skip to content

Commit

Permalink
feat: based on @muxiu1997/vue-easy-di
Browse files Browse the repository at this point in the history
release-as: 0.1.0-rc.7
  • Loading branch information
MuXiu1997 committed Nov 27, 2023
1 parent 782df7f commit dd59128
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 71 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@
}
},
"dependencies": {
"@muxiu1997/vue-easy-di": "^0.1.0-rc.1",
"mitt": "^3.0.1",
"vue-demi": "latest"
},
"devDependencies": {
"@antfu/eslint-config": "^2.1.0",
"@types/node": ">=20.0.0",
"@vitest/coverage-v8": "^1.0.0-beta.5",
"@vitest/ui": "^1.0.0-beta.5",
"@vue/test-utils": "^2.4.2",
Expand Down
85 changes: 64 additions & 21 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 12 additions & 44 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import defineUseDependencyInjection from '@muxiu1997/vue-easy-di'
import mitt from 'mitt'
import { getCurrentInstance, inject, onUnmounted, provide } from 'vue-demi'
import { getCurrentInstance, onUnmounted } from 'vue-demi'

import type { Options as DIOptions, UseInitiatedDependencyInjection } from '@muxiu1997/vue-easy-di'
import type { Emitter, EventType, Handler, WildcardHandler } from 'mitt'
import type { InjectionKey } from 'vue-demi'

export type Options<Events extends Record<EventType, unknown>> = DIOptions<AutoOffEmitter<Events>>

/**
* Extends the Emitter interface to include an `autoOff` method.
Expand Down Expand Up @@ -36,30 +39,10 @@ export function wrapAutoOff<Events extends Record<EventType, unknown>>(
})
}

export interface WithInjectDefault<Events extends Record<EventType, unknown>> {
injectDefault: AutoOffEmitter<Events> | (() => AutoOffEmitter<Events>)
}

export interface WithThrowOnNoProvider {
throwOnNoProvider: () => Error
}

export type Options<Events extends Record<EventType, unknown>> = {
key?: InjectionKey<AutoOffEmitter<Events>> | string
} & (WithInjectDefault<Events> | WithThrowOnNoProvider)

export type UseEmitterMode = 'inject' | 'provide'

/**
* A composable for using the AutoOffEmitter in a Vue component. It can be used in 'inject' or 'provide' mode.
*/
export interface UseEmitter<EE extends AutoOffEmitter<any> | undefined> {
(mode: 'provide'): NonNullable<EE>

(mode: 'inject'): EE

(): EE
}
export type UseEmitter<EE extends AutoOffEmitter<any> | undefined> = UseInitiatedDependencyInjection<EE>

/**
* Defines a composable for Vue that provides or injects an event emitter.
Expand Down Expand Up @@ -155,25 +138,10 @@ export default function defineEmitterComposable<Events extends Record<EventType,

export default function defineEmitterComposable<Events extends Record<EventType, unknown>>(
options: Partial<Options<Events>> = {},
): UseEmitter<AutoOffEmitter<Events> | undefined> {
const injectKey = options.key ?? (Symbol('vue-use-emitter') as InjectionKey<AutoOffEmitter<Events>>)
return ((mode: UseEmitterMode = 'inject') => {
if (mode === 'provide') {
const emitter: AutoOffEmitter<Events> = wrapAutoOff(mitt())
provide(injectKey, emitter)

return emitter
}

if ('injectDefault' in options && options.injectDefault != null) {
return inject(injectKey, options.injectDefault, true)
}

const emitter = inject(injectKey)
if (emitter == null && 'throwOnNoProvider' in options && options.throwOnNoProvider != null) {
throw options.throwOnNoProvider()
}

return emitter
}) as UseEmitter<AutoOffEmitter<Events> | undefined>
): UseEmitter<AutoOffEmitter<Events> | undefined> | UseEmitter<AutoOffEmitter<Events>> {
if (options.key == null) options.key = Symbol('vue-use-emitter')
return defineUseDependencyInjection(
() => wrapAutoOff(mitt()),
options,
)
}
18 changes: 14 additions & 4 deletions test/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
import mitt from 'mitt'
import { expectTypeOf } from 'vitest'

import {
useUndefinedEmitter,
useWithInjectDefaultEmitter,
useWithThrowOnNoProviderEmitter,
} from '#/index.test'
import { wrapAutoOff } from '~'

import type {
TestEvents,
} from '#/index.test'
import type { Emitter } from 'mitt'
import type { AutoOffEmitter } from '~'

describe.concurrent('useEmitter return correct type with different options', () => {
test('No options - inject mode maybe return undefined', async () => {
test('wrapAutoOff correct type', () => {
expectTypeOf(wrapAutoOff(mitt<TestEvents>())).toEqualTypeOf<AutoOffEmitter<TestEvents>>()
expectTypeOf(wrapAutoOff(mitt<TestEvents>())).toMatchTypeOf<Emitter<TestEvents>>()
expectTypeOf(wrapAutoOff(mitt<TestEvents>())).toHaveProperty('autoOff')
expectTypeOf(wrapAutoOff(mitt<TestEvents>()).autoOff).toEqualTypeOf<Emitter<TestEvents>['on']>()
})

describe('useEmitter return correct type with different options', () => {
test('No options - inject mode maybe return undefined', () => {
expectTypeOf(useUndefinedEmitter('provide')).toEqualTypeOf<AutoOffEmitter<TestEvents>>()
expectTypeOf(useUndefinedEmitter('inject')).toEqualTypeOf<AutoOffEmitter<TestEvents> | undefined>()
})

test('With injects default', async () => {
test('With injects default', () => {
expectTypeOf(useWithInjectDefaultEmitter('provide')).toEqualTypeOf<AutoOffEmitter<TestEvents>>()
expectTypeOf(useWithInjectDefaultEmitter('inject')).toEqualTypeOf<AutoOffEmitter<TestEvents>>()
})

test('With throw on no provider', async () => {
test('With throw on no provider', () => {
expectTypeOf(useWithThrowOnNoProviderEmitter('provide')).toEqualTypeOf<AutoOffEmitter<TestEvents>>()
expectTypeOf(useWithThrowOnNoProviderEmitter('inject')).toEqualTypeOf<AutoOffEmitter<TestEvents>>()
})
Expand Down
2 changes: 1 addition & 1 deletion test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ it('wrapAutoOff correct behavior', ({ expect }) => {

describe.concurrent(`useEmitter('inject') correct behavior with no provider`, () => {
// region Define Components
function createComponent<UE extends UseEmitter<AutoOffEmitter<TestEvents> | undefined>>(useEmitter: UE) {
function createComponent<UE extends UseEmitter<AutoOffEmitter<TestEvents> | undefined> | UseEmitter<AutoOffEmitter<TestEvents>>>(useEmitter: UE) {
const ChildComponent = defineComponent({
setup() {
const emitter = useEmitter()
Expand Down
Loading

0 comments on commit dd59128

Please sign in to comment.