Skip to content

Commit 1cd5b2e

Browse files
authored
Make API type safe (#15)
1 parent 23bb086 commit 1cd5b2e

33 files changed

+268
-389
lines changed

.prettierrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"printWidth": 89,
23
"singleQuote": true,
34
"trailingComma": "all"
45
}

flowdef/README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

flowdef/index.js.flow

Lines changed: 0 additions & 80 deletions
This file was deleted.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-plugin",
3-
"version": "1.0.0-alpha.17",
3+
"version": "2.0.0-alpha.1",
44
"description": "API for composable 3rd party React plugins",
55
"repository": "https://github.com/skidding/react-plugin.git",
66
"author": "Ovidiu Cherecheș <[email protected]>",
@@ -14,14 +14,14 @@
1414
"lint": "tslint --project tsconfig.json",
1515
"test": "jest --coverage",
1616
"test:watch": "jest --watch",
17-
"build": "rm -rf dist && yarn lint && yarn tsc -b tsconfig.build.json && cp flowdef/index.js.flow dist"
17+
"build": "rm -rf dist && yarn lint && yarn tsc -b tsconfig.build.json"
1818
},
1919
"dependencies": {
2020
"@skidding/linked-list": "^1.0.2",
2121
"array-find-index": "^1.0.2",
2222
"lodash": "^4.17.11",
2323
"react-is": "^16.6.3",
24-
"ui-plugin": "^1.0.0-alpha.24"
24+
"ui-plugin": "^2.0.0-alpha.1"
2525
},
2626
"devDependencies": {
2727
"@skidding/async-retry": "^1.0.2",

src/@types/@skidding/async-retry.d.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
declare module '@skidding/async-retry' {
2-
interface IOptions {
2+
type Options = {
33
timeout?: number;
44
loopDelay?: number;
5-
}
5+
};
66

7-
export default function retry(
8-
cb: () => unknown,
9-
opts?: IOptions,
10-
): Promise<void>;
7+
export default function retry(cb: () => unknown, opts?: Options): Promise<void>;
118
}

src/@types/@skidding/linked-list.d.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,5 @@ declare module '@skidding/linked-list' {
44
next: () => LinkedItem<Item>;
55
};
66

7-
export default function createLinkedList<Item>(
8-
items: Item[],
9-
): LinkedItem<Item>;
7+
export default function createLinkedList<Item>(items: Item[]): LinkedItem<Item>;
108
}

src/PluginsConsumer.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
import { isEqual } from 'lodash';
22
import * as React from 'react';
3-
import { enablePlugin, getPlugins, IPlugin, onPluginChange } from 'ui-plugin';
3+
import { enablePlugin, getPlugins, Plugin, onPluginLoad } from 'ui-plugin';
44

5-
interface IProps {
5+
type Props = {
66
children: (
77
props: {
8-
plugins: IPlugin[];
8+
plugins: Plugin[];
99
enable: (pluginName: string, enabled: boolean) => void;
1010
},
1111
) => React.ReactNode;
12-
}
12+
};
1313

14-
interface IState {
15-
plugins: IPlugin[];
16-
}
14+
type State = {
15+
plugins: Plugin[];
16+
};
1717

