@modular-component/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/LICENSE +13 -0
- package/README.md +34 -0
- package/dist/index.d.ts +144 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +35 -0
- package/src/index.ts +131 -0
- package/src/types.ts +272 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright © Jérémie van der Sande
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
4
|
+
documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
|
|
5
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
6
|
+
persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
+
|
|
10
|
+
The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the
|
|
11
|
+
warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or
|
|
12
|
+
copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise,
|
|
13
|
+
arising from, out of or in connection with the software or the use or other dealings in the Software.
|
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# `@modular-component/core`
|
|
2
|
+
|
|
3
|
+
Core system for creating a `ModularComponent` factory. Exports the `modularFactory`
|
|
4
|
+
builder, and necessary types for creating extensions.
|
|
5
|
+
|
|
6
|
+
## Installation and usage
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
yarn add @modular-component/core
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
// Usage in apps
|
|
14
|
+
import { modularFactory } from '@modular-component/core'
|
|
15
|
+
|
|
16
|
+
const ModularComponent = modularFactory.build()
|
|
17
|
+
|
|
18
|
+
const MyComponent = ModularComponent().withRender(() => (
|
|
19
|
+
<div>Hello Modular!</div>
|
|
20
|
+
))
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
// Usage in extensions
|
|
25
|
+
import { createMethodRecord } from '@modular-component/core'
|
|
26
|
+
|
|
27
|
+
export const WithExtension = createMethodRecord({
|
|
28
|
+
field: 'extension',
|
|
29
|
+
} as const)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Learn more
|
|
33
|
+
|
|
34
|
+
Read the [`ModularComponent` ReadMe](https://github.com/jvdsande/modular-component/blob/master/README.md) for more information about the `ModularComponent` system.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { MethodRecord, Modular, StageEntry } from './types';
|
|
3
|
+
export type { Modular, ModularStageTransform, MethodRecord } from './types';
|
|
4
|
+
export declare const modularFactory: {
|
|
5
|
+
build: <Stages extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props = {}>(displayName?: string) => Modular<Props, {
|
|
6
|
+
readonly withRender: {
|
|
7
|
+
readonly field: "render";
|
|
8
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
9
|
+
};
|
|
10
|
+
}, Stages>;
|
|
11
|
+
extend: <_Methods extends MethodRecord>(_methods: _Methods) => {
|
|
12
|
+
build: <Stages_1 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_1 = {}>(displayName?: string) => Modular<Props_1, {
|
|
13
|
+
readonly withRender: {
|
|
14
|
+
readonly field: "render";
|
|
15
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
16
|
+
};
|
|
17
|
+
} & _Methods extends infer T ? T extends {
|
|
18
|
+
readonly withRender: {
|
|
19
|
+
readonly field: "render";
|
|
20
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
21
|
+
};
|
|
22
|
+
} & _Methods ? T extends infer U ? { [key in keyof U]: U[key]; } : never : never : never, Stages_1>;
|
|
23
|
+
extend: <_Methods_1 extends MethodRecord>(_methods: _Methods_1) => {
|
|
24
|
+
build: <Stages_2 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_2 = {}>(displayName?: string) => Modular<Props_2, {
|
|
25
|
+
readonly withRender: {
|
|
26
|
+
readonly field: "render";
|
|
27
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
28
|
+
};
|
|
29
|
+
} & _Methods & _Methods_1 extends infer T_1 ? T_1 extends {
|
|
30
|
+
readonly withRender: {
|
|
31
|
+
readonly field: "render";
|
|
32
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
33
|
+
};
|
|
34
|
+
} & _Methods & _Methods_1 ? T_1 extends infer U ? { [key_1 in keyof U]: U[key_1]; } : never : never : never, Stages_2>;
|
|
35
|
+
extend: <_Methods_2 extends MethodRecord>(_methods: _Methods_2) => {
|
|
36
|
+
build: <Stages_3 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_3 = {}>(displayName?: string) => Modular<Props_3, {
|
|
37
|
+
readonly withRender: {
|
|
38
|
+
readonly field: "render";
|
|
39
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
40
|
+
};
|
|
41
|
+
} & _Methods & _Methods_1 & _Methods_2 extends infer T_2 ? T_2 extends {
|
|
42
|
+
readonly withRender: {
|
|
43
|
+
readonly field: "render";
|
|
44
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
45
|
+
};
|
|
46
|
+
} & _Methods & _Methods_1 & _Methods_2 ? T_2 extends infer U ? { [key_2 in keyof U]: U[key_2]; } : never : never : never, Stages_3>;
|
|
47
|
+
extend: <_Methods_3 extends MethodRecord>(_methods: _Methods_3) => {
|
|
48
|
+
build: <Stages_4 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_4 = {}>(displayName?: string) => Modular<Props_4, {
|
|
49
|
+
readonly withRender: {
|
|
50
|
+
readonly field: "render";
|
|
51
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
52
|
+
};
|
|
53
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 extends infer T_3 ? T_3 extends {
|
|
54
|
+
readonly withRender: {
|
|
55
|
+
readonly field: "render";
|
|
56
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
57
|
+
};
|
|
58
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 ? T_3 extends infer U ? { [key_3 in keyof U]: U[key_3]; } : never : never : never, Stages_4>;
|
|
59
|
+
extend: <_Methods_4 extends MethodRecord>(_methods: _Methods_4) => {
|
|
60
|
+
build: <Stages_5 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_5 = {}>(displayName?: string) => Modular<Props_5, {
|
|
61
|
+
readonly withRender: {
|
|
62
|
+
readonly field: "render";
|
|
63
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
64
|
+
};
|
|
65
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 extends infer T_4 ? T_4 extends {
|
|
66
|
+
readonly withRender: {
|
|
67
|
+
readonly field: "render";
|
|
68
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
69
|
+
};
|
|
70
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 ? T_4 extends infer U ? { [key_4 in keyof U]: U[key_4]; } : never : never : never, Stages_5>;
|
|
71
|
+
extend: <_Methods_5 extends MethodRecord>(_methods: _Methods_5) => {
|
|
72
|
+
build: <Stages_6 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_6 = {}>(displayName?: string) => Modular<Props_6, {
|
|
73
|
+
readonly withRender: {
|
|
74
|
+
readonly field: "render";
|
|
75
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
76
|
+
};
|
|
77
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 extends infer T_5 ? T_5 extends {
|
|
78
|
+
readonly withRender: {
|
|
79
|
+
readonly field: "render";
|
|
80
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
81
|
+
};
|
|
82
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 ? T_5 extends infer U ? { [key_5 in keyof U]: U[key_5]; } : never : never : never, Stages_6>;
|
|
83
|
+
extend: <_Methods_6 extends MethodRecord>(_methods: _Methods_6) => {
|
|
84
|
+
build: <Stages_7 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_7 = {}>(displayName?: string) => Modular<Props_7, {
|
|
85
|
+
readonly withRender: {
|
|
86
|
+
readonly field: "render";
|
|
87
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
88
|
+
};
|
|
89
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 & _Methods_6 extends infer T_6 ? T_6 extends {
|
|
90
|
+
readonly withRender: {
|
|
91
|
+
readonly field: "render";
|
|
92
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
93
|
+
};
|
|
94
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 & _Methods_6 ? T_6 extends infer U ? { [key_6 in keyof U]: U[key_6]; } : never : never : never, Stages_7>;
|
|
95
|
+
extend: <_Methods_7 extends MethodRecord>(_methods: _Methods_7) => {
|
|
96
|
+
build: <Stages_8 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_8 = {}>(displayName?: string) => Modular<Props_8, {
|
|
97
|
+
readonly withRender: {
|
|
98
|
+
readonly field: "render";
|
|
99
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
100
|
+
};
|
|
101
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 & _Methods_6 & _Methods_7 extends infer T_7 ? T_7 extends {
|
|
102
|
+
readonly withRender: {
|
|
103
|
+
readonly field: "render";
|
|
104
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
105
|
+
};
|
|
106
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 & _Methods_6 & _Methods_7 ? T_7 extends infer U ? { [key_7 in keyof U]: U[key_7]; } : never : never : never, Stages_8>;
|
|
107
|
+
extend: <_Methods_8 extends MethodRecord>(_methods: _Methods_8) => {
|
|
108
|
+
build: <Stages_9 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_9 = {}>(displayName?: string) => Modular<Props_9, {
|
|
109
|
+
readonly withRender: {
|
|
110
|
+
readonly field: "render";
|
|
111
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
112
|
+
};
|
|
113
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 & _Methods_6 & _Methods_7 & _Methods_8 extends infer T_8 ? T_8 extends {
|
|
114
|
+
readonly withRender: {
|
|
115
|
+
readonly field: "render";
|
|
116
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
117
|
+
};
|
|
118
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 & _Methods_6 & _Methods_7 & _Methods_8 ? T_8 extends infer U ? { [key_8 in keyof U]: U[key_8]; } : never : never : never, Stages_9>;
|
|
119
|
+
extend: <_Methods_9 extends MethodRecord>(_methods: _Methods_9) => {
|
|
120
|
+
build: <Stages_10 extends StageEntry[] = []>(stages?: Omit<StageEntry, 'stages'>[]) => <Props_10 = {}>(displayName?: string) => Modular<Props_10, {
|
|
121
|
+
readonly withRender: {
|
|
122
|
+
readonly field: "render";
|
|
123
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
124
|
+
};
|
|
125
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 & _Methods_6 & _Methods_7 & _Methods_8 & _Methods_9 extends infer T_9 ? T_9 extends {
|
|
126
|
+
readonly withRender: {
|
|
127
|
+
readonly field: "render";
|
|
128
|
+
readonly restrict: import("react").ReactElement<any, any> | null;
|
|
129
|
+
};
|
|
130
|
+
} & _Methods & _Methods_1 & _Methods_2 & _Methods_3 & _Methods_4 & _Methods_5 & _Methods_6 & _Methods_7 & _Methods_8 & _Methods_9 ? T_9 extends infer U ? { [key_9 in keyof U]: U[key_9]; } : never : never : never, Stages_10>;
|
|
131
|
+
extend: <_Methods_10 extends MethodRecord>(_methods: _Methods_10) => any;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
export declare function createMethodRecord<R extends MethodRecord>(record: R): R;
|
|
144
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAc,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAGvE,YAAY,EAAE,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAsH3E,eAAO,MAAM,cAAc;uDA7Gb,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,gCAEF,MAAM;;;;;;;6DAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;iEAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;qEAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;yEAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;6EAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;iFAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;qFAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;yFAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;6FAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,kCAEF,MAAM;;;;;;;;;;;;kGAFhC,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,mCAEF,MAAM;;;;;;;;;;;;;;;;;;;;;;CAgHnC,CAAA;AAEX,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAEvE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
function ModularFactory(methods) {
|
|
2
|
+
return {
|
|
3
|
+
build: (stages = []) => {
|
|
4
|
+
return (displayName) => {
|
|
5
|
+
// Create the actual Component. This is a simple React Functional Component
|
|
6
|
+
// that will call the hooks for each registered stages in order.
|
|
7
|
+
const Component = ((props) => {
|
|
8
|
+
// Prepare the shared arguments object, prefilling it with the props
|
|
9
|
+
// and an empty render result
|
|
10
|
+
const useComponent = Component.asHook();
|
|
11
|
+
const args = useComponent(props);
|
|
12
|
+
return args.render ?? null;
|
|
13
|
+
});
|
|
14
|
+
// Set the debug display name if provided
|
|
15
|
+
Component.displayName = displayName;
|
|
16
|
+
// Add an asHook system to get the components args as a reusable hook
|
|
17
|
+
Component.asHook = ((field) => (props) => {
|
|
18
|
+
// Prepare the shared arguments object, prefilling it with the props
|
|
19
|
+
// and an empty render result
|
|
20
|
+
let args = { props, render: null };
|
|
21
|
+
// Run each stage in order, replacing the arguments by the response
|
|
22
|
+
// from the last stage
|
|
23
|
+
for (const stage of stages) {
|
|
24
|
+
const method = methods[stage.key];
|
|
25
|
+
const useStage = stage.value;
|
|
26
|
+
const useTransform = method.transform ??
|
|
27
|
+
(() => typeof useStage === 'function'
|
|
28
|
+
? useStage({ ...args })
|
|
29
|
+
: useStage);
|
|
30
|
+
args = {
|
|
31
|
+
...args,
|
|
32
|
+
[method.field]: useTransform(args, useStage),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// Finally, return the args
|
|
36
|
+
return field ? args[field] : args;
|
|
37
|
+
});
|
|
38
|
+
// Add a function for rewinding the component up to a certain stage
|
|
39
|
+
Component.atStage = ((stage) => {
|
|
40
|
+
// Find the needed stage
|
|
41
|
+
const stageIndex = stages.findIndex((record) => record.key === stage);
|
|
42
|
+
// If the stage cannot be found, create a brand new, empty component
|
|
43
|
+
if (stageIndex === -1) {
|
|
44
|
+
return ModularFactory(methods).build()(displayName);
|
|
45
|
+
}
|
|
46
|
+
// Otherwise, keep all stages up to and including the found stage
|
|
47
|
+
return ModularFactory(methods).build(stages.slice(0, stageIndex + 1))(displayName);
|
|
48
|
+
});
|
|
49
|
+
// Add each configured stage method to the component
|
|
50
|
+
Object.keys(methods).forEach((method) => {
|
|
51
|
+
Component[method] = ((value) => {
|
|
52
|
+
// Prepare the new stage
|
|
53
|
+
const stage = { key: method, value };
|
|
54
|
+
// For stages in "multiple" mode, simply append the stage
|
|
55
|
+
if (methods[method].multiple) {
|
|
56
|
+
return ModularFactory(methods).build([...stages, stage])(displayName);
|
|
57
|
+
}
|
|
58
|
+
// For other stages, check if a stage of the same key already exists
|
|
59
|
+
const index = stages.findIndex((st) => st.key === method);
|
|
60
|
+
// If so, copy the stages and replace the previous record
|
|
61
|
+
if (index > -1) {
|
|
62
|
+
const nextStages = [...stages];
|
|
63
|
+
nextStages[index] = stage;
|
|
64
|
+
return ModularFactory(methods).build(nextStages)(displayName);
|
|
65
|
+
}
|
|
66
|
+
// Otherwise, append the stage as in multiple mode
|
|
67
|
+
return ModularFactory(methods).build([...stages, stage])(displayName);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return Component;
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
extend: (_methods) => {
|
|
74
|
+
return ModularFactory({
|
|
75
|
+
...methods,
|
|
76
|
+
..._methods,
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export const modularFactory = ModularFactory({
|
|
82
|
+
withRender: {
|
|
83
|
+
field: 'render',
|
|
84
|
+
restrict: {},
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
export function createMethodRecord(record) {
|
|
88
|
+
return record;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { FunctionComponent } from 'react';
|
|
2
|
+
declare type UnionToIntersection<U> = [U] extends [never] ? never : (U extends infer V ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
3
|
+
export declare type StageEntry = {
|
|
4
|
+
key: MethodName;
|
|
5
|
+
value: unknown;
|
|
6
|
+
stages: string;
|
|
7
|
+
};
|
|
8
|
+
declare type StageList = StageEntry[];
|
|
9
|
+
export declare type MethodName = `with${Capitalize<string>}`;
|
|
10
|
+
export declare type MethodEntry = {
|
|
11
|
+
field: string;
|
|
12
|
+
transform?: (args: any, value: any) => any;
|
|
13
|
+
restrict?: unknown;
|
|
14
|
+
multiple?: boolean;
|
|
15
|
+
empty?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare type MethodRecord = Record<MethodName, MethodEntry>;
|
|
18
|
+
declare type AppendStage<List extends StageList, Stage extends MethodName, Value extends unknown, Prev extends StageEntry = GetStage<List, Stage>> = [
|
|
19
|
+
...List,
|
|
20
|
+
{
|
|
21
|
+
key: Stage;
|
|
22
|
+
value: Value;
|
|
23
|
+
stages: [Prev] extends [never] ? List[number]['key'] : Prev['stages'];
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
declare type DropStages<List extends StageList, Dropped extends string> = {
|
|
27
|
+
[Index in keyof List]: List[Index]['key'] extends Dropped ? never : List[Index];
|
|
28
|
+
};
|
|
29
|
+
declare type KeepStages<List extends StageList, Allowed extends string> = {
|
|
30
|
+
[Index in keyof List]: List[Index]['key'] extends Allowed ? List[Index] : never;
|
|
31
|
+
};
|
|
32
|
+
declare type GetStage<List extends StageList, Key extends MethodName, Union = List[number]> = Union extends {
|
|
33
|
+
key: Key;
|
|
34
|
+
value: infer U;
|
|
35
|
+
stages: infer S;
|
|
36
|
+
} ? {
|
|
37
|
+
key: Key;
|
|
38
|
+
value: U;
|
|
39
|
+
stages: S;
|
|
40
|
+
} : never;
|
|
41
|
+
declare type GetStageValue<List extends StageList, Key extends MethodName> = UnionToIntersection<GetStage<List, Key>['value']>;
|
|
42
|
+
declare type ComputeArgs<Stages extends StageList, Limit extends string, Union = Stages[number], Intersection = UnionToIntersection<Union extends {
|
|
43
|
+
key: infer Key;
|
|
44
|
+
value: infer Value;
|
|
45
|
+
} ? {
|
|
46
|
+
[key in Key extends string ? Key : never]: Value;
|
|
47
|
+
} : never>> = Pick<Intersection, Limit extends keyof Intersection ? Limit : never> extends infer U ? {
|
|
48
|
+
[key in keyof U]: U[key] extends Record<string, unknown> ? U[key] extends infer V ? {
|
|
49
|
+
[key in keyof V]: V[key];
|
|
50
|
+
} : never : U[key];
|
|
51
|
+
} : never;
|
|
52
|
+
declare type TransformArg<Value, Key> = Key extends keyof ModularStageTransform<Value> ? ModularStageTransform<Value>[Key] : Value;
|
|
53
|
+
declare type MapArgs<Stages extends StageList, Limit extends string, Methods extends MethodRecord, Props, Args = ComputeArgs<Stages, Limit>> = UnionToIntersection<{
|
|
54
|
+
props: Props;
|
|
55
|
+
} | {
|
|
56
|
+
[key in keyof Methods]: key extends keyof Args ? Methods[key] extends MethodEntry ? {
|
|
57
|
+
[k in Methods[key]['field']]: TransformArg<Args[key], key>;
|
|
58
|
+
} : never : never;
|
|
59
|
+
}[keyof Methods]> extends infer U ? {
|
|
60
|
+
[key in keyof U]: U[key] extends Record<string, unknown> ? U[key] extends infer V ? {
|
|
61
|
+
[key in keyof V]: V[key];
|
|
62
|
+
} : never : U[key];
|
|
63
|
+
} : never;
|
|
64
|
+
declare type ModularExtension<Props, Methods extends MethodRecord, Stages extends StageList> = {
|
|
65
|
+
[key in keyof Methods]: (Methods[key] extends MethodEntry ? Methods[key] : never)['restrict'] extends undefined ? <Key extends key extends MethodName ? key : never, Method extends Methods[Key] extends MethodEntry ? Methods[Key] : never, Prev extends Method['multiple'] extends true ? never : GetStageValue<Stages, Key>, Limit extends Method['multiple'] extends true ? Stages[number]['key'] : [GetStage<Stages, Key>] extends [never] ? Stages[number]['key'] : GetStage<Stages, Key>['stages'], KeptStages extends Method['multiple'] extends true ? DropStages<Stages, Key> : Stages, Value extends [Prev] extends [never] ? [Method['restrict']] extends [never] ? unknown : Method['restrict'] : Prev>(value?: Value | ((args: MapArgs<Stages, Limit, Methods, Props>) => Value | void)) => Modular<Props, Methods, AppendStage<KeptStages, Key, Value>> : <Key extends key extends MethodName ? key : never, Method extends Methods[Key] extends MethodEntry ? Methods[Key] : never, Prev extends Method['multiple'] extends true ? never : GetStageValue<Stages, Key>, Limit extends Method['multiple'] extends true ? Stages[number]['key'] : [GetStage<Stages, Key>] extends [never] ? Stages[number]['key'] : GetStage<Stages, Key>['stages'], KeptStages extends Method['multiple'] extends true ? DropStages<Stages, Key> : Stages, Value extends [Prev] extends [never] ? [Method['restrict']] extends [never] ? unknown : Method['restrict'] : Prev>(value: Value | ((args: MapArgs<Stages, Limit, Methods, Props>) => Value)) => Modular<Props, Methods, AppendStage<KeptStages, Key, Value>>;
|
|
66
|
+
} & {
|
|
67
|
+
atStage<Key extends Stages[number]['key'], KeptStages extends KeepStages<Stages, GetStage<Stages, Key>['stages'] | Key>>(stage: Key): Modular<Props, Methods, KeptStages>;
|
|
68
|
+
asHook(): Props extends {} ? () => MapArgs<Stages, Stages[number]['key'], Methods, Props> : (props: Props) => MapArgs<Stages, Stages[number]['key'], Methods, Props>;
|
|
69
|
+
asHook<Field extends keyof MapArgs<Stages, Stages[number]['key'], Methods, Props>>(field: Field): Props extends {} ? () => MapArgs<Stages, Stages[number]['key'], Methods, Props>[Field] : (props: Props) => MapArgs<Stages, Stages[number]['key'], Methods, Props>[Field];
|
|
70
|
+
};
|
|
71
|
+
export declare type Modular<Props, Methods extends MethodRecord, Stages extends StageList> = FunctionComponent<Props> & ModularExtension<Props, Methods, Stages>;
|
|
72
|
+
export interface ModularStageTransform<T> {
|
|
73
|
+
}
|
|
74
|
+
export {};
|
|
75
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@modular-component/core",
|
|
3
|
+
"description": "Delightfully organized and deeply testable React Components",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"React",
|
|
6
|
+
"Modular",
|
|
7
|
+
"Factory",
|
|
8
|
+
"Test"
|
|
9
|
+
],
|
|
10
|
+
"version": "0.1.0",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"src",
|
|
18
|
+
"dist",
|
|
19
|
+
"CHANGELOG.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "yarn build:self",
|
|
23
|
+
"build:self": "tsc",
|
|
24
|
+
"license": "cp ../../LICENSE ./LICENSE"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"react": ">=17 <19"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/react": "^18.0.17",
|
|
31
|
+
"typescript": "^4.6.4"
|
|
32
|
+
},
|
|
33
|
+
"main": "dist/index.js",
|
|
34
|
+
"types": "dist/index.d.ts"
|
|
35
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { MethodName, MethodRecord, Modular, StageEntry } from './types'
|
|
2
|
+
import { FunctionComponent } from 'react'
|
|
3
|
+
|
|
4
|
+
export type { Modular, ModularStageTransform, MethodRecord } from './types'
|
|
5
|
+
|
|
6
|
+
function ModularFactory<Methods extends MethodRecord>(methods: Methods) {
|
|
7
|
+
type CleanMethods = Methods extends infer U
|
|
8
|
+
? { [key in keyof U]: U[key] }
|
|
9
|
+
: never
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
build: <Stages extends StageEntry[] = []>(
|
|
13
|
+
stages: Omit<StageEntry, 'stages'>[] = [],
|
|
14
|
+
) => {
|
|
15
|
+
return <Props = {}>(displayName?: string) => {
|
|
16
|
+
// Create the actual Component. This is a simple React Functional Component
|
|
17
|
+
// that will call the hooks for each registered stages in order.
|
|
18
|
+
const Component = ((props) => {
|
|
19
|
+
// Prepare the shared arguments object, prefilling it with the props
|
|
20
|
+
// and an empty render result
|
|
21
|
+
const useComponent = Component.asHook()
|
|
22
|
+
const args = useComponent(props)
|
|
23
|
+
|
|
24
|
+
return (args as unknown as { render: null }).render ?? null
|
|
25
|
+
}) as Modular<Props, CleanMethods, Stages>
|
|
26
|
+
|
|
27
|
+
// Set the debug display name if provided
|
|
28
|
+
Component.displayName = displayName
|
|
29
|
+
|
|
30
|
+
// Add an asHook system to get the components args as a reusable hook
|
|
31
|
+
Component.asHook = ((field: string) => (props: Props) => {
|
|
32
|
+
// Prepare the shared arguments object, prefilling it with the props
|
|
33
|
+
// and an empty render result
|
|
34
|
+
let args = { props, render: null }
|
|
35
|
+
|
|
36
|
+
// Run each stage in order, replacing the arguments by the response
|
|
37
|
+
// from the last stage
|
|
38
|
+
for (const stage of stages) {
|
|
39
|
+
const method = methods[stage.key as MethodName]
|
|
40
|
+
const useStage = stage.value
|
|
41
|
+
const useTransform =
|
|
42
|
+
method.transform ??
|
|
43
|
+
(() =>
|
|
44
|
+
typeof useStage === 'function'
|
|
45
|
+
? useStage({ ...args })
|
|
46
|
+
: useStage)
|
|
47
|
+
|
|
48
|
+
args = {
|
|
49
|
+
...args,
|
|
50
|
+
[method.field as keyof typeof args]: useTransform(args, useStage),
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Finally, return the args
|
|
55
|
+
return field ? args[field as keyof typeof args] : args
|
|
56
|
+
}) as unknown as Modular<Props, CleanMethods, Stages>['asHook']
|
|
57
|
+
|
|
58
|
+
// Add a function for rewinding the component up to a certain stage
|
|
59
|
+
Component.atStage = ((stage: MethodName) => {
|
|
60
|
+
// Find the needed stage
|
|
61
|
+
const stageIndex = stages.findIndex((record) => record.key === stage)
|
|
62
|
+
|
|
63
|
+
// If the stage cannot be found, create a brand new, empty component
|
|
64
|
+
if (stageIndex === -1) {
|
|
65
|
+
return ModularFactory<Methods>(methods).build()<Props>(displayName)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Otherwise, keep all stages up to and including the found stage
|
|
69
|
+
return ModularFactory<Methods>(methods).build(
|
|
70
|
+
stages.slice(0, stageIndex + 1),
|
|
71
|
+
)<Props>(displayName)
|
|
72
|
+
}) as unknown as Modular<Props, CleanMethods, Stages>['atStage']
|
|
73
|
+
|
|
74
|
+
// Add each configured stage method to the component
|
|
75
|
+
Object.keys(methods).forEach((method) => {
|
|
76
|
+
Component[method as keyof CleanMethods] = ((value: unknown) => {
|
|
77
|
+
// Prepare the new stage
|
|
78
|
+
const stage = { key: method as MethodName, value }
|
|
79
|
+
|
|
80
|
+
// For stages in "multiple" mode, simply append the stage
|
|
81
|
+
if (methods[method as MethodName].multiple) {
|
|
82
|
+
return ModularFactory(methods).build([...stages, stage])<Props>(
|
|
83
|
+
displayName,
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// For other stages, check if a stage of the same key already exists
|
|
88
|
+
const index = stages.findIndex((st) => st.key === method)
|
|
89
|
+
|
|
90
|
+
// If so, copy the stages and replace the previous record
|
|
91
|
+
if (index > -1) {
|
|
92
|
+
const nextStages = [...stages]
|
|
93
|
+
nextStages[index] = stage
|
|
94
|
+
return ModularFactory(methods).build(nextStages)<Props>(
|
|
95
|
+
displayName,
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Otherwise, append the stage as in multiple mode
|
|
100
|
+
return ModularFactory(methods).build([...stages, stage])<Props>(
|
|
101
|
+
displayName,
|
|
102
|
+
)
|
|
103
|
+
}) as unknown as Modular<
|
|
104
|
+
Props,
|
|
105
|
+
CleanMethods,
|
|
106
|
+
Stages
|
|
107
|
+
>[keyof CleanMethods]
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
return Component
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
extend: <_Methods extends MethodRecord>(_methods: _Methods) => {
|
|
114
|
+
return ModularFactory<Methods & _Methods>({
|
|
115
|
+
...methods,
|
|
116
|
+
..._methods,
|
|
117
|
+
})
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const modularFactory = ModularFactory({
|
|
123
|
+
withRender: {
|
|
124
|
+
field: 'render',
|
|
125
|
+
restrict: {} as ReturnType<FunctionComponent>,
|
|
126
|
+
},
|
|
127
|
+
} as const)
|
|
128
|
+
|
|
129
|
+
export function createMethodRecord<R extends MethodRecord>(record: R): R {
|
|
130
|
+
return record
|
|
131
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { FunctionComponent } from 'react'
|
|
2
|
+
|
|
3
|
+
// Collapse a union of similar object into the intersection of the various objects
|
|
4
|
+
type UnionToIntersection<U> = [U] extends [never]
|
|
5
|
+
? never
|
|
6
|
+
: (U extends infer V ? (k: U) => void : never) extends (k: infer I) => void
|
|
7
|
+
? I
|
|
8
|
+
: never
|
|
9
|
+
|
|
10
|
+
// Base types used for manipulating stages
|
|
11
|
+
export type StageEntry = { key: MethodName; value: unknown; stages: string }
|
|
12
|
+
type StageList = StageEntry[]
|
|
13
|
+
|
|
14
|
+
// Base type used for manipulating methods
|
|
15
|
+
export type MethodName = `with${Capitalize<string>}`
|
|
16
|
+
export type MethodEntry = {
|
|
17
|
+
field: string
|
|
18
|
+
transform?: (args: any, value: any) => any
|
|
19
|
+
restrict?: unknown
|
|
20
|
+
multiple?: boolean
|
|
21
|
+
empty?: boolean
|
|
22
|
+
}
|
|
23
|
+
export type MethodRecord = Record<MethodName, MethodEntry>
|
|
24
|
+
|
|
25
|
+
// Take a stage list, and append a new stage at the end
|
|
26
|
+
type AppendStage<
|
|
27
|
+
List extends StageList,
|
|
28
|
+
Stage extends MethodName,
|
|
29
|
+
Value extends unknown,
|
|
30
|
+
Prev extends StageEntry = GetStage<List, Stage>,
|
|
31
|
+
> = [
|
|
32
|
+
...List,
|
|
33
|
+
{
|
|
34
|
+
key: Stage
|
|
35
|
+
value: Value
|
|
36
|
+
stages: [Prev] extends [never] ? List[number]['key'] : Prev['stages']
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
// Take a stage list, and remove all stages matching a set of keys
|
|
41
|
+
type DropStages<List extends StageList, Dropped extends string> = {
|
|
42
|
+
[Index in keyof List]: List[Index]['key'] extends Dropped
|
|
43
|
+
? never
|
|
44
|
+
: List[Index]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Take a stage list, and keep only the stages matching a set of keys
|
|
48
|
+
type KeepStages<List extends StageList, Allowed extends string> = {
|
|
49
|
+
[Index in keyof List]: List[Index]['key'] extends Allowed
|
|
50
|
+
? List[Index]
|
|
51
|
+
: never
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Parse a stage list to extract all the stages matching a key
|
|
55
|
+
type GetStage<
|
|
56
|
+
List extends StageList,
|
|
57
|
+
Key extends MethodName,
|
|
58
|
+
Union = List[number],
|
|
59
|
+
> = Union extends { key: Key; value: infer U; stages: infer S }
|
|
60
|
+
? { key: Key; value: U; stages: S }
|
|
61
|
+
: never
|
|
62
|
+
|
|
63
|
+
// Parse a stage list to extract the collapsed value for a given stage key
|
|
64
|
+
type GetStageValue<
|
|
65
|
+
List extends StageList,
|
|
66
|
+
Key extends MethodName,
|
|
67
|
+
> = UnionToIntersection<GetStage<List, Key>['value']>
|
|
68
|
+
|
|
69
|
+
// Collapse a complete stage list into an argument object
|
|
70
|
+
// Use the deep `extends infer U` method to get a clean object in tooltips
|
|
71
|
+
type ComputeArgs<
|
|
72
|
+
Stages extends StageList,
|
|
73
|
+
Limit extends string,
|
|
74
|
+
Union = Stages[number],
|
|
75
|
+
Intersection = UnionToIntersection<
|
|
76
|
+
Union extends { key: infer Key; value: infer Value }
|
|
77
|
+
? { [key in Key extends string ? Key : never]: Value }
|
|
78
|
+
: never
|
|
79
|
+
>,
|
|
80
|
+
> = Pick<
|
|
81
|
+
Intersection,
|
|
82
|
+
Limit extends keyof Intersection ? Limit : never
|
|
83
|
+
|
|
84
|
+
// Deeply spread the object for cleaner type tooltips
|
|
85
|
+
> extends infer U
|
|
86
|
+
? {
|
|
87
|
+
[key in keyof U]: U[key] extends Record<string, unknown>
|
|
88
|
+
? U[key] extends infer V
|
|
89
|
+
? { [key in keyof V]: V[key] }
|
|
90
|
+
: never
|
|
91
|
+
: U[key]
|
|
92
|
+
}
|
|
93
|
+
: never
|
|
94
|
+
|
|
95
|
+
// Check if a custom transform exists for the given argument, and apply
|
|
96
|
+
// it to the current value if there is
|
|
97
|
+
type TransformArg<Value, Key> = Key extends keyof ModularStageTransform<Value>
|
|
98
|
+
? ModularStageTransform<Value>[Key]
|
|
99
|
+
: Value
|
|
100
|
+
|
|
101
|
+
// Map all computed arguments against the methods map to convert
|
|
102
|
+
// from the stage key to the wanted field name
|
|
103
|
+
// Use the deep `extends infer U` method to get a clean object in tooltips
|
|
104
|
+
type MapArgs<
|
|
105
|
+
Stages extends StageList,
|
|
106
|
+
Limit extends string,
|
|
107
|
+
Methods extends MethodRecord,
|
|
108
|
+
Props,
|
|
109
|
+
Args = ComputeArgs<Stages, Limit>,
|
|
110
|
+
> = UnionToIntersection<
|
|
111
|
+
// Start by injecting the original props
|
|
112
|
+
| { props: Props }
|
|
113
|
+
// Map over all configured methods
|
|
114
|
+
| {
|
|
115
|
+
[key in keyof Methods]: key extends keyof Args // Check if an arg exists for the given method
|
|
116
|
+
? Methods[key] extends MethodEntry
|
|
117
|
+
? {
|
|
118
|
+
// Extract the field name from the method
|
|
119
|
+
[k in Methods[key]['field']]: TransformArg<Args[key], key>
|
|
120
|
+
}
|
|
121
|
+
: never
|
|
122
|
+
: // Set to never if the arg does not exist
|
|
123
|
+
never
|
|
124
|
+
}[keyof Methods]
|
|
125
|
+
|
|
126
|
+
// Deeply spread the object for cleaner type tooltips
|
|
127
|
+
> extends infer U
|
|
128
|
+
? {
|
|
129
|
+
[key in keyof U]: U[key] extends Record<string, unknown>
|
|
130
|
+
? U[key] extends infer V
|
|
131
|
+
? { [key in keyof V]: V[key] }
|
|
132
|
+
: never
|
|
133
|
+
: U[key]
|
|
134
|
+
}
|
|
135
|
+
: never
|
|
136
|
+
|
|
137
|
+
type ModularExtension<
|
|
138
|
+
Props,
|
|
139
|
+
Methods extends MethodRecord,
|
|
140
|
+
Stages extends StageList,
|
|
141
|
+
> = {
|
|
142
|
+
[key in keyof Methods]: (Methods[key] extends MethodEntry
|
|
143
|
+
? Methods[key]
|
|
144
|
+
: never)['restrict'] extends undefined
|
|
145
|
+
? <
|
|
146
|
+
// Cast the method key to a method name
|
|
147
|
+
Key extends key extends MethodName ? key : never,
|
|
148
|
+
// Extract the current method
|
|
149
|
+
Method extends Methods[Key] extends MethodEntry ? Methods[Key] : never,
|
|
150
|
+
// If the mode is not 'multiple', get any previous value used
|
|
151
|
+
// for the stage
|
|
152
|
+
Prev extends Method['multiple'] extends true
|
|
153
|
+
? never
|
|
154
|
+
: GetStageValue<Stages, Key>,
|
|
155
|
+
// Find the stages occurring before the first instance of the current
|
|
156
|
+
// stage, in order to limit the arguments to those defined before the
|
|
157
|
+
// stage. This is needed for 'single' mode stages that are called
|
|
158
|
+
// multiple time.
|
|
159
|
+
Limit extends Method['multiple'] extends true // Ignore for 'multiple' stages
|
|
160
|
+
? Stages[number]['key']
|
|
161
|
+
: [GetStage<Stages, Key>] extends [never] // Ignore if it's the first time we see the stage
|
|
162
|
+
? Stages[number]['key']
|
|
163
|
+
: GetStage<Stages, Key>['stages'],
|
|
164
|
+
// Compute the kept stages by dropping all references to current stage
|
|
165
|
+
// for multiple mode, or keeping all previous stages for single mode
|
|
166
|
+
KeptStages extends Method['multiple'] extends true
|
|
167
|
+
? DropStages<Stages, Key>
|
|
168
|
+
: Stages,
|
|
169
|
+
// Get the value to use or infer, restricting it to any
|
|
170
|
+
// configured restriction or previously used values
|
|
171
|
+
Value extends [Prev] extends [never]
|
|
172
|
+
? [Method['restrict']] extends [never]
|
|
173
|
+
? unknown
|
|
174
|
+
: Method['restrict']
|
|
175
|
+
: Prev,
|
|
176
|
+
>(
|
|
177
|
+
// A stage accepts either a direct value or a function (hook) generating the value
|
|
178
|
+
value?:
|
|
179
|
+
| Value
|
|
180
|
+
| ((args: MapArgs<Stages, Limit, Methods, Props>) => Value | void),
|
|
181
|
+
) => Modular<Props, Methods, AppendStage<KeptStages, Key, Value>>
|
|
182
|
+
: <
|
|
183
|
+
// Cast the method key to a method name
|
|
184
|
+
Key extends key extends MethodName ? key : never,
|
|
185
|
+
// Extract the current method
|
|
186
|
+
Method extends Methods[Key] extends MethodEntry ? Methods[Key] : never,
|
|
187
|
+
// If the mode is not 'multiple', get any previous value used
|
|
188
|
+
// for the stage
|
|
189
|
+
Prev extends Method['multiple'] extends true
|
|
190
|
+
? never
|
|
191
|
+
: GetStageValue<Stages, Key>,
|
|
192
|
+
// Find the stages occurring before the first instance of the current
|
|
193
|
+
// stage, in order to limit the arguments to those defined before the
|
|
194
|
+
// stage. This is needed for 'single' mode stages that are called
|
|
195
|
+
// multiple time.
|
|
196
|
+
Limit extends Method['multiple'] extends true // Ignore for 'multiple' stages
|
|
197
|
+
? Stages[number]['key']
|
|
198
|
+
: [GetStage<Stages, Key>] extends [never] // Ignore if it's the first time we see the stage
|
|
199
|
+
? Stages[number]['key']
|
|
200
|
+
: GetStage<Stages, Key>['stages'],
|
|
201
|
+
// Compute the kept stages by dropping all references to current stage
|
|
202
|
+
// for multiple mode, or keeping all previous stages for single mode
|
|
203
|
+
KeptStages extends Method['multiple'] extends true
|
|
204
|
+
? DropStages<Stages, Key>
|
|
205
|
+
: Stages,
|
|
206
|
+
// Get the value to use or infer, restricting it to any
|
|
207
|
+
// configured restriction or previously used values
|
|
208
|
+
Value extends [Prev] extends [never]
|
|
209
|
+
? [Method['restrict']] extends [never]
|
|
210
|
+
? unknown
|
|
211
|
+
: Method['restrict']
|
|
212
|
+
: Prev,
|
|
213
|
+
>(
|
|
214
|
+
// A stage accepts either a direct value or a function (hook) generating the value
|
|
215
|
+
value:
|
|
216
|
+
| Value
|
|
217
|
+
| ((args: MapArgs<Stages, Limit, Methods, Props>) => Value),
|
|
218
|
+
) => Modular<Props, Methods, AppendStage<KeptStages, Key, Value>>
|
|
219
|
+
} & {
|
|
220
|
+
// Create a new component using the same stages as the current component
|
|
221
|
+
// up to a certain point
|
|
222
|
+
atStage<
|
|
223
|
+
// Key of the stage to keep to
|
|
224
|
+
Key extends Stages[number]['key'],
|
|
225
|
+
// List of stages up to the one referenced by the key
|
|
226
|
+
KeptStages extends KeepStages<
|
|
227
|
+
Stages,
|
|
228
|
+
GetStage<Stages, Key>['stages'] | Key
|
|
229
|
+
>,
|
|
230
|
+
>(
|
|
231
|
+
stage: Key,
|
|
232
|
+
): Modular<Props, Methods, KeptStages>
|
|
233
|
+
// Generate a hook instead of a component, returning the generated arguments
|
|
234
|
+
asHook(): Props extends {}
|
|
235
|
+
? () => MapArgs<Stages, Stages[number]['key'], Methods, Props>
|
|
236
|
+
: (props: Props) => MapArgs<Stages, Stages[number]['key'], Methods, Props>
|
|
237
|
+
// Overload the asHook function to allow taking in a field from the generated arguments,
|
|
238
|
+
// and returning only the value from this field
|
|
239
|
+
asHook<
|
|
240
|
+
Field extends keyof MapArgs<Stages, Stages[number]['key'], Methods, Props>,
|
|
241
|
+
>(
|
|
242
|
+
field: Field,
|
|
243
|
+
): Props extends {}
|
|
244
|
+
? () => MapArgs<Stages, Stages[number]['key'], Methods, Props>[Field]
|
|
245
|
+
: (
|
|
246
|
+
props: Props,
|
|
247
|
+
) => MapArgs<Stages, Stages[number]['key'], Methods, Props>[Field]
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Type used for describing a ModularComponent. In essence, it is a FunctionComponent
|
|
251
|
+
// with all the factories methods appended.
|
|
252
|
+
// In this type, we strongly-type all factory methods and the enhanced returned component
|
|
253
|
+
// by keeping track of all the previous stages through a stage-list tuple
|
|
254
|
+
export type Modular<
|
|
255
|
+
// The props are set and are invariant for the component, but the `props` argument
|
|
256
|
+
// itself can be extended
|
|
257
|
+
Props,
|
|
258
|
+
// List of all methods available for the component, won't change as the component
|
|
259
|
+
// is built but depends on the factory that started the build
|
|
260
|
+
Methods extends MethodRecord,
|
|
261
|
+
// Finally, the list of stages that will be appended as methods are called
|
|
262
|
+
Stages extends StageList,
|
|
263
|
+
> =
|
|
264
|
+
// At its core, the ModularComponent is a normal FunctionComponent taking
|
|
265
|
+
// the original props, extended with additional methods
|
|
266
|
+
FunctionComponent<Props> & ModularExtension<Props, Methods, Stages>
|
|
267
|
+
|
|
268
|
+
/* Exposed interfaces used for extending functionality */
|
|
269
|
+
|
|
270
|
+
// Add a value transformation for a given stage. The T type is the
|
|
271
|
+
// original type of the value passed to the stage.
|
|
272
|
+
export interface ModularStageTransform<T> {}
|