Skip to content

Commit

Permalink
feat: Added definePlugin hybrid function.
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgrozav committed Mar 11, 2022
1 parent 321adb8 commit 0826a51
Show file tree
Hide file tree
Showing 14 changed files with 206 additions and 3 deletions.
3 changes: 3 additions & 0 deletions packages/common/src/definePlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { DefinePluginFn } from './types';

export const definePlugin: DefinePluginFn<any, any> = () => ({});
1 change: 1 addition & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './computed';
export * from './defineComponent';
export * from './definePlugin';
export * from './events';
export * from './h';
export * from './provide';
Expand Down
12 changes: 12 additions & 0 deletions packages/common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ export interface InjectFn<T = any> {
(identifier: string | symbol, defaultValue?: T | (() => T)): T | undefined
}

/**
* Plugin types
*/

export interface DefinePluginContext {
provide: ProvideFn;
}

export interface DefinePluginFn<Plugin, Options = any> {
(setup: (options: Options, context: DefinePluginContext) => void): Plugin;
}

/**
* Storybook types
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Vitest Snapshot v1

exports[`react > definePlugin() > should create a new higher order component 1`] = `
<div>
Hello world!
</div>
`;

exports[`react > definePlugin() > should provide data to children 1`] = `
<div>
light
</div>
`;
58 changes: 58 additions & 0 deletions packages/react/src/__tests__/definePlugin.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { describe, it, expect } from 'vitest';
import { render } from '@testing-library/react';
import { defineComponent, definePlugin, h, inject } from '../index';

describe('react', () => {
describe('definePlugin()', () => {
it('should create a new higher order component', () => {
const Plugin = definePlugin(() => {});
const Component = defineComponent({
render () {
return h('div', {}, 'Hello world!');
}
});

const wrapper = render(h(Plugin, {}, h(Component)) as any);
expect(wrapper.container.firstChild).toMatchSnapshot();
});

it('should be called with plugin options', () => {
const pluginOptions = {
color: 'light'
};

const Plugin = definePlugin((options) => {
expect(options).toEqual(pluginOptions);
});
const Component = defineComponent({
render () {
return h('div', {}, 'Hello world!');
}
});

render(h(Plugin, { options: pluginOptions }, h(Component)) as any);
});

it('should provide data to children', () => {
const provideSymbol = Symbol('provide');
const provideData = { color: 'light' };

const Plugin = definePlugin((options, { provide }) => {
provide(provideSymbol, provideData);
});
const Component = defineComponent({
setup () {
const data = inject(provideSymbol);

return { data };
},
render ({ data }) {
return h('div', {}, data?.color);
}
});

const wrapper = render(h(Plugin, {}, h(Component)) as any);
expect(wrapper.container.firstChild).toMatchSnapshot();
});
});
});
15 changes: 15 additions & 0 deletions packages/react/src/definePlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { DefineReactPluginFn } from './types';
import { provide } from './provide';

export const definePlugin: DefineReactPluginFn = (setup) => ({ children, options }) => {
/**
* Setup the plugin
*/

setup(options, { provide });

/**
* Render the child components array as-is
*/
return children;
};
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './computed';
export * from './defineComponent';
export * from './definePlugin';
export * from './events';
export * from './h';
export * from './helpers';
Expand Down
12 changes: 12 additions & 0 deletions packages/react/src/types-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ export interface InjectFn<T = any> {
(identifier: string | symbol, defaultValue?: T | (() => T)): T | undefined
}

/**
* Plugin types
*/

export interface DefinePluginContext {
provide: ProvideFn;
}

export interface DefinePluginFn<Plugin, Options = any> {
(setup: (options: Options, context: DefinePluginContext) => void): Plugin;
}

/**
* Storybook types
*/
Expand Down
4 changes: 3 additions & 1 deletion packages/react/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DefineComponentFn } from './types-common';
import {DefineComponentFn, DefinePluginFn} from './types-common';
import { FunctionComponent } from 'react';

export * from './types-common';
Expand All @@ -16,3 +16,5 @@ export type DefineReactComponentFn<
Props = Record<string, any>,
State = Record<string, any>
> = DefineComponentFn<Props, State, VNode, FunctionComponent<Props> & { [key: string]: any; }>

export type DefineReactPluginFn<Options = any> = DefinePluginFn<FunctionComponent<{ options: Options, children: any }>, Options>;
45 changes: 45 additions & 0 deletions packages/vue/src/__tests__/definePlugin.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, it, expect } from 'vitest';
import { definePlugin } from '../index';
import { createApp } from 'vue';

describe('vue', () => {
describe('definePlugin()', () => {
it('should create a new vue plugin', () => {
const Plugin = definePlugin(() => {});

expect(Plugin).toHaveProperty('install');
expect(Plugin.install).toBeInstanceOf(Function);
});

it('should be installable', () => {
const app = createApp({});
const Inkline = definePlugin(() => {});

expect(() => app.use(Inkline)).not.toThrow();
});

it('should pass plugin options', () => {
const pluginOptions = { color: 'light' };
const app = createApp({});
const Inkline = definePlugin((options) => {
expect(options).toEqual(pluginOptions);
});

app.use(Inkline, pluginOptions);
});

it('should provide data to children', () => {
const provideSymbol = Symbol('provided');
const provideData = { color: 'light' };

const app = createApp({});
const Inkline = definePlugin((options, { provide }) => {
provide(provideSymbol, provideData);
});

app.use(Inkline);

expect(app.config.globalProperties).toHaveProperty(`$${provideSymbol.description}`, provideData);
});
});
});
26 changes: 26 additions & 0 deletions packages/vue/src/definePlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { DefineVuePluginFn } from './types';

export const definePlugin: DefineVuePluginFn = (setup) => ({
install (app, options) {
/**
* Register components provided through options globally
*/

for (const componentIndex in options?.components) {
if (options.components[componentIndex].name) {
app.component(options.components[componentIndex].name, options.components[componentIndex]);
}
}

/**
* Setup the plugin
*/

setup(options, {
provide: (identifier, data) => {
app.config.globalProperties[`$${typeof identifier === 'symbol' ? identifier.description : identifier}`] = data;
app.provide(identifier, data);
}
});
}
});
1 change: 1 addition & 0 deletions packages/vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './computed';
export * from './defineComponent';
export * from './definePlugin';
export * from './events';
export * from './h';
export * from './provide';
Expand Down
12 changes: 12 additions & 0 deletions packages/vue/src/types-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ export interface InjectFn<T = any> {
(identifier: string | symbol, defaultValue?: T | (() => T)): T | undefined
}

/**
* Plugin types
*/

export interface DefinePluginContext {
provide: ProvideFn;
}

export interface DefinePluginFn<Plugin, Options = any> {
(setup: (options: Options, context: DefinePluginContext) => void): Plugin;
}

/**
* Storybook types
*/
Expand Down
6 changes: 4 additions & 2 deletions packages/vue/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DefineComponentFn } from './types-common';
import { VNode } from 'vue';
import { DefineComponentFn, DefinePluginFn } from './types-common';
import { Plugin, VNode } from 'vue';
import { Component } from '@vue/runtime-core';

export * from './types-common';
Expand All @@ -10,3 +10,5 @@ export type DefineVueComponentFn<
State = Record<string, any>,
Props = Record<string, any>
> = DefineComponentFn<State, Props, VNode, Component>

export type DefineVuePluginFn<Options = any> = DefinePluginFn<Plugin, Options & { components?: Record<string, any> }>;

0 comments on commit 0826a51

Please sign in to comment.