@collagejs/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/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/MountedPiece.d.ts +10 -0
- package/dist/MountedPiece.js +70 -0
- package/dist/Stack.d.ts +99 -0
- package/dist/Stack.js +139 -0
- package/dist/common.d.ts +1 -0
- package/dist/common.js +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/internal-types.d.ts +8 -0
- package/dist/internal-types.js +1 -0
- package/dist/logos/collagejs-128.svg +66 -0
- package/dist/logos/collagejs-16.svg +19 -0
- package/dist/logos/collagejs-48.svg +50 -0
- package/dist/logos/collagejs-512.svg +99 -0
- package/dist/logos/collagejs-64.svg +54 -0
- package/dist/logos/collagejs-icon.svg +70 -0
- package/dist/logos/logo.d.ts +24 -0
- package/dist/mountPiece.d.ts +10 -0
- package/dist/mountPiece.js +15 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.js +3 -0
- package/package.json +80 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 collagejs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# <img src="src/logos/collagejs-48.svg" alt="Svelte Router Logo" width="48" height="48" align="left"> CollageJS
|
|
2
|
+
|
|
3
|
+
> Micro library for framework-agnostic micro-frontends
|
|
4
|
+
|
|
5
|
+
**🚧🚧 YOU'RE EARLY. WORK IN PROGRESS... 🚧🚧**
|
|
6
|
+
|
|
7
|
+
*If you would like to express youself, head to the [Discussions board](https://github.com/collagejs/collagejs/discussions).*
|
|
8
|
+
|
|
9
|
+
[Full Documentation](https://collagejs.dev)
|
|
10
|
+
|
|
11
|
+
*CollageJS* is a very, very small library that enables the composition of a web user interface with micro-frontends created with any technology (Svelte, React, Vue, Solid, HTMX, etc.). It is heavily inspired by the *parcel* concept in the excellent `single-spa` routing library.
|
|
12
|
+
|
|
13
|
+
## How It Works
|
|
14
|
+
|
|
15
|
+
*CollageJS* defines a contract that must be fulfilled by an object. This contract is defined as the following TypeScript types (simplified):
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
type UnmountFn = () => Promise<void>;
|
|
19
|
+
type MountFn<TProps> = (target: HTMLElement, props?: TProps) => Promise<UnmountFn>;
|
|
20
|
+
type Mount<TProps> = MountFn<TProps> | MountFn<TProps>[] | Mount<TProps>[];
|
|
21
|
+
type UpdateFn<TProps> = (props: TProps) => Promise<void>;
|
|
22
|
+
type Update<TProps> = UpdateFn<TProps> | UpdateFn<TProps>[] | Update[];
|
|
23
|
+
|
|
24
|
+
interface CorePiece<TProps> {
|
|
25
|
+
mount: Mount<TProps>;
|
|
26
|
+
update?: Update<TProps>;
|
|
27
|
+
};
|
|
28
|
+
```
|
|
29
|
+
> ℹ️ These types were simplified. See the real ones after installing the library.
|
|
30
|
+
|
|
31
|
+
In short: Micro-frontend creators must simply provide a way to generate an object that fulfills the above `CorePiece` interface, where:
|
|
32
|
+
|
|
33
|
+
- `mount` mounts the micro-frontend user interface in the document
|
|
34
|
+
- `update` updates the properties given to the micro-frontend
|
|
35
|
+
|
|
36
|
+
The `update` function is optional. The `mount` function must return a cleanup function that, ideally, reverts the mounting process.
|
|
37
|
+
|
|
38
|
+
This object, once obtained by the consuming project/micro-frontend, is given to the `<Piece>` component. The implementation of this component is framework-specific. For example, the `<Piece>` component found in the `@collagejs/svelte` package is a **Svelte** component.
|
|
39
|
+
|
|
40
|
+
## Router Needs
|
|
41
|
+
|
|
42
|
+
As you may (or may not) know, `single-spa` is a client-side router that defines a contract similar to `CorePiece` above. *CollageJS*, on the other hand, doesn't provide a router. Use whichever client-side router you wish in your micro-frontend projects.
|
|
43
|
+
|
|
44
|
+
### Why No Router
|
|
45
|
+
|
|
46
|
+
There are 2 reasons. The first one is quite simple: A router is not mandatory to implement and use micro-frontends. Micro-frontends can come and go for any reason, such as the user clicking a button, a timer running out, etc. The "micro-frontend" concept is not tied to routing.
|
|
47
|
+
|
|
48
|
+
The second reason is maintenance: Historically, the `single-spa` router has had a tough time pleasing everyone because most often than not, micro-frontends come with their own "sub-routers" installed. MFE's created in React usually come featuring the `react-router` router; SolidJS MFE's come with `@solidjs/router`, etc. and the mixture has sometimes caused problems. Furthermore, `single-spa` provides a web component to configure the router in markup format, which has caused even more issues. Moreover, this layout component lacks features people are used to having within their own frameworks of choice.
|
|
49
|
+
|
|
50
|
+
In light of this: **Bring Your Own Router**. It is just better. There are routers out there supported by entire teams with great many features, and developers probably learned to use them already. Not providing a router (unlike `single-spa`) is one less thing to learn for consumers of this library.
|
|
51
|
+
|
|
52
|
+
Do you disagree with this? Perhaps you need one and don't know which one would work best? No problem! We can recommend one: Create a "root" **Vite + Svelte** project and use `@svelte-router/core` ([documentation](https://svelte-router.dev)). This is a multi-route-matching router designed for micro-frontends. It is very simple to use and learn, even if you have never used Svelte before.
|
|
53
|
+
|
|
54
|
+
**"But I don't want to learn Svelte"**, you might say. Well, it's understandable. However, if you're coming from a `single-spa` experience, learning a bit of Svelte to configure the root router is no different than learning `single-spa`'s layout web component.
|
|
55
|
+
|
|
56
|
+
In the end, it is your choice.
|
|
57
|
+
|
|
58
|
+
## For the `single-spa` Savvy
|
|
59
|
+
|
|
60
|
+
If you know/are used to `single-spa`, you're almost up to speed with *CollageJS*. Basically, there's no concept of a "root config" project, but of course, there's always a "root" project. Use whatever framework/technology you want to produce it.
|
|
61
|
+
|
|
62
|
+
Then the micro-frontends: The concept doesn't exist. At this point (after creating a root UI project), you're 100% free to do as you wish. Just mount *CollageJS pieces*, which are basically the equivalent of `single-spa` parcels. You don't get a router provided, you bring your own, or don't bring a router. No worries. Who says that a router is required? Not us. You can trigger "parcel" loading by any means at your disposal: Button clicks, timers, window events, and yes, also location URL changes (routing) if you want.
|
|
63
|
+
|
|
64
|
+
### Technical Differences
|
|
65
|
+
|
|
66
|
+
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.
|
|
67
|
+
|
|
68
|
+
Yes, you can still use import maps, and can even continue using the excellent `import-map-overrides` package. It is encouraged.
|
|
69
|
+
|
|
70
|
+
#### Where Did the `unmount` Lifecycle Function Go?
|
|
71
|
+
|
|
72
|
+
In *CollageJS*, `CorePiece.mount()` returns the clean-up (unmounting) function.
|
|
73
|
+
|
|
74
|
+
#### And What About `bootstrap`?
|
|
75
|
+
|
|
76
|
+
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.
|
|
77
|
+
|
|
78
|
+
## Packages
|
|
79
|
+
|
|
80
|
+
| Package | Status | Description |
|
|
81
|
+
| - | - | - |
|
|
82
|
+
| `@collagejs/core` | ✔️ | Core functionality. Provides the general mounting and unmouting logic. |
|
|
83
|
+
| `@collagejs/vite` | ❌ | Vite plug-in that offers a CSS-mounting algorithm that is fully compatible with Vite's CSS bundling, including split CSS. |
|
|
84
|
+
| `@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. |
|
|
85
|
+
| `@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. |
|
|
86
|
+
| `@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. |
|
|
87
|
+
| `@collagejs/vue` | ❌ | 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. |
|
|
88
|
+
| `@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. |
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CorePiece, MountPiece } from "./types.js";
|
|
2
|
+
export declare const mountKey: unique symbol;
|
|
3
|
+
export declare class MountedPiece<TProps extends Record<string, any> = Record<string, any>> {
|
|
4
|
+
#private;
|
|
5
|
+
get mountPiece(): MountPiece<TProps>;
|
|
6
|
+
constructor(piece: CorePiece<TProps>, mountPiece: MountPiece<TProps>, parent?: MountedPiece);
|
|
7
|
+
[mountKey](target: HTMLElement, props?: TProps): Promise<void>;
|
|
8
|
+
unmount(): Promise<void>;
|
|
9
|
+
update(props: TProps): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { mountPieceKey } from "./common.js";
|
|
2
|
+
import { Stack } from "./Stack.js";
|
|
3
|
+
export const mountKey = Symbol();
|
|
4
|
+
let pieceIdCounter = 0;
|
|
5
|
+
function generatePieceId() {
|
|
6
|
+
return `cjsp-${++pieceIdCounter}-${Date.now().toString(36)}`;
|
|
7
|
+
}
|
|
8
|
+
async function doMount(mount, target, props) {
|
|
9
|
+
if (Array.isArray(mount)) {
|
|
10
|
+
const unmountFns = new Stack();
|
|
11
|
+
for (const m of mount) {
|
|
12
|
+
unmountFns.push(await doMount(m, target, props));
|
|
13
|
+
}
|
|
14
|
+
return async () => {
|
|
15
|
+
for (const u of unmountFns) {
|
|
16
|
+
await u();
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return await mount(target, props);
|
|
21
|
+
}
|
|
22
|
+
async function doUpdate(update, props) {
|
|
23
|
+
if (!update)
|
|
24
|
+
return;
|
|
25
|
+
if (Array.isArray(update)) {
|
|
26
|
+
for (const u of update) {
|
|
27
|
+
await doUpdate(u, props);
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
return await update(props);
|
|
32
|
+
}
|
|
33
|
+
export class MountedPiece {
|
|
34
|
+
#piece;
|
|
35
|
+
#id;
|
|
36
|
+
#childPieces;
|
|
37
|
+
#parent;
|
|
38
|
+
#cleanup;
|
|
39
|
+
#mountPiece;
|
|
40
|
+
get mountPiece() {
|
|
41
|
+
return this.#mountPiece;
|
|
42
|
+
}
|
|
43
|
+
constructor(piece, mountPiece, parent) {
|
|
44
|
+
this.#piece = piece;
|
|
45
|
+
this.#parent = parent;
|
|
46
|
+
this.#id = generatePieceId();
|
|
47
|
+
this.#childPieces = new Stack();
|
|
48
|
+
this.#mountPiece = mountPiece.bind(this);
|
|
49
|
+
}
|
|
50
|
+
async [mountKey](target, props) {
|
|
51
|
+
this.#cleanup = await doMount(this.#piece.mount, target, { ...props, [mountPieceKey]: this.#mountPiece });
|
|
52
|
+
if (this.#parent) {
|
|
53
|
+
this.#parent.#childPieces.push(this);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async unmount() {
|
|
57
|
+
if (this.#childPieces.size) {
|
|
58
|
+
for (const childPiece of this.#childPieces) {
|
|
59
|
+
await childPiece.unmount();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
await this.#cleanup?.();
|
|
63
|
+
if (this.#parent) {
|
|
64
|
+
this.#parent.#childPieces.delete((item) => item.#id === this.#id);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
update(props) {
|
|
68
|
+
return doUpdate(this.#piece.update, props);
|
|
69
|
+
}
|
|
70
|
+
}
|
package/dist/Stack.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A generic stack implementation providing standard stack operations.
|
|
3
|
+
* Follows LIFO (Last In, First Out) principle.
|
|
4
|
+
*
|
|
5
|
+
* @template T The type of elements stored in the stack
|
|
6
|
+
*/
|
|
7
|
+
export declare class Stack<T> {
|
|
8
|
+
#private;
|
|
9
|
+
/**
|
|
10
|
+
* Adds an element to the top of the stack.
|
|
11
|
+
*
|
|
12
|
+
* @param item The item to push onto the stack
|
|
13
|
+
* @returns The new size of the stack
|
|
14
|
+
*/
|
|
15
|
+
push(item: T): number;
|
|
16
|
+
/**
|
|
17
|
+
* Removes and returns the top element from the stack.
|
|
18
|
+
*
|
|
19
|
+
* @returns The top element, or undefined if the stack is empty
|
|
20
|
+
*/
|
|
21
|
+
pop(): T | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the top element without removing it.
|
|
24
|
+
*
|
|
25
|
+
* @returns The top element, or undefined if the stack is empty
|
|
26
|
+
*/
|
|
27
|
+
peek(): T | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Returns the top element without removing it.
|
|
30
|
+
* Alias for peek() method.
|
|
31
|
+
*
|
|
32
|
+
* @returns The top element, or undefined if the stack is empty
|
|
33
|
+
*/
|
|
34
|
+
top(): T | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Checks if the stack is empty.
|
|
37
|
+
*
|
|
38
|
+
* @returns True if the stack contains no elements, false otherwise
|
|
39
|
+
*/
|
|
40
|
+
isEmpty(): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Returns the number of elements in the stack.
|
|
43
|
+
*
|
|
44
|
+
* @returns The size of the stack
|
|
45
|
+
*/
|
|
46
|
+
get size(): number;
|
|
47
|
+
/**
|
|
48
|
+
* Returns the number of elements in the stack.
|
|
49
|
+
* Alias for size property.
|
|
50
|
+
*
|
|
51
|
+
* @returns The length of the stack
|
|
52
|
+
*/
|
|
53
|
+
get length(): number;
|
|
54
|
+
/**
|
|
55
|
+
* Removes all elements from the stack.
|
|
56
|
+
*/
|
|
57
|
+
clear(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Removes the first element that matches the predicate function.
|
|
60
|
+
* Searches from top to bottom of the stack.
|
|
61
|
+
*
|
|
62
|
+
* @param predicate Function that tests each element for removal
|
|
63
|
+
* @returns True if an element was removed, false if no match was found
|
|
64
|
+
*/
|
|
65
|
+
delete(predicate: (item: T) => boolean): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Returns a shallow copy of the stack as an array.
|
|
68
|
+
* The first element in the array represents the bottom of the stack.
|
|
69
|
+
*
|
|
70
|
+
* @returns A copy of the internal array
|
|
71
|
+
*/
|
|
72
|
+
toArray(): T[];
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new stack from an array of items.
|
|
75
|
+
* The first element in the array becomes the bottom of the stack.
|
|
76
|
+
*
|
|
77
|
+
* @param items Array of items to initialize the stack with
|
|
78
|
+
* @returns A new Stack instance
|
|
79
|
+
*/
|
|
80
|
+
static fromArray<U>(items: U[]): Stack<U>;
|
|
81
|
+
/**
|
|
82
|
+
* Returns a string representation of the stack.
|
|
83
|
+
*
|
|
84
|
+
* @returns String representation showing stack contents
|
|
85
|
+
*/
|
|
86
|
+
toString(): string;
|
|
87
|
+
/**
|
|
88
|
+
* Allows iteration over the stack from top to bottom.
|
|
89
|
+
*
|
|
90
|
+
* @returns Iterator that yields elements from top to bottom
|
|
91
|
+
*/
|
|
92
|
+
[Symbol.iterator](): Iterator<T>;
|
|
93
|
+
/**
|
|
94
|
+
* Returns an iterator that yields elements from bottom to top.
|
|
95
|
+
*
|
|
96
|
+
* @returns Iterator that yields elements from bottom to top
|
|
97
|
+
*/
|
|
98
|
+
bottomToTop(): Iterator<T>;
|
|
99
|
+
}
|
package/dist/Stack.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A generic stack implementation providing standard stack operations.
|
|
3
|
+
* Follows LIFO (Last In, First Out) principle.
|
|
4
|
+
*
|
|
5
|
+
* @template T The type of elements stored in the stack
|
|
6
|
+
*/
|
|
7
|
+
export class Stack {
|
|
8
|
+
#items = [];
|
|
9
|
+
/**
|
|
10
|
+
* Adds an element to the top of the stack.
|
|
11
|
+
*
|
|
12
|
+
* @param item The item to push onto the stack
|
|
13
|
+
* @returns The new size of the stack
|
|
14
|
+
*/
|
|
15
|
+
push(item) {
|
|
16
|
+
return this.#items.push(item);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Removes and returns the top element from the stack.
|
|
20
|
+
*
|
|
21
|
+
* @returns The top element, or undefined if the stack is empty
|
|
22
|
+
*/
|
|
23
|
+
pop() {
|
|
24
|
+
return this.#items.pop();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns the top element without removing it.
|
|
28
|
+
*
|
|
29
|
+
* @returns The top element, or undefined if the stack is empty
|
|
30
|
+
*/
|
|
31
|
+
peek() {
|
|
32
|
+
return this.#items[this.#items.length - 1];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns the top element without removing it.
|
|
36
|
+
* Alias for peek() method.
|
|
37
|
+
*
|
|
38
|
+
* @returns The top element, or undefined if the stack is empty
|
|
39
|
+
*/
|
|
40
|
+
top() {
|
|
41
|
+
return this.peek();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Checks if the stack is empty.
|
|
45
|
+
*
|
|
46
|
+
* @returns True if the stack contains no elements, false otherwise
|
|
47
|
+
*/
|
|
48
|
+
isEmpty() {
|
|
49
|
+
return this.#items.length === 0;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the number of elements in the stack.
|
|
53
|
+
*
|
|
54
|
+
* @returns The size of the stack
|
|
55
|
+
*/
|
|
56
|
+
get size() {
|
|
57
|
+
return this.#items.length;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns the number of elements in the stack.
|
|
61
|
+
* Alias for size property.
|
|
62
|
+
*
|
|
63
|
+
* @returns The length of the stack
|
|
64
|
+
*/
|
|
65
|
+
get length() {
|
|
66
|
+
return this.size;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Removes all elements from the stack.
|
|
70
|
+
*/
|
|
71
|
+
clear() {
|
|
72
|
+
this.#items = [];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Removes the first element that matches the predicate function.
|
|
76
|
+
* Searches from top to bottom of the stack.
|
|
77
|
+
*
|
|
78
|
+
* @param predicate Function that tests each element for removal
|
|
79
|
+
* @returns True if an element was removed, false if no match was found
|
|
80
|
+
*/
|
|
81
|
+
delete(predicate) {
|
|
82
|
+
for (let i = this.#items.length - 1; i >= 0; i--) {
|
|
83
|
+
if (predicate(this.#items[i])) {
|
|
84
|
+
this.#items.splice(i, 1);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Returns a shallow copy of the stack as an array.
|
|
92
|
+
* The first element in the array represents the bottom of the stack.
|
|
93
|
+
*
|
|
94
|
+
* @returns A copy of the internal array
|
|
95
|
+
*/
|
|
96
|
+
toArray() {
|
|
97
|
+
return [...this.#items];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Creates a new stack from an array of items.
|
|
101
|
+
* The first element in the array becomes the bottom of the stack.
|
|
102
|
+
*
|
|
103
|
+
* @param items Array of items to initialize the stack with
|
|
104
|
+
* @returns A new Stack instance
|
|
105
|
+
*/
|
|
106
|
+
static fromArray(items) {
|
|
107
|
+
const stack = new Stack();
|
|
108
|
+
stack.#items = [...items];
|
|
109
|
+
return stack;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Returns a string representation of the stack.
|
|
113
|
+
*
|
|
114
|
+
* @returns String representation showing stack contents
|
|
115
|
+
*/
|
|
116
|
+
toString() {
|
|
117
|
+
return `Stack[${this.#items.join(', ')}]`;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Allows iteration over the stack from top to bottom.
|
|
121
|
+
*
|
|
122
|
+
* @returns Iterator that yields elements from top to bottom
|
|
123
|
+
*/
|
|
124
|
+
*[Symbol.iterator]() {
|
|
125
|
+
for (let i = this.#items.length - 1; i >= 0; i--) {
|
|
126
|
+
yield this.#items[i];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Returns an iterator that yields elements from bottom to top.
|
|
131
|
+
*
|
|
132
|
+
* @returns Iterator that yields elements from bottom to top
|
|
133
|
+
*/
|
|
134
|
+
*bottomToTop() {
|
|
135
|
+
for (let i = 0; i < this.#items.length; i++) {
|
|
136
|
+
yield this.#items[i];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
package/dist/common.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const mountPieceKey: unique symbol;
|
package/dist/common.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const mountPieceKey = Symbol.for("collagejs.mountPiece");
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
5
|
+
<stop offset="0%" stop-color="#4F46E5"/>
|
|
6
|
+
<stop offset="100%" stop-color="#7C3AED"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="secondaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
9
|
+
<stop offset="0%" stop-color="#06B6D4"/>
|
|
10
|
+
<stop offset="100%" stop-color="#0EA5E9"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
13
|
+
<stop offset="0%" stop-color="#10B981"/>
|
|
14
|
+
<stop offset="100%" stop-color="#059669"/>
|
|
15
|
+
</linearGradient>
|
|
16
|
+
<linearGradient id="warningGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
17
|
+
<stop offset="0%" stop-color="#F59E0B"/>
|
|
18
|
+
<stop offset="100%" stop-color="#D97706"/>
|
|
19
|
+
</linearGradient>
|
|
20
|
+
<filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
21
|
+
<feDropShadow dx="1" dy="2" stdDeviation="2" flood-opacity="0.2"/>
|
|
22
|
+
</filter>
|
|
23
|
+
</defs>
|
|
24
|
+
|
|
25
|
+
<!-- No background - clean floating pieces -->
|
|
26
|
+
|
|
27
|
+
<!-- Simplified collage pieces -->
|
|
28
|
+
<!-- Main piece (top-left) -->
|
|
29
|
+
<path d="M20 30 L55 25 L60 45 L50 60 L30 55 L20 40 Z"
|
|
30
|
+
fill="url(#primaryGrad)"
|
|
31
|
+
filter="url(#dropShadow)"
|
|
32
|
+
opacity="0.9"/>
|
|
33
|
+
|
|
34
|
+
<!-- Secondary piece (top-right) -->
|
|
35
|
+
<path d="M70 20 L105 30 L100 50 L90 45 L80 35 L70 30 Z"
|
|
36
|
+
fill="url(#secondaryGrad)"
|
|
37
|
+
filter="url(#dropShadow)"
|
|
38
|
+
opacity="0.85"/>
|
|
39
|
+
|
|
40
|
+
<!-- Third piece (center-left) -->
|
|
41
|
+
<path d="M15 65 L45 60 L50 80 L40 90 L25 85 L15 75 Z"
|
|
42
|
+
fill="url(#accentGrad)"
|
|
43
|
+
filter="url(#dropShadow)"
|
|
44
|
+
opacity="0.8"/>
|
|
45
|
+
|
|
46
|
+
<!-- Fourth piece (bottom-right) -->
|
|
47
|
+
<path d="M55 75 L95 80 L90 100 L75 105 L60 95 L55 85 Z"
|
|
48
|
+
fill="url(#warningGrad)"
|
|
49
|
+
filter="url(#dropShadow)"
|
|
50
|
+
opacity="0.85"/>
|
|
51
|
+
|
|
52
|
+
<!-- Small connecting dots for detail -->
|
|
53
|
+
<circle cx="60" cy="50" r="4" fill="url(#secondaryGrad)" opacity="0.8"/>
|
|
54
|
+
<circle cx="80" cy="65" r="3" fill="url(#accentGrad)" opacity="0.8"/>
|
|
55
|
+
|
|
56
|
+
<!-- Central JS text with enhanced visibility -->
|
|
57
|
+
<text x="64" y="74"
|
|
58
|
+
font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
|
|
59
|
+
font-size="24"
|
|
60
|
+
font-weight="700"
|
|
61
|
+
text-anchor="middle"
|
|
62
|
+
fill="url(#primaryGrad)"
|
|
63
|
+
stroke="#FFFFFF"
|
|
64
|
+
stroke-width="1"
|
|
65
|
+
paint-order="stroke fill">JS</text>
|
|
66
|
+
</svg>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
5
|
+
<stop offset="0%" stop-color="#4F46E5"/>
|
|
6
|
+
<stop offset="100%" stop-color="#7C3AED"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="warningGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
9
|
+
<stop offset="0%" stop-color="#F59E0B"/>
|
|
10
|
+
<stop offset="100%" stop-color="#D97706"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
</defs>
|
|
13
|
+
|
|
14
|
+
<!-- Pure geometric representation -->
|
|
15
|
+
<path d="M3 4 L7 3 L8 6 L6 8 L4 7 L3 5 Z" fill="url(#primaryGrad)" opacity="0.9"/>
|
|
16
|
+
<path d="M9 3 L13 4 L12 7 L10 6 L9 5 Z" fill="#06B6D4" opacity="0.8"/>
|
|
17
|
+
<path d="M2 9 L6 8 L7 11 L5 13 L3 12 L2 10 Z" fill="#10B981" opacity="0.8"/>
|
|
18
|
+
<rect x="8" y="9" width="6" height="4" rx="1" fill="url(#warningGrad)" opacity="0.8"/>
|
|
19
|
+
</svg>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
5
|
+
<stop offset="0%" stop-color="#4F46E5"/>
|
|
6
|
+
<stop offset="100%" stop-color="#7C3AED"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="secondaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
9
|
+
<stop offset="0%" stop-color="#06B6D4"/>
|
|
10
|
+
<stop offset="100%" stop-color="#0EA5E9"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
13
|
+
<stop offset="0%" stop-color="#10B981"/>
|
|
14
|
+
<stop offset="100%" stop-color="#059669"/>
|
|
15
|
+
</linearGradient>
|
|
16
|
+
<linearGradient id="warningGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
17
|
+
<stop offset="0%" stop-color="#F59E0B"/>
|
|
18
|
+
<stop offset="100%" stop-color="#D97706"/>
|
|
19
|
+
</linearGradient>
|
|
20
|
+
</defs>
|
|
21
|
+
|
|
22
|
+
<!-- No background - ultra minimal -->
|
|
23
|
+
|
|
24
|
+
<!-- Very simplified geometric shapes -->
|
|
25
|
+
<path d="M8 12 L20 10 L22 18 L18 22 L12 20 L8 16 Z"
|
|
26
|
+
fill="url(#primaryGrad)"
|
|
27
|
+
opacity="0.9"/>
|
|
28
|
+
|
|
29
|
+
<path d="M26 8 L38 12 L36 20 L32 18 L28 14 L26 12 Z"
|
|
30
|
+
fill="url(#secondaryGrad)"
|
|
31
|
+
opacity="0.85"/>
|
|
32
|
+
|
|
33
|
+
<path d="M6 26 L18 24 L20 32 L16 36 L10 34 L6 30 Z"
|
|
34
|
+
fill="url(#accentGrad)"
|
|
35
|
+
opacity="0.8"/>
|
|
36
|
+
|
|
37
|
+
<rect x="24" y="28" width="16" height="12" rx="2"
|
|
38
|
+
fill="url(#warningGrad)"
|
|
39
|
+
opacity="0.85"/>
|
|
40
|
+
|
|
41
|
+
<!-- Enhanced JS text with stroke -->
|
|
42
|
+
<text x="24" y="28"
|
|
43
|
+
font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
|
|
44
|
+
font-size="10"
|
|
45
|
+
font-weight="700"
|
|
46
|
+
text-anchor="middle"
|
|
47
|
+
fill="#FFFFFF"
|
|
48
|
+
stroke="url(#primaryGrad)"
|
|
49
|
+
stroke-width="0.5">JS</text>
|
|
50
|
+
</svg>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<defs>
|
|
4
|
+
<!-- Gradients for depth and modern look -->
|
|
5
|
+
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
6
|
+
<stop offset="0%" stop-color="#4F46E5"/>
|
|
7
|
+
<stop offset="100%" stop-color="#7C3AED"/>
|
|
8
|
+
</linearGradient>
|
|
9
|
+
<linearGradient id="secondaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
10
|
+
<stop offset="0%" stop-color="#06B6D4"/>
|
|
11
|
+
<stop offset="100%" stop-color="#0EA5E9"/>
|
|
12
|
+
</linearGradient>
|
|
13
|
+
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
14
|
+
<stop offset="0%" stop-color="#10B981"/>
|
|
15
|
+
<stop offset="100%" stop-color="#059669"/>
|
|
16
|
+
</linearGradient>
|
|
17
|
+
<linearGradient id="warningGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
18
|
+
<stop offset="0%" stop-color="#F59E0B"/>
|
|
19
|
+
<stop offset="100%" stop-color="#D97706"/>
|
|
20
|
+
</linearGradient>
|
|
21
|
+
<!-- Drop shadows -->
|
|
22
|
+
<filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
23
|
+
<feDropShadow dx="4" dy="6" stdDeviation="8" flood-opacity="0.15"/>
|
|
24
|
+
</filter>
|
|
25
|
+
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
|
|
26
|
+
<feGaussianBlur stdDeviation="3" result="coloredBlur"/>
|
|
27
|
+
<feMerge>
|
|
28
|
+
<feMergeNode in="coloredBlur"/>
|
|
29
|
+
<feMergeNode in="SourceGraphic"/>
|
|
30
|
+
</feMerge>
|
|
31
|
+
</filter>
|
|
32
|
+
</defs>
|
|
33
|
+
|
|
34
|
+
<!-- No background - pieces float freely -->
|
|
35
|
+
|
|
36
|
+
<!-- Main collage pieces - representing micro-frontend components -->
|
|
37
|
+
<!-- Large primary piece (top-left) -->
|
|
38
|
+
<path d="M80 120 L220 100 L240 180 L200 240 L120 220 L80 160 Z"
|
|
39
|
+
fill="url(#primaryGrad)"
|
|
40
|
+
filter="url(#glow)"
|
|
41
|
+
opacity="0.95"/>
|
|
42
|
+
|
|
43
|
+
<!-- Secondary piece (top-right) -->
|
|
44
|
+
<path d="M280 80 L420 120 L400 200 L360 180 L320 140 L280 120 Z"
|
|
45
|
+
fill="url(#secondaryGrad)"
|
|
46
|
+
filter="url(#dropShadow)"
|
|
47
|
+
opacity="0.85"/>
|
|
48
|
+
|
|
49
|
+
<!-- Third piece (center-left) -->
|
|
50
|
+
<path d="M60 260 L180 240 L200 320 L160 360 L100 340 L60 300 Z"
|
|
51
|
+
fill="url(#accentGrad)"
|
|
52
|
+
filter="url(#dropShadow)"
|
|
53
|
+
opacity="0.8"/>
|
|
54
|
+
|
|
55
|
+
<!-- Fourth piece (bottom-center) -->
|
|
56
|
+
<path d="M220 300 L380 320 L360 400 L300 420 L240 380 L220 340 Z"
|
|
57
|
+
fill="url(#warningGrad)"
|
|
58
|
+
filter="url(#dropShadow)"
|
|
59
|
+
opacity="0.85"/>
|
|
60
|
+
|
|
61
|
+
<!-- Fifth piece (right) -->
|
|
62
|
+
<path d="M380 200 L460 240 L440 320 L400 300 L380 260 Z"
|
|
63
|
+
fill="url(#primaryGrad)"
|
|
64
|
+
filter="url(#dropShadow)"
|
|
65
|
+
opacity="0.7"/>
|
|
66
|
+
|
|
67
|
+
<!-- Small connecting pieces for detail -->
|
|
68
|
+
<circle cx="240" cy="200" r="16" fill="url(#secondaryGrad)" opacity="0.8"/>
|
|
69
|
+
<circle cx="320" cy="260" r="12" fill="url(#accentGrad)" opacity="0.8"/>
|
|
70
|
+
<circle cx="180" cy="300" r="10" fill="url(#primaryGrad)" opacity="0.8"/>
|
|
71
|
+
|
|
72
|
+
<!-- Stylized "JS" text with enhanced visibility -->
|
|
73
|
+
<g transform="translate(256, 400)">
|
|
74
|
+
<text x="0" y="0"
|
|
75
|
+
font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
|
|
76
|
+
font-size="72"
|
|
77
|
+
font-weight="700"
|
|
78
|
+
text-anchor="middle"
|
|
79
|
+
fill="url(#primaryGrad)"
|
|
80
|
+
stroke="#FFFFFF"
|
|
81
|
+
stroke-width="2"
|
|
82
|
+
paint-order="stroke fill">JS</text>
|
|
83
|
+
</g>
|
|
84
|
+
|
|
85
|
+
<!-- CollageJS text -->
|
|
86
|
+
<g transform="translate(256, 450)">
|
|
87
|
+
<text x="0" y="0"
|
|
88
|
+
font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
|
|
89
|
+
font-size="28"
|
|
90
|
+
font-weight="500"
|
|
91
|
+
text-anchor="middle"
|
|
92
|
+
fill="#374151">Collage</text>
|
|
93
|
+
</g>
|
|
94
|
+
|
|
95
|
+
<!-- Subtle connection lines showing pieces working together -->
|
|
96
|
+
<line x1="150" y1="160" x2="200" y2="200" stroke="url(#primaryGrad)" stroke-width="3" opacity="0.3"/>
|
|
97
|
+
<line x1="280" y1="140" x2="320" y2="180" stroke="url(#secondaryGrad)" stroke-width="3" opacity="0.3"/>
|
|
98
|
+
<line x1="200" y1="280" x2="280" y2="300" stroke="url(#accentGrad)" stroke-width="3" opacity="0.3"/>
|
|
99
|
+
</svg>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
5
|
+
<stop offset="0%" stop-color="#4F46E5"/>
|
|
6
|
+
<stop offset="100%" stop-color="#7C3AED"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="secondaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
9
|
+
<stop offset="0%" stop-color="#06B6D4"/>
|
|
10
|
+
<stop offset="100%" stop-color="#0EA5E9"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
13
|
+
<stop offset="0%" stop-color="#10B981"/>
|
|
14
|
+
<stop offset="100%" stop-color="#059669"/>
|
|
15
|
+
</linearGradient>
|
|
16
|
+
<linearGradient id="warningGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
17
|
+
<stop offset="0%" stop-color="#F59E0B"/>
|
|
18
|
+
<stop offset="100%" stop-color="#D97706"/>
|
|
19
|
+
</linearGradient>
|
|
20
|
+
</defs>
|
|
21
|
+
|
|
22
|
+
<!-- No background - minimal clean design -->
|
|
23
|
+
|
|
24
|
+
<!-- Simplified geometric pieces -->
|
|
25
|
+
<path d="M10 15 L28 12 L30 22 L25 30 L15 28 L10 20 Z"
|
|
26
|
+
fill="url(#primaryGrad)"
|
|
27
|
+
opacity="0.9"/>
|
|
28
|
+
|
|
29
|
+
<path d="M35 10 L52 15 L50 25 L45 22 L40 17 L35 15 Z"
|
|
30
|
+
fill="url(#secondaryGrad)"
|
|
31
|
+
opacity="0.85"/>
|
|
32
|
+
|
|
33
|
+
<path d="M8 32 L22 30 L25 40 L20 45 L12 42 L8 37 Z"
|
|
34
|
+
fill="url(#accentGrad)"
|
|
35
|
+
opacity="0.8"/>
|
|
36
|
+
|
|
37
|
+
<path d="M28 37 L47 40 L45 50 L37 52 L30 47 L28 42 Z"
|
|
38
|
+
fill="url(#warningGrad)"
|
|
39
|
+
opacity="0.85"/>
|
|
40
|
+
|
|
41
|
+
<!-- Small connecting dot for detail -->
|
|
42
|
+
<circle cx="40" cy="32" r="2" fill="url(#secondaryGrad)" opacity="0.8"/>
|
|
43
|
+
|
|
44
|
+
<!-- Central JS with stroke for visibility -->
|
|
45
|
+
<text x="32" y="37"
|
|
46
|
+
font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
|
|
47
|
+
font-size="12"
|
|
48
|
+
font-weight="700"
|
|
49
|
+
text-anchor="middle"
|
|
50
|
+
fill="url(#primaryGrad)"
|
|
51
|
+
stroke="#FFFFFF"
|
|
52
|
+
stroke-width="0.8"
|
|
53
|
+
paint-order="stroke fill">JS</text>
|
|
54
|
+
</svg>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="256" height="256" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
5
|
+
<stop offset="0%" stop-color="#4F46E5"/>
|
|
6
|
+
<stop offset="100%" stop-color="#7C3AED"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="secondaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
9
|
+
<stop offset="0%" stop-color="#06B6D4"/>
|
|
10
|
+
<stop offset="100%" stop-color="#0EA5E9"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
13
|
+
<stop offset="0%" stop-color="#10B981"/>
|
|
14
|
+
<stop offset="100%" stop-color="#059669"/>
|
|
15
|
+
</linearGradient>
|
|
16
|
+
<linearGradient id="warningGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
17
|
+
<stop offset="0%" stop-color="#F59E0B"/>
|
|
18
|
+
<stop offset="100%" stop-color="#D97706"/>
|
|
19
|
+
</linearGradient>
|
|
20
|
+
<filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
21
|
+
<feDropShadow dx="2" dy="3" stdDeviation="4" flood-opacity="0.15"/>
|
|
22
|
+
</filter>
|
|
23
|
+
</defs>
|
|
24
|
+
|
|
25
|
+
<!-- Subtle universal background -->
|
|
26
|
+
<defs>
|
|
27
|
+
<radialGradient id="universalBg" cx="50%" cy="50%" r="70%">
|
|
28
|
+
<stop offset="0%" stop-color="#F8FAFC" stop-opacity="0.9"/>
|
|
29
|
+
<stop offset="100%" stop-color="#E2E8F0" stop-opacity="0.7"/>
|
|
30
|
+
</radialGradient>
|
|
31
|
+
</defs>
|
|
32
|
+
<rect width="256" height="256" fill="url(#universalBg)"/>
|
|
33
|
+
|
|
34
|
+
<!-- Stylized collage pieces arranged in a pleasing composition -->
|
|
35
|
+
<path d="M40 60 L110 50 L120 90 L100 120 L60 110 L40 80 Z"
|
|
36
|
+
fill="url(#primaryGrad)"
|
|
37
|
+
filter="url(#dropShadow)"
|
|
38
|
+
opacity="0.9"/>
|
|
39
|
+
|
|
40
|
+
<path d="M140 40 L210 60 L200 100 L180 90 L160 70 L140 60 Z"
|
|
41
|
+
fill="url(#secondaryGrad)"
|
|
42
|
+
filter="url(#dropShadow)"
|
|
43
|
+
opacity="0.85"/>
|
|
44
|
+
|
|
45
|
+
<path d="M30 130 L90 120 L100 160 L80 180 L50 170 L30 150 Z"
|
|
46
|
+
fill="url(#accentGrad)"
|
|
47
|
+
filter="url(#dropShadow)"
|
|
48
|
+
opacity="0.8"/>
|
|
49
|
+
|
|
50
|
+
<path d="M110 150 L190 160 L180 200 L150 210 L120 190 L110 170 Z"
|
|
51
|
+
fill="url(#warningGrad)"
|
|
52
|
+
filter="url(#dropShadow)"
|
|
53
|
+
opacity="0.85"/>
|
|
54
|
+
|
|
55
|
+
<path d="M190 100 L230 120 L220 160 L200 150 L190 130 Z"
|
|
56
|
+
fill="url(#primaryGrad)"
|
|
57
|
+
filter="url(#dropShadow)"
|
|
58
|
+
opacity="0.7"/>
|
|
59
|
+
|
|
60
|
+
<!-- Central focus point -->
|
|
61
|
+
<circle cx="128" cy="128" r="8" fill="url(#secondaryGrad)" opacity="0.8"/>
|
|
62
|
+
|
|
63
|
+
<!-- Clean, modern "JS" -->
|
|
64
|
+
<text x="128" y="145"
|
|
65
|
+
font-family="'SF Pro Display', 'Segoe UI', -apple-system, sans-serif"
|
|
66
|
+
font-size="36"
|
|
67
|
+
font-weight="700"
|
|
68
|
+
text-anchor="middle"
|
|
69
|
+
fill="url(#primaryGrad)">JS</text>
|
|
70
|
+
</svg>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare module "@collagejs/core/logo/16" {
|
|
2
|
+
const content: string;
|
|
3
|
+
export default content;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
declare module "@collagejs/core/logo/48" {
|
|
7
|
+
const content: string;
|
|
8
|
+
export default content;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare module "@collagejs/core/logo/64" {
|
|
12
|
+
const content: string;
|
|
13
|
+
export default content;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare module "@collagejs/core/logo/128" {
|
|
17
|
+
const content: string;
|
|
18
|
+
export default content;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare module "@collagejs/core/logo/512" {
|
|
22
|
+
const content: string;
|
|
23
|
+
export default content;
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MountedPiece } from "./MountedPiece.js";
|
|
2
|
+
import type { CorePiece } from "./types.js";
|
|
3
|
+
export declare function mountPieceCore<TProps extends Record<string, any> = Record<string, any>>(this: MountedPiece | undefined, piece: CorePiece<TProps>, target: HTMLElement, props?: TProps): Promise<MountedPiece<TProps>>;
|
|
4
|
+
/**
|
|
5
|
+
* Mounts the CollageJS piece as a child of the target element.
|
|
6
|
+
* @param piece The CollageJS piece to mount.
|
|
7
|
+
* @param target The target element to mount the piece to.
|
|
8
|
+
* @param props The properties to pass to the piece.
|
|
9
|
+
*/
|
|
10
|
+
export declare function mountPiece<TProps extends Record<string, any> = Record<string, any>>(piece: CorePiece<TProps>, target: HTMLElement, props?: TProps): Promise<import("./types.js").MountedPiece<TProps>>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MountedPiece, mountKey } from "./MountedPiece.js";
|
|
2
|
+
export async function mountPieceCore(piece, target, props) {
|
|
3
|
+
const mp = new MountedPiece(piece, (mountPieceCore), this);
|
|
4
|
+
await mp[mountKey](target, props);
|
|
5
|
+
return mp;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Mounts the CollageJS piece as a child of the target element.
|
|
9
|
+
* @param piece The CollageJS piece to mount.
|
|
10
|
+
* @param target The target element to mount the piece to.
|
|
11
|
+
* @param props The properties to pass to the piece.
|
|
12
|
+
*/
|
|
13
|
+
export function mountPiece(piece, target, props) {
|
|
14
|
+
return (mountPieceCore.bind(undefined))(piece, target, props);
|
|
15
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type MountProps<TProps extends Record<string, any> = Record<string, any>> = TProps & {
|
|
2
|
+
[x: symbol]: MountPiece<TProps>;
|
|
3
|
+
};
|
|
4
|
+
export type UnmountFn = () => Promise<void>;
|
|
5
|
+
export type MountFn<TProps extends Record<string, any> = Record<string, any>> = (target: HTMLElement, props?: MountProps<TProps>) => Promise<UnmountFn>;
|
|
6
|
+
export type UpdateFn<TProps extends Record<string, any> = Record<string, any>> = (props: TProps) => Promise<void>;
|
|
7
|
+
export type Mount<TProps extends Record<string, any> = Record<string, any>> = MountFn<TProps> | MountFn<TProps>[] | Mount<TProps>[];
|
|
8
|
+
export type Update<TProps extends Record<string, any> = Record<string, any>> = UpdateFn<TProps> | UpdateFn<TProps>[] | Update[];
|
|
9
|
+
export interface CorePiece<TProps extends Record<string, any> = Record<string, any>> {
|
|
10
|
+
mount: Mount<TProps>;
|
|
11
|
+
update?: Update<TProps>;
|
|
12
|
+
}
|
|
13
|
+
export type FactoryFnUntyped = () => Promise<CorePiece>;
|
|
14
|
+
export type Factories = Record<string, FactoryFnUntyped>;
|
|
15
|
+
export type CollageModule = {
|
|
16
|
+
bootstrap: UnmountFn;
|
|
17
|
+
unload: UnmountFn;
|
|
18
|
+
factories: Factories;
|
|
19
|
+
};
|
|
20
|
+
export interface MountedPiece<TProps extends Record<string, any> = Record<string, any>> {
|
|
21
|
+
update: UpdateFn<TProps>;
|
|
22
|
+
unmount: UnmountFn;
|
|
23
|
+
mountPiece: MountPiece<TProps>;
|
|
24
|
+
}
|
|
25
|
+
export type MountPiece<TProps extends Record<string, any> = Record<string, any>> = (piece: CorePiece<TProps>, target: HTMLElement, props?: TProps) => Promise<MountedPiece<TProps>>;
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@collagejs/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core functionality for CollageJS.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "npm run test:unit && npm run test:types",
|
|
9
|
+
"test:unit": "ts-mocha -n loader=ts-node/esm -p ./tsconfig.json --require ./tests/setup.ts ./tests/ut/**/*.test.ts",
|
|
10
|
+
"test:watch": "ts-mocha -n loader=ts-node/esm -p ./tsconfig.json --require ./tests/setup.ts ./tests/ut/**/*.test.ts --watch",
|
|
11
|
+
"test:types": "tstyche ./tests/typetests",
|
|
12
|
+
"build": "tsc && pwsh -File ./post-build.ps1 && publint",
|
|
13
|
+
"check": "tsc --noEmit"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"collage",
|
|
17
|
+
"collage-js",
|
|
18
|
+
"single-spa",
|
|
19
|
+
"micro-frontend"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/collagejs/core.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/collagejs/core/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://collagejs.dev",
|
|
29
|
+
"author": {
|
|
30
|
+
"email": "webJose@gmail.com",
|
|
31
|
+
"name": "José Pablo Ramírez Vargas"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"import": "./dist/index.js",
|
|
38
|
+
"default": "./dist/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./logo/16": {
|
|
41
|
+
"types": "./dist/logos/logo.d.ts",
|
|
42
|
+
"default": "./dist/logos/collagejs-16.svg"
|
|
43
|
+
},
|
|
44
|
+
"./logo/48": {
|
|
45
|
+
"types": "./dist/logos/logo.d.ts",
|
|
46
|
+
"default": "./dist/logos/collagejs-48.svg"
|
|
47
|
+
},
|
|
48
|
+
"./logo/64": {
|
|
49
|
+
"types": "./dist/logos/logo.d.ts",
|
|
50
|
+
"default": "./dist/logos/collagejs-64.svg"
|
|
51
|
+
},
|
|
52
|
+
"./logo/128": {
|
|
53
|
+
"types": "./dist/logos/logo.d.ts",
|
|
54
|
+
"default": "./dist/logos/collagejs-128.svg"
|
|
55
|
+
},
|
|
56
|
+
"./logo/512": {
|
|
57
|
+
"types": "./dist/logos/logo.d.ts",
|
|
58
|
+
"default": "./dist/logos/collagejs-512.svg"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist"
|
|
63
|
+
],
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/chai": "^5.2.2",
|
|
66
|
+
"@types/jsdom": "^27.0.0",
|
|
67
|
+
"@types/mocha": "^10.0.10",
|
|
68
|
+
"@types/node": "^25.0.1",
|
|
69
|
+
"@types/sinon": "^21.0.0",
|
|
70
|
+
"chai": "^6.0.1",
|
|
71
|
+
"jsdom": "^27.3.0",
|
|
72
|
+
"mocha": "^11.7.2",
|
|
73
|
+
"publint": "^0.3.11",
|
|
74
|
+
"sinon": "^21.0.0",
|
|
75
|
+
"ts-mocha": "^11.1.0",
|
|
76
|
+
"ts-node": "^10.9.2",
|
|
77
|
+
"tstyche": "^5.0.2",
|
|
78
|
+
"typescript": "^5.8.2"
|
|
79
|
+
}
|
|
80
|
+
}
|