@collagejs/core 0.4.0 → 0.6.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/README.md +21 -7
- package/dist/MountedPiece.d.ts +6 -4
- package/dist/MountedPiece.js +31 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mountPiece.d.ts +3 -3
- package/dist/mountPiece.js +1 -1
- package/dist/preventRemount.d.ts +32 -0
- package/dist/preventRemount.js +40 -0
- package/dist/types.d.ts +90 -5
- package/package.json +4 -2
- package/dist/internal-types.d.ts +0 -8
- package/dist/internal-types.js +0 -1
package/README.md
CHANGED
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
```typescript
|
|
24
24
|
type UnmountFn = () => Promise<void>;
|
|
25
25
|
|
|
26
|
-
interface CorePiece<TProps> {
|
|
26
|
+
interface CorePiece<TProps, TCap> {
|
|
27
27
|
mount: (target: HTMLElement | ShadowRoot, props?: TProps) => Promise<UnmountFn>;
|
|
28
28
|
update?: (props: TProps) => Promise<void>;
|
|
29
|
+
readonly capabilities?: CorePieceCapabilities & TCap;
|
|
29
30
|
};
|
|
30
31
|
```
|
|
31
32
|
> ℹ️ These types were simplified. See the real ones after installing the library.
|
|
@@ -34,6 +35,7 @@ In short: Micro-frontend creators must simply provide a way to generate an obje
|
|
|
34
35
|
|
|
35
36
|
- `mount` mounts the micro-frontend user interface in the document
|
|
36
37
|
- `update` updates the properties given to the micro-frontend
|
|
38
|
+
- `capabilities` is a feature introduced in v0.5.0 that allows core piece objects to declare its capabilities (see more in its own section)
|
|
37
39
|
|
|
38
40
|
The `update` function is optional. The `mount` function must return a cleanup function that, ideally, reverts the mounting process.
|
|
39
41
|
|
|
@@ -67,7 +69,7 @@ export function buildTestPiece<TProps extends Record<string, any> = Record<strin
|
|
|
67
69
|
// Here's the unmounting function:
|
|
68
70
|
return () => {
|
|
69
71
|
callbacks?.unmount?.();
|
|
70
|
-
|
|
72
|
+
pre.remove();
|
|
71
73
|
return Promise.resolve();
|
|
72
74
|
};
|
|
73
75
|
},
|
|
@@ -142,7 +144,7 @@ Then the micro-frontends: The concept doesn't exist. At this point (after crea
|
|
|
142
144
|
|
|
143
145
|
While `single-spa` asks you to shape your module exports in a particular way (the lifecycle functions), *CollageJS* imposes no such restriction. It is just not necessary. Just make sure you can get an object of type `CorePiece` to the `<Piece>` component of your preferred framework. Then use your framework's marvels to make the `<Piece>` component appear or disappear.
|
|
144
146
|
|
|
145
|
-
Yes, you'll still be working with import maps. They are super handy. We provide an enhanced (and simplified at the same time) version of `import-map-overrides` named `@collagejs/imo`. It only supports the `overridable-importmap` type (and therefore only native import maps for native ES modules), but carries support for our `@collagejs/vite-aim` plug-in that
|
|
147
|
+
Yes, you'll still be working with import maps. They are super handy. We provide an enhanced (and simplified at the same time) version of `import-map-overrides` named `@collagejs/imo`. It only supports the `overridable-importmap` type (and therefore only native import maps for native ES modules), but carries support for our `@collagejs/vite-aim` plug-in that lets you statically import from micro-frontends. **That's right! We are free from dynamic `import()` calls!** We can statically import from micro-frontends. Furthermore, it has a more modern user interface:
|
|
146
148
|
|
|
147
149
|

