diff --git a/docs/presentation.md b/docs/presentation.md index 1ace9c2e..d5cdb281 100644 --- a/docs/presentation.md +++ b/docs/presentation.md @@ -71,10 +71,11 @@ To add a new dependency: 1. **Define its symbol**: Define an associated symbol for every dependency in [`injectionSymbols.ts`](./../src/presentation/injectionSymbols.ts). Symbols are grouped into: - **Singletons**: Shared across components, instantiated once. - **Transients**: Factories yielding a new instance on every access. -2. **Provide the dependency**: Modify the [`provideDependencies`](./../src/presentation/bootstrapping/DependencyProvider.ts) function to include the new dependency. [`App.vue`](./../src/presentation/components/App.vue) calls this function within its `setup()` hook to register the dependencies. -3. **Inject the dependency**: Use Vue's `inject` method alongside the defined symbol to incorporate the dependency into components. - - For singletons, invoke the factory method: `inject(symbolKey)()`. - - For transients, directly inject: `inject(symbolKey)`. +2. **Provide the dependency**: + Modify the [`provideDependencies`](./../src/presentation/bootstrapping/DependencyProvider.ts) function to include the new dependency. + [`App.vue`](./../src/presentation/components/App.vue) calls this function within its `setup()` hook to register the dependencies. +3. **Inject the dependency**: Use `injectKey` to inject a dependency. Pass a selector function to `injectKey` that retrieves the appropriate symbol from the provided dependencies. + - Example usage: `injectKey((keys) => keys.useCollectionState)`; ## Shared UI components diff --git a/src/presentation/bootstrapping/DependencyProvider.ts b/src/presentation/bootstrapping/DependencyProvider.ts index dc392c02..09f67d0b 100644 --- a/src/presentation/bootstrapping/DependencyProvider.ts +++ b/src/presentation/bootstrapping/DependencyProvider.ts @@ -2,38 +2,89 @@ import { InjectionKey, provide, inject } from 'vue'; import { useCollectionState } from '@/presentation/components/Shared/Hooks/UseCollectionState'; import { useApplication } from '@/presentation/components/Shared/Hooks/UseApplication'; import { useAutoUnsubscribedEvents } from '@/presentation/components/Shared/Hooks/UseAutoUnsubscribedEvents'; +import { useClipboard } from '@/presentation/components/Shared/Hooks/Clipboard/UseClipboard'; +import { useCurrentCode } from '@/presentation/components/Shared/Hooks/UseCurrentCode'; import { IApplicationContext } from '@/application/Context/IApplicationContext'; import { RuntimeEnvironment } from '@/infrastructure/RuntimeEnvironment/RuntimeEnvironment'; -import { InjectionKeys } from '@/presentation/injectionSymbols'; -import { useClipboard } from '../components/Shared/Hooks/Clipboard/UseClipboard'; -import { useCurrentCode } from '../components/Shared/Hooks/UseCurrentCode'; +import { + AnyLifetimeInjectionKey, InjectionKeySelector, InjectionKeys, SingletonKey, + TransientKey, injectKey, +} from '@/presentation/injectionSymbols'; +import { PropertyKeys } from '@/TypeHelpers'; export function provideDependencies( context: IApplicationContext, api: VueDependencyInjectionApi = { provide, inject }, ) { - const registerSingleton = (key: InjectionKey, value: T) => api.provide(key, value); - const registerTransient = ( - key: InjectionKey<() => T>, - factory: () => T, - ) => api.provide(key, factory); + const resolvers: Record, (di: DependencyRegistrar) => void> = { + useCollectionState: (di) => di.provide( + InjectionKeys.useCollectionState, + () => { + const { events } = di.injectKey((keys) => keys.useAutoUnsubscribedEvents); + return useCollectionState(context, events); + }, + ), + useApplication: (di) => di.provide( + InjectionKeys.useApplication, + useApplication(context.app), + ), + useRuntimeEnvironment: (di) => di.provide( + InjectionKeys.useRuntimeEnvironment, + RuntimeEnvironment.CurrentEnvironment, + ), + useAutoUnsubscribedEvents: (di) => di.provide( + InjectionKeys.useAutoUnsubscribedEvents, + useAutoUnsubscribedEvents, + ), + useClipboard: (di) => di.provide( + InjectionKeys.useClipboard, + useClipboard, + ), + useCurrentCode: (di) => di.provide( + InjectionKeys.useCurrentCode, + () => { + const { events } = di.injectKey((keys) => keys.useAutoUnsubscribedEvents); + const state = di.injectKey((keys) => keys.useCollectionState); + return useCurrentCode(state, events); + }, + ), + }; + registerAll(Object.values(resolvers), api); +} - registerSingleton(InjectionKeys.useApplication, useApplication(context.app)); - registerSingleton(InjectionKeys.useRuntimeEnvironment, RuntimeEnvironment.CurrentEnvironment); - registerTransient(InjectionKeys.useAutoUnsubscribedEvents, () => useAutoUnsubscribedEvents()); - registerTransient(InjectionKeys.useCollectionState, () => { - const { events } = api.inject(InjectionKeys.useAutoUnsubscribedEvents)(); - return useCollectionState(context, events); - }); - registerTransient(InjectionKeys.useClipboard, () => useClipboard()); - registerTransient(InjectionKeys.useCurrentCode, () => { - const { events } = api.inject(InjectionKeys.useAutoUnsubscribedEvents)(); - const state = api.inject(InjectionKeys.useCollectionState)(); - return useCurrentCode(state, events); - }); +function registerAll( + registrations: ReadonlyArray<(di: DependencyRegistrar) => void>, + api: VueDependencyInjectionApi, +) { + const registrar = new DependencyRegistrar(api); + Object.values(registrations).forEach((register) => register(registrar)); } export interface VueDependencyInjectionApi { provide(key: InjectionKey, value: T): void; inject(key: InjectionKey): T; } + +class DependencyRegistrar { + constructor(private api: VueDependencyInjectionApi) {} + + public provide( + key: TransientKey, + resolver: () => T, + ): void; + public provide( + key: SingletonKey, + resolver: T, + ): void; + public provide( + key: AnyLifetimeInjectionKey, + resolver: T | (() => T), + ): void { + this.api.provide(key.key, resolver); + } + + public injectKey(key: InjectionKeySelector): T { + const injector = this.api.inject.bind(this.api); + return injectKey(key, injector); + } +} diff --git a/src/presentation/components/Code/CodeButtons/CodeCopyButton.vue b/src/presentation/components/Code/CodeButtons/CodeCopyButton.vue index ab20237e..3c38cdba 100644 --- a/src/presentation/components/Code/CodeButtons/CodeCopyButton.vue +++ b/src/presentation/components/Code/CodeButtons/CodeCopyButton.vue @@ -7,10 +7,8 @@