@modular-component/with-components 0.2.3 → 0.3.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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # @modular-component/with-components
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1784a2b: Add a clean way to extend the ModularComponent API with new dedicated stage functions
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [1784a2b]
12
+ - @modular-component/core@0.3.0
13
+
3
14
  ## 0.2.3
4
15
 
5
16
  ### Patch Changes
package/README.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # @modular-component/with-components
2
2
 
3
- Provides a `with(components)` stage that fills the `components` argument with
3
+ Provides a `components()` stage that fills the `components` argument with
4
4
  a map of React components. Useful when running tests in an environment that
5
5
  does not allow module mocking: sub-components can be stubbed in tests by
6
6
  mocking the stage to replace their implementations.
7
7
 
8
8
  ## Usage
9
9
 
10
+ **Stage function imports**
11
+
10
12
  ```tsx
11
- import { ModularComponent } from '@modular-component/core'
13
+ import { ModularComponent, render } from '@modular-component/core'
12
14
  import { components } from '@modular-component/with-components'
13
15
 
14
16
  import { SomeComponent } from 'some-component'
@@ -18,52 +20,72 @@ const MyComponent = ModularComponent()
18
20
  .with(render(({ props, components }) => <components.SomeComponent />))
19
21
  ```
20
22
 
23
+ **Stage registration**
24
+
25
+ ```tsx
26
+ import { ModularComponent } from '@modular-component/core'
27
+ import '@modular-component/core/register'
28
+ import '@modular-component/with-components/register'
29
+
30
+ import { SomeComponent } from 'some-component'
31
+
32
+ const MyComponent = ModularComponent()
33
+ .withComponents({ SomeComponent })
34
+ .withRender(({ props, components }) => <components.SomeComponent />)
35
+ ```
36
+
21
37
  ## Replacing sub-components
22
38
 
23
39
  Replacing sub-components can be done either by updating or mocking the stage.
24
- It allows creating a clone of the component with a different sub-component implementation,
40
+ It allows creating a clone of the component with a different sub-components implementation,
25
41
  either for tests or for content.
26
42
  For instance, one could imagine a `Layout` base component taking advantage of this functionality:
27
43
 
28
44
  ```tsx
29
45
  const PageLayout = ModularComponent()
30
- .with(components({
46
+ .withComponents({
31
47
  Title: React.Fragment,
32
48
  Subtitle: React.Fragment,
33
49
  Content: React.Fragment,
34
- Footer: React.Fragment
35
- }))
36
- .with(render(({ components }) => (
50
+ Footer: React.Fragment,
51
+ })
52
+ .withRender(({ components }) => {
37
53
  // Build a layout using <components.Title />, <components.Subtitle />...
38
- )))
54
+ })
39
55
 
40
- const PageOne = PageLayout.with(components({
56
+ const PageOne = PageLayout.withComponents({
41
57
  Title: () => <>First page</>,
42
58
  Subtitle: () => <>I have a subtitle but no footer</>,
43
59
  Content: () => <>First page content</>,
44
- Footer: React.Fragment
45
- }))
60
+ Footer: React.Fragment,
61
+ })
46
62
 
47
- const PageTwo = PageLayout.with(components({
63
+ const PageTwo = PageLayout.withComponents({
48
64
  Title: () => <>Second page</>,
49
65
  Subtitle: React.Fragment,
50
66
  Content: () => <>Second page content</>,
51
- Footer: () => <>I have a footer but no subtitle</>
52
- }))
67
+ Footer: () => <>I have a footer but no subtitle</>,
68
+ })
53
69
  ```
54
70
 
55
- ## Implementation
71
+ ## Stage registration
56
72
 
57
- `with(components)` is a simple stage adding the provided record as a `components` argument. It has a restriction
58
- on accepted values, to only accept a record of React components.
73
+ You can either automatically register the stage on `withComponents` by importing `@modular-component/with-components/register`,
74
+ or handle the registration manually thanks to the `components` function and `WithComponents` type exports.
59
75
 
60
- ```tsx
61
- import { ComponentType } from 'react'
62
- import { ModularStage } from '@modular-component/core'
76
+ For instance, here is how you could register it on `withSubComponents` instead:
77
+
78
+ ```ts
79
+ import { ModularComponent, ModularContext } from '@modular-component/core'
80
+ import { components, WithComponents } from '@modular-component/with-components'
81
+
82
+ // Register the stage on the factory
83
+ ModularComponent.register({ subComponents: components })
63
84
 