18-
export class PluginsConsumer extends React.Component<IProps, IState> {
18+
export class PluginsConsumer extends React.Component<Props, State> {
1919
state = {
2020
plugins: getPluginArray(),
2121
};
2222

23-
removePluginChangeHandler: null | (() => unknown) = null;
23+
removePluginLoadHandler: null | (() => unknown) = null;
2424

2525
render() {
2626
const { children } = this.props;
@@ -33,17 +33,17 @@ export class PluginsConsumer extends React.Component<IProps, IState> {
3333
}
3434

3535
componentDidMount() {
36-
this.removePluginChangeHandler = onPluginChange(this.handlePluginChange);
36+
this.removePluginLoadHandler = onPluginLoad(this.handlePluginLoad);
3737
}
3838

3939
componentWillUnmount() {
40-
if (this.removePluginChangeHandler) {
41-
this.removePluginChangeHandler();
42-
this.removePluginChangeHandler = null;
40+
if (this.removePluginLoadHandler) {
41+
this.removePluginLoadHandler();
42+
this.removePluginLoadHandler = null;
4343
}
4444
}
4545

46-
handlePluginChange = () => {
46+
handlePluginLoad = () => {
4747
const newPlugins = getPluginArray();
4848

4949
if (!isEqual(newPlugins, this.state.plugins)) {

src/Slot/PlugConnect.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import { isEqual } from 'lodash';
22
import * as React from 'react';
3-
import { getPluginContext, isPluginLoaded, onStateChange } from 'ui-plugin';
4-
import { GetProps } from '../shared';
3+
import { getPlugin, getPluginContext, onStateChange } from 'ui-plugin';
4+
import { GetProps } from '../types';
55

6-
interface IProps {
6+
type Props = {
77
pluginName: string;
88
component: React.ComponentType;
99
slotProps: object;
1010
getProps: GetProps;
1111
children?: React.ReactNode;
12-
}
12+
};
1313

14-
interface IState {
14+
type State = {
1515
plugProps: object;
16-
}
16+
};
1717

18-
export class PlugConnect extends React.Component<IProps, IState> {
19-
static getDerivedStateFromProps(props: IProps, state: IState) {
18+
export class PlugConnect extends React.Component<Props, State> {
19+
static getDerivedStateFromProps(props: Props, state: State) {
2020
const plugProps = getPlugProps(props);
2121

2222
if (plugPropsEqual(plugProps, state.plugProps)) {
@@ -57,7 +57,7 @@ export class PlugConnect extends React.Component<IProps, IState> {
5757
// rendering is async, it takes a while for the Slot components to process
5858
// plugin changes, so PlugConnect components might receive state changes
5959
// for plugins that are no longer enabled.
60-
if (!isPluginLoaded(this.props.pluginName)) {
60+
if (!getPlugin(this.props.pluginName).enabled) {
6161
return;
6262
}
6363

@@ -77,7 +77,7 @@ export class PlugConnect extends React.Component<IProps, IState> {
7777
}
7878
}
7979

80-
function getPlugProps({ pluginName, slotProps, getProps }: IProps) {
80+
function getPlugProps({ pluginName, slotProps, getProps }: Props) {
8181
return getProps(getPluginContext(pluginName), slotProps);
8282
}
8383

src/Slot/contexts.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import { LinkedItem } from '@skidding/linked-list';
22
import * as React from 'react';
3-
import { IPlug } from '../shared';
3+
import { Plug } from '../types';
44

5-
type SlotContextValue = undefined | LinkedItem<IPlug>;
5+
type SlotContextValue = undefined | LinkedItem<Plug>;
66

7-
interface ISlotContexts {
7+
type SlotContexts = {
88
[slotName: string]: React.Context<SlotContextValue>;
9-
}
9+
};
1010

1111
// Slots are nested, so higher-level Slots can contain lower-level Slots.
1212
// Multiple Plugs can be consumed by the same Slot, and the reference to the
1313
// current Plug is is passed down through the Slot context. A different context
1414
// is created for each Slot name to prevent Slots that contain other Slots from
1515
// interfering with each other’s Plug references.
16-
const slotContexts: ISlotContexts = {};
16+
const slotContexts: SlotContexts = {};
1717

1818
export function getSlotContext(slotName: string) {
1919
if (!slotContexts[slotName]) {

src/Slot/index.tsx

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@ import createLinkedList from '@skidding/linked-list';
22
import { isEqual } from 'lodash';
33
import * as React from 'react';
44
import { isValidElementType } from 'react-is';
5-
import { onPluginChange } from 'ui-plugin';
6-
import { getLoadedPlugsForSlot } from '../pluginStore';
7-
import { IPlug } from '../shared';
5+
import { onPluginLoad } from 'ui-plugin';
6+
import { Plug } from '../types';
7+
import { getEnabledPlugsForSlot } from '../store';
88
import { getSlotContext } from './contexts';
99
import { PlugConnect } from './PlugConnect';
1010

11-
interface IProps {
11+
type Props = {
1212
name: string;
1313
children?: React.ReactNode;
1414
props?: object;
15-
}
15+
};
1616

17-
interface IState {
18-
plugs: IPlug[];
19-
}
17+
type State = {
18+
plugs: Plug[];
19+
};
2020

21-
export class Slot extends React.Component<IProps, IState> {
21+
export class Slot extends React.Component<Props, State> {
2222
state = {
23-
plugs: getLoadedPlugsForSlot(this.props.name),
23+
plugs: getEnabledPlugsForSlot(this.props.name),
2424
};
2525

26-
removePluginChangeHandler: null | (() => unknown) = null;
26+
removePluginLoadHandler: null | (() => unknown) = null;
2727

2828
render() {
2929
const { name, children, props = {} } = this.props;
@@ -52,40 +52,34 @@ export class Slot extends React.Component<IProps, IState> {
5252
}
5353

5454
return (
55-
<Provider value={next()}>
56-
{getPlugNode(plug, props, children)}
57-
</Provider>
55+
<Provider value={next()}>{getPlugNode(plug, props, children)}</Provider>
5856
);
5957
}}
6058
</Consumer>
6159
);
6260
}
6361

6462
componentDidMount() {
65-
this.removePluginChangeHandler = onPluginChange(this.handlePluginChange);
63+
this.removePluginLoadHandler = onPluginLoad(this.handlePluginLoad);
6664
}
6765

6866
componentWillUnmount() {
69-
if (this.removePluginChangeHandler) {
70-
this.removePluginChangeHandler();
71-
this.removePluginChangeHandler = null;
67+
if (this.removePluginLoadHandler) {
68+
this.removePluginLoadHandler();
69+
this.removePluginLoadHandler = null;
7270
}
7371
}
7472

75-
handlePluginChange = () => {
76-
const newPlugs = getLoadedPlugsForSlot(this.props.name);
73+
handlePluginLoad = () => {
74+
const newPlugs = getEnabledPlugsForSlot(this.props.name);
7775

7876
if (!isEqual(newPlugs, this.state.plugs)) {
7977
this.setState({ plugs: newPlugs });
8078
}
8179
};
8280
}
8381

84-
function getPlugNode(
85-
plug: IPlug,
86-
slotProps: object,
87-
children?: React.ReactNode,
88-
) {
82+
function getPlugNode(plug: Plug, slotProps: object, children?: React.ReactNode) {
8983
const { pluginName, render, getProps } = plug;
9084

9185
if (typeof render === 'string' || !isValidElementType(render)) {
@@ -108,7 +102,7 @@ function getPlugNode(
108102
return React.createElement(render, slotProps, children);
109103
}
110104

111-
function getFirstLinkedPlug(plugs: IPlug[]) {
105+
function getFirstLinkedPlug(plugs: Plug[]) {
112106
// Plugs are traversed in the order they're applied. But this doesn't mean
113107
// top-down from a component hierarchy point of view. The traversal of the
114108
// plugs can go up and down the component hierachy repeatedly, based on the

0 commit comments

Comments
 (0)