|
|
148
150
|
|
|
@@ -156,19 +158,31 @@ In *CollageJS*, `CorePiece.mount()` returns the clean-up (unmounting) function.
|
|
|
156
158
|
|
|
157
159
|
Gone. There's no equivalent in *CollageJS*, as experience with `single-spa` has demonstrated that is rarely needed, and if needed, one can do this initialization easily without having to impose the function requirement. At least for now, there's no foreseeable future where an initialization function similar to `single-spa`'s `bootstrap()` will be defined. But we agree: *Never say NEVER*.
|
|
158
160
|
|
|
161
|
+
## I'm Curious about `capabilities`
|
|
162
|
+
|
|
163
|
+
Ok, in a nutshell, what inspired this feature was implementing the ability to mount micro-frontends (and its CSS) inside shadow root objects, plus give the developers a good DX. In short: If you, the dev, said you wanted the MFE in an open shadow root, but then changed your mind and now you want a closed shadow root, we have to unmount and remount or some other hacky things, like a full page reload. But for this case, and at least in Svelte, we could relocate the component's generated DOM tree without remounting.
|
|
164
|
+
|
|
165
|
+
This sounds great, but what if that breaks the MFE? So the safe path is not to take advantage of cool features. This conclusion made me sad as a developer. Therefore, enter `capabilties`.
|
|
166
|
+
|
|
167
|
+
The `capabilities` object simply states what the core piece object is able to withstand. The core library defines 2 capabilities, and devs can add user-defined ones to the object.
|
|
168
|
+
|
|
169
|
+
One of the stock (or "official" if you will) capabilities is `relocatable: boolean`. If a core piece object returns `true` for `relocatable`, it is making this statement: "I can take DOM relocation operations without going through the mounting lifecycle".
|
|
170
|
+
|
|
171
|
+
With this reassurance at hand, framework adapters like `@collagejs/svelte` and others that can pull the trick cleanly can go ahead and do it, enhancing DX. This made me happy once more as a developer, and hope that it makes more devs happy.
|
|
172
|
+
|
|
159
173
|
## Packages
|
|
160
174
|
|
|
161
175
|
| Package | Status | Links | Description |
|
|
162
176
|
| - | - | - | - |
|
|
163
177
|
| `@collagejs/core` | ✔️ | (This repo) | Core functionality. Provides the general mounting and unmounting logic. |
|
|
164
178
|
| `@collagejs/vite-css` | ✔️ | [Repo](https://github.com/collagejs/vite) | Vite plug-in that offers a CSS-mounting algorithm that is fully compatible with Vite's CSS bundling, including split CSS. It also features FOUC prevention. |
|
|
165
|
-
| `@collagejs/vite-im` | ✔️ | [Repo](https://github.com/collagejs/vite) | Vite plug-in that injects an import map and optionally the `
|
|
166
|
-
| `@collagejs/vite-aim` | ✔️ | [Repo](https://github.com/collagejs/vite) | Vite-plugin that
|
|
179
|
+
| `@collagejs/vite-im` | ✔️ | [Repo](https://github.com/collagejs/vite) | Vite plug-in that injects an import map and optionally the `@collagejs/imo` package to define bare module identifiers for easy micro-frontend loading and debugging. |
|
|
180
|
+
| `@collagejs/vite-aim` | ✔️ | [Repo](https://github.com/collagejs/vite) | Vite-plugin that auto-externalizes the module identifiers found in the application's import map. It receives the import map live (and with overrides) from the client. This enables static imports (no more dynamic `import()` calls). |
|
|
167
181
|
| `@collagejs/imo` | ✔️ | [Repo](https://github.com/collagejs/imo) | Our version of `import-map-overrides` that does the usual overriding of import map entries, plus it transmits the final import map to Vite development servers found in it. |
|
|
168
182
|
| `@collagejs/svelte` | ✔️ | [Repo](https://github.com/collagejs/svelte) | Svelte component library that can be used to create `CorePiece`-compliant objects and to mount `CorePiece` objects (of any technology) by providing the `<Piece>` component. |
|
|
169
|
-
| `@collagejs/react` |
|
|
183
|
+
| `@collagejs/react` | ✔️ | [Repo](https://github.com/collagejs/react) | React component library that can be used to create `CorePiece`-compliant objects and to mount `CorePiece` objects (of any technology) by providing the `<Piece>` component. |
|
|
170
184
|
| `@collagejs/solidjs` | ❌ | [Repo](https://github.com/collagejs/solidjs) | SolidJS component library that can be used to create `CorePiece`-compliant objects and to mount `CorePiece` objects (of any technology) by providing the `<Piece>` component. |
|
|
171
|
-
| `@collagejs/vue` |
|
|
185
|
+
| `@collagejs/vue` | 🚧 | [Repo](https://github.com/collagejs/vue) | **Next in line** VueJS component library that can be used to create `CorePiece`-compliant objects and to mount `CorePiece` objects (of any technology) by providing the `<Piece>` component. |
|
|
172
186
|
| `@collagejs/angular` | ❌ | | **External help needed.** We don't have expertise in Angular, nor do we want to acquire it. If you're an Angular developer, please consider contributing. |
|
|
173
187
|
|
|
174
188
|
## Other Repositories
|
package/dist/MountedPiece.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type { CorePiece, MountPiece, AcceptableTarget } from "./types.js";
|
|
1
|
+
import type { CorePiece, MountPiece, AcceptableTarget, CorePieceCapabilities, RelocationResult } from "./types.js";
|
|
2
2
|
export declare const mountKey: unique symbol;
|
|
3
|
-
export declare class MountedPiece<TProps extends Record<string, any> = Record<string, any
|
|
3
|
+
export declare class MountedPiece<TProps extends Record<string, any> = Record<string, any>, TCap extends Record<string, any> = {}> {
|
|
4
4
|
#private;
|
|
5
|
-
get mountPiece():
|
|
6
|
-
constructor(piece: CorePiece<TProps>, mountPiece: MountPiece<TProps>, parent?: MountedPiece);
|
|
5
|
+
get mountPiece(): <UProps extends Record<string, any> = Record<string, any>, UCap extends CorePieceCapabilities = CorePieceCapabilities>(piece: CorePiece<UProps, UCap> | Promise<CorePiece<UProps, UCap>>, target: AcceptableTarget, props?: UProps) => Promise<MountedPiece<UProps, UCap>>;
|
|
6
|
+
constructor(piece: CorePiece<TProps, TCap>, mountPiece: MountPiece<TProps, TCap>, parent?: MountedPiece);
|
|
7
7
|
[mountKey](target: AcceptableTarget, props?: TProps): Promise<void>;
|
|
8
8
|
unmount(): Promise<void>;
|
|
9
9
|
update(props: TProps): Promise<void>;
|
|
10
|
+
relocate(target: AcceptableTarget, newTarget: AcceptableTarget): Promise<RelocationResult>;
|
|
11
|
+
get capabilities(): (CorePieceCapabilities & TCap) | undefined;
|
|
10
12
|
}
|
package/dist/MountedPiece.js
CHANGED
|
@@ -30,6 +30,27 @@ async function doUpdate(update, props) {
|
|
|
30
30
|
}
|
|
31
31
|
return await update(props);
|
|
32
32
|
}
|
|
33
|
+
async function doRelocate(relocate, target, newTarget) {
|
|
34
|
+
if (Array.isArray(relocate)) {
|
|
35
|
+
let first = true;
|
|
36
|
+
let ready = false;
|
|
37
|
+
for (const fn of relocate) {
|
|
38
|
+
const r = await doRelocate(fn, target, newTarget);
|
|
39
|
+
if (r === 'ready') {
|
|
40
|
+
ready = true;
|
|
41
|
+
}
|
|
42
|
+
else if (!r) {
|
|
43
|
+
if (first) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
throw new Error("Relocation function returned 'false' after another relocation function returned 'ready' or 'true'. The piece's state is now inconsistent.");
|
|
47
|
+
}
|
|
48
|
+
first = false;
|
|
49
|
+
}
|
|
50
|
+
return ready ? 'ready' : true;
|
|
51
|
+
}
|
|
52
|
+
return await relocate(target, newTarget);
|
|
53
|
+
}
|
|
33
54
|
export class MountedPiece {
|
|
34
55
|
#piece;
|
|
35
56
|
#id;
|
|
@@ -63,8 +84,18 @@ export class MountedPiece {
|
|
|
63
84
|
if (this.#parent) {
|
|
64
85
|
this.#parent.#childPieces.delete((item) => item.#id === this.#id);
|
|
65
86
|
}
|
|
87
|
+
this.#cleanup = undefined;
|
|
66
88
|
}
|
|
67
89
|
update(props) {
|
|
68
90
|
return doUpdate(this.#piece.update, props);
|
|
69
91
|
}
|
|
92
|
+
relocate(target, newTarget) {
|
|
93
|
+
if (!this.#piece.relocate) {
|
|
94
|
+
return Promise.resolve(false);
|
|
95
|
+
}
|
|
96
|
+
return doRelocate(this.#piece.relocate, target, newTarget);
|
|
97
|
+
}
|
|
98
|
+
get capabilities() {
|
|
99
|
+
return this.#piece.capabilities;
|
|
100
|
+
}
|
|
70
101
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/mountPiece.d.ts
CHANGED
|
@@ -6,13 +6,13 @@ import type { AcceptableTarget, CorePiece, MountPiece } from "./types.js";
|
|
|
6
6
|
* This exists merely to allow unit testing.
|
|
7
7
|
*/
|
|
8
8
|
export interface MountedPieceConstructor {
|
|
9
|
-
new
|
|
9
|
+
new (piece: CorePiece<any, any>, mountPiece: MountPiece<any, any>, parent?: MountedPiece<any, any>): MountedPiece<any, any>;
|
|
10
10
|
}
|
|
11
|
-
export declare function mountPieceCore<TProps extends Record<string, any> = Record<string, any
|
|
11
|
+
export declare function mountPieceCore<TProps extends Record<string, any> = Record<string, any>, TCap extends Record<string, any> = {}>(this: MountedPiece<any, any> | undefined, piece: CorePiece<TProps, TCap> | Promise<CorePiece<TProps, TCap>>, target: AcceptableTarget, props?: TProps, MountedPieceClass?: MountedPieceConstructor): Promise<MountedPiece<TProps, TCap>>;
|
|
12
12
|
/**
|
|
13
13
|
* Mounts the CollageJS piece as a child of the target element.
|
|
14
14
|
* @param piece The CollageJS piece to mount.
|
|
15
15
|
* @param target The target HTML element or shadow root where to mount the piece.
|
|
16
16
|
* @param props The properties to pass to the piece.
|
|
17
17
|
*/
|
|
18
|
-
export declare function mountPiece<TProps extends Record<string, any> = Record<string, any
|
|
18
|
+
export declare function mountPiece<TProps extends Record<string, any> = Record<string, any>, TCap extends Record<string, any> = {}>(piece: CorePiece<TProps, TCap>, target: AcceptableTarget, props?: TProps): Promise<MountedPiece<TProps, TCap>>;
|
package/dist/mountPiece.js
CHANGED
|
@@ -3,7 +3,7 @@ export async function mountPieceCore(piece, target, props, MountedPieceClass = M
|
|
|
3
3
|
if (piece instanceof Promise) {
|
|
4
4
|
piece = await piece;
|
|
5
5
|
}
|
|
6
|
-
const mp = new MountedPieceClass(piece,
|
|
6
|
+
const mp = new MountedPieceClass(piece, mountPieceCore, this);
|
|
7
7
|
await mp[mountKey](target, props);
|
|
8
8
|
return mp;
|
|
9
9
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { MountFn } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a mount function that can only be called once. If the mount function is called more than once, it will throw
|
|
4
|
+
* an error. This effectively prevents a piece from being mounted more than once.
|
|
5
|
+
*
|
|
6
|
+
* Use this on core piece objects that cannot guarantee the integrity of their state after they unmount.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { preventRemount } from "@collagejs/core";
|
|
10
|
+
*
|
|
11
|
+
* export function myCorePieceFactory() {
|
|
12
|
+
* ...
|
|
13
|
+
* return {
|
|
14
|
+
* // The most logical place is at the very beginning of the mount array.
|
|
15
|
+
* mount: [preventRemount(), myMount],
|
|
16
|
+
* update: ...,
|
|
17
|
+
* capabilities: {
|
|
18
|
+
* // Informational only: Allow the core piece object to answer the question.
|
|
19
|
+
* remountable: false,
|
|
20
|
+
* }
|
|
21
|
+
* };
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* ### 💡 Tips
|
|
25
|
+
*
|
|
26
|
+
* - Try to always follow the "fail fast" principle, so call `preventRemount()` as early as possible in the mount array.
|
|
27
|
+
* - If for any reason the mount operation is expected to fail (for whatever needed reason), consider moving the call
|
|
28
|
+
* to `preventRemount()` after the mount operation that may fail, so that the piece object does not have to be
|
|
29
|
+
* discarded unnecessarily.
|
|
30
|
+
* @returns A mount function that throws an error if called more than once.
|
|
31
|
+
*/
|
|
32
|
+
export declare function preventRemount<TProps extends Record<string, any> = Record<string, any>>(): MountFn<TProps>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a mount function that can only be called once. If the mount function is called more than once, it will throw
|
|
3
|
+
* an error. This effectively prevents a piece from being mounted more than once.
|
|
4
|
+
*
|
|
5
|
+
* Use this on core piece objects that cannot guarantee the integrity of their state after they unmount.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { preventRemount } from "@collagejs/core";
|
|
9
|
+
*
|
|
10
|
+
* export function myCorePieceFactory() {
|
|
11
|
+
* ...
|
|
12
|
+
* return {
|
|
13
|
+
* // The most logical place is at the very beginning of the mount array.
|
|
14
|
+
* mount: [preventRemount(), myMount],
|
|
15
|
+
* update: ...,
|
|
16
|
+
* capabilities: {
|
|
17
|
+
* // Informational only: Allow the core piece object to answer the question.
|
|
18
|
+
* remountable: false,
|
|
19
|
+
* }
|
|
20
|
+
* };
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* ### 💡 Tips
|
|
24
|
+
*
|
|
25
|
+
* - Try to always follow the "fail fast" principle, so call `preventRemount()` as early as possible in the mount array.
|
|
26
|
+
* - If for any reason the mount operation is expected to fail (for whatever needed reason), consider moving the call
|
|
27
|
+
* to `preventRemount()` after the mount operation that may fail, so that the piece object does not have to be
|
|
28
|
+
* discarded unnecessarily.
|
|
29
|
+
* @returns A mount function that throws an error if called more than once.
|
|
30
|
+
*/
|
|
31
|
+
export function preventRemount() {
|
|
32
|
+
let mountCount = 0;
|
|
33
|
+
return () => {
|
|
34
|
+
if (mountCount > 0) {
|
|
35
|
+
throw new Error("This piece cannot be mounted more than once. If this is unexpected, you might be unknowingly sharing the same piece object in different places or Piece components.");
|
|
36
|
+
}
|
|
37
|
+
++mountCount;
|
|
38
|
+
return Promise.resolve(() => Promise.resolve());
|
|
39
|
+
};
|
|
40
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -20,6 +20,19 @@ export type UnmountFn = () => Promise<void>;
|
|
|
20
20
|
* @returns A promise to the cleanup function that unmounts the piece.
|
|
21
21
|
*/
|
|
22
22
|
export type MountFn<TProps extends Record<string, any> = Record<string, any>> = (target: AcceptableTarget, props?: MountProps<TProps>) => Promise<UnmountFn>;
|
|
23
|
+
/**
|
|
24
|
+
* Defines the possible return values of `CorePiece.relocate`.
|
|
25
|
+
*/
|
|
26
|
+
export type RelocationResult = boolean | 'ready';
|
|
27
|
+
/**
|
|
28
|
+
* Type that defines the signature of the functions accepted in `CorePiece.relocate`.
|
|
29
|
+
* @param parent The current parent of the piece's root element(s).
|
|
30
|
+
* @param newParent The new parent where the piece's root element(s) will be relocated.
|
|
31
|
+
* @returns A promise that resolves to `true` if the relocation was successful, `false` if it failed or relocation
|
|
32
|
+
* is disallowed, or `'ready'` if the piece is ready to be relocated, but the relocation must be performed by the
|
|
33
|
+
* caller.
|
|
34
|
+
*/
|
|
35
|
+
export type RelocateFn = (parent: AcceptableTarget, newParent: AcceptableTarget) => Promise<RelocationResult>;
|
|
23
36
|
/**
|
|
24
37
|
* Type that defines the signature of the functions accepted in `CorePiece.update`.
|
|
25
38
|
* @param props The new property values for the mounted piece.
|
|
@@ -33,11 +46,32 @@ export type Mount<TProps extends Record<string, any> = Record<string, any>> = Mo
|
|
|
33
46
|
/**
|
|
34
47
|
* Defines the accepted shapes for `CorePiece.update`.
|
|
35
48
|
*/
|
|
36
|
-
export type Update<TProps extends Record<string, any> = Record<string, any>> = UpdateFn<TProps> | UpdateFn<TProps>[] | Update[];
|
|
49
|
+
export type Update<TProps extends Record<string, any> = Record<string, any>> = UpdateFn<TProps> | UpdateFn<TProps>[] | Update<TProps>[];
|
|
50
|
+
/**
|
|
51
|
+
* Defines the accepted shapes for `CorePiece.relocate`.
|
|
52
|
+
*/
|
|
53
|
+
export type Relocate = RelocateFn | RelocateFn[] | Relocate[];
|
|
54
|
+
/**
|
|
55
|
+
* Defines the capabilities of a `CorePiece` object recognized by the core *CollageJS* library. These capabilities are
|
|
56
|
+
* used to determine how the core library should handle the piece's lifecycle, or whether a particular action or
|
|
57
|
+
* feature can be enabled or allowed.
|
|
58
|
+
*/
|
|
59
|
+
export type CorePieceCapabilities = {
|
|
60
|
+
/**
|
|
61
|
+
* Informative only: Indicates that the piece can be mounted more than once.
|
|
62
|
+
*
|
|
63
|
+
* Since `@collagejs/core` never injects code into `CorePiece` objects, it cannot enforce this capability. The
|
|
64
|
+
* only place where this can be enforced is at `CorePiece.mount`. The core library provides the `preventRemount()`
|
|
65
|
+
* function to help developers create mount functions that throw an error if called more than once.
|
|
66
|
+
*
|
|
67
|
+
* **💡TIP**: Official framework adapters provide this functionality.
|
|
68
|
+
*/
|
|
69
|
+
remountable?: boolean;
|
|
70
|
+
};
|
|
37
71
|
/**
|
|
38
72
|
* Defines the contract that objects must follow in order to be mountable as *CollageJS* pieces (micro-frontends).
|
|
39
73
|
*/
|
|
40
|
-
export interface CorePiece<TProps extends Record<string, any> = Record<string, any
|
|
74
|
+
export interface CorePiece<TProps extends Record<string, any> = Record<string, any>, TCap extends Record<string, any> = {}> {
|
|
41
75
|
/**
|
|
42
76
|
* Mounts the piece (micro-frontend) in the document. Every mount function should always return a cleanup function
|
|
43
77
|
* that, when called, unmounts the piece.
|
|
@@ -48,11 +82,54 @@ export interface CorePiece<TProps extends Record<string, any> = Record<string, a
|
|
|
48
82
|
* while mounted in the document, and all property values must have been passed during mounting.
|
|
49
83
|
*/
|
|
50
84
|
update?: Update<TProps>;
|
|
85
|
+
/**
|
|
86
|
+
* Either relocates the root element(s) of the piece to a new parent, or prepares the piece for relocation. This
|
|
87
|
+
* is optional. If not provided, the piece won't support relocation of its root element(s) to a new parent, and
|
|
88
|
+
* the piece will be unmounted and remounted instead in the pertinent cases.
|
|
89
|
+
*
|
|
90
|
+
* ### Return Values
|
|
91
|
+
*
|
|
92
|
+
* + `true`: The relocation was successful.
|
|
93
|
+
* + `false`: The relocation failed or is disallowed.
|
|
94
|
+
* + `'ready'`: The piece is ready to be relocated, but the relocation must be performed by the caller.
|
|
95
|
+
*
|
|
96
|
+
* ### When Using Multiple Relocation Functions
|
|
97
|
+
*
|
|
98
|
+
* If multiple relocation functions are provided, they will be called in order:
|
|
99
|
+
*
|
|
100
|
+
* + If the first of them returns `false`, the relocation process will stop.
|
|
101
|
+
* + If all of them return `true`, the relocation is considered successful.
|
|
102
|
+
* + If any of them returns `'ready'`, the remaining functions are still called, but the caller will
|
|
103
|
+
* run its relocation process after all functions have been called.
|
|
104
|
+
* + If any of them returns `false` after one or more of them returned `'ready'` or `true`, an error is thrown.
|
|
105
|
+
*/
|
|
106
|
+
relocate?: Relocate;
|
|
107
|
+
/**
|
|
108
|
+
* Declares the capabilities of the piece. This is optional. If not provided, the piece will be assumed to have no
|
|
109
|
+
* capabilities.
|
|
110
|
+
*
|
|
111
|
+
* ### Notable Exception
|
|
112
|
+
*
|
|
113
|
+
* The library defines the `remountable` capability, which is informative only. The core library cannot enforce
|
|
114
|
+
* this capability, so `CorePiece` developers should use the `preventRemount()` function (or equivalent) to throw an
|
|
115
|
+
* error if the piece is mounted more than once for pieces that cannot withstand multiple mountings.
|
|
116
|
+
*
|
|
117
|
+
* Official framework adapters query the value of `capabilities.remountable` and act accordingly to their best
|
|
118
|
+
* ability, and at least emit a warning if a non-remountable piece is mounted more than once.
|
|
119
|
+
*
|
|
120
|
+
* Only the author of a `CorePiece` object can guarantee that the piece is remountable. We encourage developers to
|
|
121
|
+
* be explicit about this capability when creating `CorePiece` objects.
|
|
122
|
+
*
|
|
123
|
+
* > ℹ️ **NOTE:** Official framework adapters are free to choose which default value for `capabilities.remountable`
|
|
124
|
+
* > they will use while creating `CorePiece` objects when the property is not provided in order to maximize
|
|
125
|
+
* > framework feature usage (perhaps a framework can guarantee component state automatically, or perhaps it cannot).
|
|
126
|
+
*/
|
|
127
|
+
readonly capabilities?: CorePieceCapabilities & TCap;
|
|
51
128
|
}
|
|
52
129
|
/**
|
|
53
130
|
* Defines the shape of the object returned by the process of mounting a `CorePiece` object.
|
|
54
131
|
*/
|
|
55
|
-
export interface MountedPiece<TProps extends Record<string, any> = Record<string, any
|
|
132
|
+
export interface MountedPiece<TProps extends Record<string, any> = Record<string, any>, TCap extends Record<string, any> = {}> {
|
|
56
133
|
/**
|
|
57
134
|
* Function used to apply updated property values to the mounted `CorePiece` object.
|
|
58
135
|
*/
|
|
@@ -61,6 +138,10 @@ export interface MountedPiece<TProps extends Record<string, any> = Record<string
|
|
|
61
138
|
* Function used to unmount the `CorePiece` object.
|
|
62
139
|
*/
|
|
63
140
|
unmount: UnmountFn;
|
|
141
|
+
/**
|
|
142
|
+
* Function used to relocate the `CorePiece` object to a new parent without unmounting.
|
|
143
|
+
*/
|
|
144
|
+
relocate: RelocateFn;
|
|
64
145
|
/**
|
|
65
146
|
* The version of the global `mountPiece` function that tracks mounted children so their unmounting is
|
|
66
147
|
* synchronized with this piece's unmount event.
|
|
@@ -68,7 +149,11 @@ export interface MountedPiece<TProps extends Record<string, any> = Record<string
|
|
|
68
149
|
* **IMPORTANT:** Always use this function instead of the global `mountPiece` function when mounting other
|
|
69
150
|
* `CorePiece` objects inside the mounted `CorePiece` object to prevent lifecycle issues.
|
|
70
151
|
*/
|
|
71
|
-
mountPiece:
|
|
152
|
+
mountPiece<UProps extends Record<string, any> = Record<string, any>, UCap extends CorePieceCapabilities = CorePieceCapabilities>(piece: CorePiece<UProps, UCap> | Promise<CorePiece<UProps, UCap>>, target: AcceptableTarget, props?: UProps): Promise<MountedPiece<UProps, UCap>>;
|
|
153
|
+
/**
|
|
154
|
+
* The declared capabilities of the mounted `CorePiece` object.
|
|
155
|
+
*/
|
|
156
|
+
readonly capabilities: (CorePieceCapabilities & TCap) | undefined;
|
|
72
157
|
}
|
|
73
158
|
/**
|
|
74
159
|
* Type definition for the `mountPiece` functions that mount *CollageJS* pieces in the HTML document.
|
|
@@ -80,7 +165,7 @@ export interface MountedPiece<TProps extends Record<string, any> = Record<string
|
|
|
80
165
|
* @param target HTML element or shadow root where to mount.
|
|
81
166
|
* @param props Optional properties for the `CorePiece` object.
|
|
82
167
|
*/
|
|
83
|
-
export type MountPiece<TProps extends Record<string, any> = Record<string, any
|
|
168
|
+
export type MountPiece<TProps extends Record<string, any> = Record<string, any>, TCap extends Record<string, any> = {}> = (piece: CorePiece<TProps, TCap> | Promise<CorePiece<TProps, TCap>>, target: AcceptableTarget, props?: TProps) => Promise<MountedPiece<TProps, TCap>>;
|
|
84
169
|
declare global {
|
|
85
170
|
/**
|
|
86
171
|
* Defines the capabilities in the global `CollageJs` object.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@collagejs/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Core functionality for CollageJS.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"test:unit": "vitest run",
|
|
10
10
|
"test:watch": "vitest",
|
|
11
11
|
"test:types": "tstyche ./tests/typetests",
|
|
12
|
-
"
|
|
12
|
+
"clean": "rimraf dist",
|
|
13
|
+
"build": "npm run clean && tsc && pwsh -File ./post-build.ps1 && publint",
|
|
13
14
|
"check": "tsc --noEmit"
|
|
14
15
|
},
|
|
15
16
|
"keywords": [
|
|
@@ -72,6 +73,7 @@
|
|
|
72
73
|
"@types/sinon": "^21.0.0",
|
|
73
74
|
"jsdom": "^29.1.1",
|
|
74
75
|
"publint": "^0.3.11",
|
|
76
|
+
"rimraf": "^6.1.3",
|
|
75
77
|
"sinon": "^22.0.0",
|
|
76
78
|
"tstyche": "^7.2.1",
|
|
77
79
|
"typescript": "^6.0.3",
|
package/dist/internal-types.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { UnmountFn, UpdateFn } from "./types.js";
|
|
2
|
-
export declare namespace Internal {
|
|
3
|
-
type MountedPiece<TProps extends Record<string, any> = Record<string, any>> = {
|
|
4
|
-
update: UpdateFn<TProps>;
|
|
5
|
-
unmount: UnmountFn;
|
|
6
|
-
childPieces: Map<string, MountedPiece>;
|
|
7
|
-
};
|
|
8
|
-
}
|
package/dist/internal-types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|