64
- export function components<Components extends Record<string, ComponentType>>(
65
- components: Components,
66
- ): ModularStage<'components', () => Components> {
67
- return { field: 'components', useStage: () => components }
85
+ // Extend the type definition
86
+ declare module '@modular-component/stages' {
87
+ export interface ModularComponentStages<Context extends ModularContext> {
88
+ withSubComponents: WithComponents<Context>
89
+ }
68
90
  }
69
91
  ```
package/dist/index.d.ts CHANGED
@@ -1,4 +1,10 @@
1
1
  import { ComponentType } from 'react';
2
- import { ModularStage } from '@modular-component/core';
3
- export declare function components<Components extends Record<string, ComponentType>>(components: Components): ModularStage<'components', () => Components>;
2
+ import { ModularContext, GetConstraintFor, GetValueGetterFor, StageParams, StageReturn } from '@modular-component/core/extend';
3
+ type Constraint<Context extends ModularContext> = GetConstraintFor<Context, 'components', Record<string, ComponentType<any>>>;
4
+ export declare function components<Context extends ModularContext, Type extends Constraint<Context>>(components: GetValueGetterFor<Context, 'components', Type>): (_?: Context | undefined) => {
5
+ field: "components";
6
+ provide: (args: import("@modular-component/core/extend").GetArgsFor<Context, "components">) => Type;
7
+ };
8
+ export type WithComponents<Context extends ModularContext> = <Type extends Constraint<Context>>(...args: StageParams<typeof components<Context, Type>>) => StageReturn<typeof components<Context, Type>>;
9
+ export {};
4
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAEtD,wBAAgB,UAAU,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACzE,UAAU,EAAE,UAAU,GACrB,YAAY,CAAC,YAAY,EAAE,MAAM,UAAU,CAAC,CAE9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AACrC,OAAO,EAGL,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,WAAW,EACZ,MAAM,gCAAgC,CAAA;AAEvC,KAAK,UAAU,CAAC,OAAO,SAAS,cAAc,IAAI,gBAAgB,CAChE,OAAO,EACP,YAAY,EACZ,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CACnC,CAAA;AAED,wBAAgB,UAAU,CACxB,OAAO,SAAS,cAAc,EAC9B,IAAI,SAAS,UAAU,CAAC,OAAO,CAAC,EAChC,UAAU,EAAE,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,CAAC;;;EAE3D;AAED,MAAM,MAAM,cAAc,CAAC,OAAO,SAAS,cAAc,IAAI,CAC3D,IAAI,SAAS,UAAU,CAAC,OAAO,CAAC,EAEhC,GAAG,IAAI,EAAE,WAAW,CAAC,OAAO,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KACnD,WAAW,CAAC,OAAO,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
+ import { addTo, wrap, } from '@modular-component/core/extend';
1
2
  export function components(components) {
2
- return { field: 'components', useStage: () => components };
3
+ return addTo().on('components').provide(wrap(components));
3
4
  }
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,UAAU,CACxB,UAAsB;IAEtB,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAA;AAC5D,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EACL,IAAI,GAML,MAAM,gCAAgC,CAAA;AAQvC,MAAM,UAAU,UAAU,CAGxB,UAA0D;IAC1D,OAAO,KAAK,EAAW,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA;AACpE,CAAC"}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "Sub-components",
10
10
  "Injection"
11
11
  ],
12
- "version": "0.2.3",
12
+ "version": "0.3.0",
13
13
  "type": "module",
14
14
  "license": "MIT",
15
15
  "publishConfig": {
@@ -18,23 +18,24 @@
18
18
  "files": [
19
19
  "src",
20
20
  "dist",
21
+ "register.js",
22
+ "register.d.ts",
21
23
  "CHANGELOG.md"
22
24
  ],
23
25
  "scripts": {
24
26
  "build": "yarn build:core && yarn build:self",
25
27
  "build:core": "yarn workspace @modular-component/core build",
26
- "build:self": "tsc -p tsconfig.build.json",
28
+ "build:self": "tsc -p tsconfig.build.json && tsc --noEmit register",
27
29
  "license": "cp ../../LICENSE ./LICENSE"
28
30
  },
29
- "dependencies": {
30
- "@modular-component/core": "0.2.3"
31
- },
32
31
  "peerDependencies": {
32
+ "@modular-component/core": "0.3.0",
33
33
  "react": ">=17 <19"
34
34
  },
35
35
  "devDependencies": {
36
+ "@modular-component/core": "*",
36
37
  "@types/react": "^18.0.17",
37
- "typescript": "^5.2.2"
38
+ "typescript": "^5.9.3"
38
39
  },
39
40
  "main": "dist/index.js",
40
41
  "types": "dist/index.d.ts"
package/register.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { ModularContext } from '@modular-component/core'
2
+ import { WithComponents } from '@modular-component/with-components'
3
+
4
+ declare module '@modular-component/stages' {
5
+ export interface ModularComponentStages<Context extends ModularContext> {
6
+ withComponents: WithComponents<Context>
7
+ }
8
+ }
package/register.js ADDED
@@ -0,0 +1,4 @@
1
+ import { ModularComponent } from '@modular-component/core'
2
+ import { components } from '@modular-component/with-components'
3
+
4
+ ModularComponent.register({ components })
package/src/index.ts CHANGED
@@ -1,8 +1,29 @@
1
1
  import { ComponentType } from 'react'
2
- import { ModularStage } from '@modular-component/core'
2
+ import {
3
+ addTo,
4
+ wrap,
5
+ ModularContext,
6
+ GetConstraintFor,
7
+ GetValueGetterFor,
8
+ StageParams,
9
+ StageReturn,
10
+ } from '@modular-component/core/extend'
3
11
 
4
- export function components<Components extends Record<string, ComponentType>>(
5
- components: Components,
6
- ): ModularStage<'components', () => Components> {
7
- return { field: 'components', useStage: () => components }
12
+ type Constraint<Context extends ModularContext> = GetConstraintFor<
13
+ Context,
14
+ 'components',
15
+ Record<string, ComponentType<any>>
16
+ >
17
+
18
+ export function components<
19
+ Context extends ModularContext,
20
+ Type extends Constraint<Context>,
21
+ >(components: GetValueGetterFor<Context, 'components', Type>) {
22
+ return addTo<Context>().on('components').provide(wrap(components))
8
23
  }
24
+
25
+ export type WithComponents<Context extends ModularContext> = <
26
+ Type extends Constraint<Context>,
27
+ >(
28
+ ...args: StageParams<typeof components<Context, Type>>
29
+ ) => StageReturn<typeof components<Context, Type>>