1
0
mirror of https://github.com/robonen/tools.git synced 2026-03-20 19:04:46 +00:00

feat(packages/vue): add useContexFactory composable

This commit is contained in:
2024-10-05 22:02:45 +07:00
parent b525d08363
commit e84187fa02
2 changed files with 103 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
import { describe, it, expect } from 'vitest';
import { defineComponent } from 'vue';
import { useContextFactory } from './index';
import { mount } from '@vue/test-utils';
import { VueToolsError } from '../../utils';
function testFactory<Data>(
data: Data,
options?: { contextName?: string, fallback?: Data },
) {
const contextName = options?.contextName ?? 'TestContext';
const [inject, provide] = useContextFactory(contextName);
const Child = defineComponent({
setup() {
const value = inject(options?.fallback);
return { value };
},
template: `{{ value }}`,
});
const Parent = defineComponent({
components: { Child },
setup() {
provide(data);
},
template: `<Child />`,
});
return {
Parent,
Child,
};
}
// TODO: maybe replace template with passing mock functions to setup
describe('useContextFactory', () => {
it('should provide and inject context correctly', () => {
const { Parent } = testFactory('test');
const component = mount(Parent);
expect(component.text()).toBe('test');
});
it('should throw an error when context is not provided', () => {
const { Child } = testFactory('test');
expect(() => mount(Child)).toThrow(VueToolsError);
});
it('should inject a fallback value when context is not provided', () => {
const { Child } = testFactory('test', { fallback: 'fallback' });
const component = mount(Child);
expect(component.text()).toBe('fallback');
});
it('should correctly handle null values', () => {
const { Parent } = testFactory(null);
const component = mount(Parent);
expect(component.text()).toBe('');
});
});

View File

@@ -0,0 +1,34 @@
import { inject, provide, type InjectionKey } from 'vue';
import { VueToolsError } from '../../utils';
/**
* @name useContextFactory
* @category Utilities
* @description A composable that provides a factory for creating context with unique key
*
* @param {string} name The name of the context
* @returns {readonly [injectContext, provideContext]} The context factory
* @throws {VueToolsError} when the context is not provided
*
* @example
* const [injectContext, provideContext] = useContextFactory('MyContext');
*/
export function useContextFactory<ContextValue>(name: string) {
const injectionKey: InjectionKey<ContextValue> = Symbol(name);
const injectContext = <Fallback extends ContextValue = ContextValue>(fallback?: Fallback) => {
const context = inject(injectionKey, fallback);
if (context !== undefined)
return context;
throw new VueToolsError(`useContextFactory: '${name}' context is not provided`);
};
const provideContext = (context: ContextValue) => {
provide(injectionKey, context);
return context;
};
return [injectContext, provideContext] as const;
}