@elyndra/astro-frames 1.2.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/package.json +60 -0
- package/src/FrameBase/FrameBase.astro +33 -0
- package/src/FrameBase/FrameBase.test.ts +15 -0
- package/src/FrameCircle/FrameCircle.astro +33 -0
- package/src/FrameCircle/FrameCircle.test.ts +15 -0
- package/src/FrameCorners/FrameCorners.astro +33 -0
- package/src/FrameCorners/FrameCorners.test.ts +15 -0
- package/src/FrameHeader/FrameHeader.astro +33 -0
- package/src/FrameHeader/FrameHeader.test.ts +15 -0
- package/src/FrameKranox/FrameKranox.astro +33 -0
- package/src/FrameKranox/FrameKranox.test.ts +15 -0
- package/src/FrameLines/FrameLines.astro +33 -0
- package/src/FrameLines/FrameLines.test.ts +15 -0
- package/src/FrameNefrex/FrameNefrex.astro +33 -0
- package/src/FrameNefrex/FrameNefrex.test.ts +15 -0
- package/src/FrameNero/FrameNero.astro +33 -0
- package/src/FrameNero/FrameNero.test.ts +15 -0
- package/src/FrameOctagon/FrameOctagon.astro +33 -0
- package/src/FrameOctagon/FrameOctagon.test.ts +15 -0
- package/src/FrameUnderline/FrameUnderline.astro +33 -0
- package/src/FrameUnderline/FrameUnderline.test.ts +15 -0
- package/src/astro.d.ts +7 -0
- package/src/client/frameClient.test.ts +92 -0
- package/src/client/frameClient.ts +186 -0
- package/src/index.ts +2 -0
- package/src/testUtils/index.ts +1 -0
- package/src/testUtils/renderComponent.ts +16 -0
- package/src/types.ts +100 -0
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elyndra/astro-frames",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"sideEffects": false,
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"description": "Elyndra frames components for Astro (SSR shells with vanilla client hydration)",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"elyndra",
|
|
11
|
+
"ui",
|
|
12
|
+
"front-end",
|
|
13
|
+
"framework",
|
|
14
|
+
"scifi",
|
|
15
|
+
"sci-fi",
|
|
16
|
+
"science-fiction",
|
|
17
|
+
"astro"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://elyndra.dev",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/Gabox301/elyndra.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/Gabox301/elyndra/issues"
|
|
26
|
+
},
|
|
27
|
+
"funding": "https://github.com/sponsors/romelperez",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"files": [
|
|
30
|
+
"src"
|
|
31
|
+
],
|
|
32
|
+
"exports": {
|
|
33
|
+
".": "./src/index.ts",
|
|
34
|
+
"./FrameBase": "./src/FrameBase/FrameBase.astro",
|
|
35
|
+
"./FrameCircle": "./src/FrameCircle/FrameCircle.astro",
|
|
36
|
+
"./FrameCorners": "./src/FrameCorners/FrameCorners.astro",
|
|
37
|
+
"./FrameHeader": "./src/FrameHeader/FrameHeader.astro",
|
|
38
|
+
"./FrameKranox": "./src/FrameKranox/FrameKranox.astro",
|
|
39
|
+
"./FrameLines": "./src/FrameLines/FrameLines.astro",
|
|
40
|
+
"./FrameNefrex": "./src/FrameNefrex/FrameNefrex.astro",
|
|
41
|
+
"./FrameNero": "./src/FrameNero/FrameNero.astro",
|
|
42
|
+
"./FrameOctagon": "./src/FrameOctagon/FrameOctagon.astro",
|
|
43
|
+
"./FrameUnderline": "./src/FrameUnderline/FrameUnderline.astro",
|
|
44
|
+
"./client": "./src/client/frameClient.ts"
|
|
45
|
+
},
|
|
46
|
+
"types": "./src/index.ts",
|
|
47
|
+
"module": "./src/index.ts",
|
|
48
|
+
"main": "./src/index.ts",
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"astro": "7.3.2"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@elyndra/frames": "^1.2.0",
|
|
54
|
+
"@elyndra/tools": "^1.2.0",
|
|
55
|
+
"tslib": "2.8.1"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsc --noEmit -p tsconfig.json"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameBaseElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameBaseElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-base-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-base
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameBaseElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameBaseElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameBase from './FrameBase.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render children inside the frame base shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameBase, {
|
|
10
|
+
slots: { default: '<g><circle /></g>' },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-base');
|
|
14
|
+
expect(html).toContain('initFrameBaseElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameCircleElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameCircleElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-circle-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-circle
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameCircleElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameCircleElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameCircle from './FrameCircle.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame circle shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameCircle, {
|
|
10
|
+
props: { padding: 4 },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-circle');
|
|
14
|
+
expect(html).toContain('initFrameCircleElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameCornersElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameCornersElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-corners-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-corners
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameCornersElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameCornersElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameCorners from './FrameCorners.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame corners shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameCorners, {
|
|
10
|
+
props: { cornerLength: 8 },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-corners');
|
|
14
|
+
expect(html).toContain('initFrameCornersElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameHeaderElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameHeaderElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-header-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-header
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameHeaderElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameHeaderElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameHeader from './FrameHeader.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame header shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameHeader, {
|
|
10
|
+
props: { direction: 'vertical' },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-header');
|
|
14
|
+
expect(html).toContain('initFrameHeaderElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameKranoxElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameKranoxElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-kranox-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-kranox
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameKranoxElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameKranoxElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameKranox from './FrameKranox.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame kranox shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameKranox, {
|
|
10
|
+
props: { squareSize: 8 },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-kranox');
|
|
14
|
+
expect(html).toContain('initFrameKranoxElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameLinesElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameLinesElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-lines-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-lines
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameLinesElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameLinesElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameLines from './FrameLines.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame lines shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameLines, {
|
|
10
|
+
props: { smallLineLength: 8 },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-lines');
|
|
14
|
+
expect(html).toContain('initFrameLinesElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameNefrexElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameNefrexElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-nefrex-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-nefrex
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameNefrexElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameNefrexElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameNefrex from './FrameNefrex.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame nefrex shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameNefrex, {
|
|
10
|
+
props: { leftTop: false },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-nefrex');
|
|
14
|
+
expect(html).toContain('initFrameNefrexElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameNeroElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameNeroElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-nero-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-nero
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameNeroElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameNeroElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameNero from './FrameNero.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame nero shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameNero, {
|
|
10
|
+
props: { cornerLength: 8 },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-nero');
|
|
14
|
+
expect(html).toContain('initFrameNeroElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameOctagonElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameOctagonElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-octagon-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-octagon
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameOctagonElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameOctagonElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameOctagon from './FrameOctagon.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame octagon shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameOctagon, {
|
|
10
|
+
props: { squareSize: 8 },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-octagon');
|
|
14
|
+
expect(html).toContain('initFrameOctagonElement');
|
|
15
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { FrameUnderlineElementProps } from '../types.js';
|
|
3
|
+
|
|
4
|
+
interface Props extends FrameUnderlineElementProps {}
|
|
5
|
+
|
|
6
|
+
const { className, preserveAspectRatio = 'none', ...settings } = Astro.props as Props;
|
|
7
|
+
|
|
8
|
+
// Ids only need page-level uniqueness: the component script consumes them in
|
|
9
|
+
// the same render.
|
|
10
|
+
const nodeId = `elyndra-frame-underline-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
const serializable = { ...settings };
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<svg
|
|
15
|
+
id={nodeId}
|
|
16
|
+
data-elyndra-frame-underline
|
|
17
|
+
role="presentation"
|
|
18
|
+
class={className}
|
|
19
|
+
style="position: absolute; inset: 0; display: block; border: 0; margin: 0; padding: 0; width: 100%; height: 100%;"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
preserveAspectRatio={preserveAspectRatio}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</svg>
|
|
25
|
+
|
|
26
|
+
<script define:vars={{ nodeId, serializable }}>
|
|
27
|
+
import { initFrameUnderlineElement } from '../client/frameClient.js';
|
|
28
|
+
|
|
29
|
+
const element = document.getElementById(nodeId);
|
|
30
|
+
if (element instanceof SVGSVGElement) {
|
|
31
|
+
initFrameUnderlineElement(element, serializable);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Render tests assert on SSR strings, so they run in node: under jsdom the
|
|
3
|
+
// Astro plugin compiles `.astro` imports for the browser (client stub).
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { renderComponent } from '../testUtils/index.js';
|
|
6
|
+
import FrameUnderline from './FrameUnderline.astro';
|
|
7
|
+
|
|
8
|
+
test('Should render the frame underline shell', async () => {
|
|
9
|
+
const html = await renderComponent(FrameUnderline, {
|
|
10
|
+
props: { strokeWidth: 2 },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(html).toContain('data-elyndra-frame-underline');
|
|
14
|
+
expect(html).toContain('initFrameUnderlineElement');
|
|
15
|
+
});
|
package/src/astro.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// In-repo ambient types for `.astro` imports (tests only). The published
|
|
2
|
+
// package ships the `.astro` sources and consumers get full prop inference
|
|
3
|
+
// from the frontmatter `Props` interfaces via their own Astro setup.
|
|
4
|
+
declare module '*.astro' {
|
|
5
|
+
const Component: unknown;
|
|
6
|
+
export default Component;
|
|
7
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { beforeEach, expect, test, vi } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
initFrameAssemblerElement,
|
|
4
|
+
initFrameBaseElement,
|
|
5
|
+
initFrameCircleElement,
|
|
6
|
+
initFrameCornersElement,
|
|
7
|
+
initFrameHeaderElement,
|
|
8
|
+
initFrameKranoxElement,
|
|
9
|
+
initFrameLinesElement,
|
|
10
|
+
initFrameNefrexElement,
|
|
11
|
+
initFrameNeroElement,
|
|
12
|
+
initFrameOctagonElement,
|
|
13
|
+
initFrameUnderlineElement,
|
|
14
|
+
} from './frameClient.js';
|
|
15
|
+
|
|
16
|
+
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
document.body.innerHTML = '';
|
|
20
|
+
vi.unstubAllGlobals();
|
|
21
|
+
// jsdom has no ResizeObserver: the vanilla frame observes resizes, so the
|
|
22
|
+
// tests stub the constructor (observe/disconnect no-ops).
|
|
23
|
+
vi.stubGlobal(
|
|
24
|
+
'ResizeObserver',
|
|
25
|
+
class {
|
|
26
|
+
observe(): void {}
|
|
27
|
+
disconnect(): void {}
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const mountSVG = (): SVGSVGElement => {
|
|
33
|
+
const element = document.createElementNS(SVG_NAMESPACE, 'svg');
|
|
34
|
+
document.body.appendChild(element);
|
|
35
|
+
return element;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
test('Should render a static base frame and mark the node', () => {
|
|
39
|
+
const element = mountSVG();
|
|
40
|
+
|
|
41
|
+
const handle = initFrameBaseElement(element, { elements: [] });
|
|
42
|
+
|
|
43
|
+
expect(element.hasAttribute('data-elyndra-frame-node')).toBe(true);
|
|
44
|
+
expect(element.querySelector('[data-frame]')).not.toBeNull();
|
|
45
|
+
|
|
46
|
+
handle.dispose();
|
|
47
|
+
handle.dispose();
|
|
48
|
+
|
|
49
|
+
expect(element.hasAttribute('data-elyndra-frame-node')).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('Should render every named frame statically and unmark on dispose', () => {
|
|
53
|
+
const inits = [
|
|
54
|
+
() => initFrameCircleElement(mountSVG(), { animated: false }),
|
|
55
|
+
() => initFrameCornersElement(mountSVG(), { animated: false }),
|
|
56
|
+
() => initFrameHeaderElement(mountSVG(), { animated: false }),
|
|
57
|
+
() => initFrameKranoxElement(mountSVG(), { animated: false }),
|
|
58
|
+
() => initFrameLinesElement(mountSVG(), { animated: false }),
|
|
59
|
+
() => initFrameNefrexElement(mountSVG(), { animated: false }),
|
|
60
|
+
() => initFrameNeroElement(mountSVG(), { animated: false }),
|
|
61
|
+
() => initFrameOctagonElement(mountSVG(), { animated: false }),
|
|
62
|
+
() => initFrameUnderlineElement(mountSVG(), { animated: false }),
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
for (const init of inits) {
|
|
66
|
+
const handle = init();
|
|
67
|
+
const svg = document.body.lastElementChild;
|
|
68
|
+
expect(svg?.hasAttribute('data-elyndra-frame-node')).toBe(true);
|
|
69
|
+
handle.dispose();
|
|
70
|
+
expect(svg?.hasAttribute('data-elyndra-frame-node')).toBe(false);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('Should dispose the previous frame on second init', () => {
|
|
75
|
+
const element = mountSVG();
|
|
76
|
+
|
|
77
|
+
initFrameCircleElement(element, { animated: false });
|
|
78
|
+
initFrameCircleElement(element, { animated: false });
|
|
79
|
+
|
|
80
|
+
expect(element.hasAttribute('data-elyndra-frame-node')).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('Should run one assembly and cancel on dispose', () => {
|
|
84
|
+
const element = mountSVG();
|
|
85
|
+
|
|
86
|
+
const handle = initFrameAssemblerElement(element, { duration: 0.05, isEntering: true });
|
|
87
|
+
|
|
88
|
+
handle.dispose();
|
|
89
|
+
handle.dispose();
|
|
90
|
+
|
|
91
|
+
expect(element.hasAttribute('data-elyndra-frame-node')).toBe(false);
|
|
92
|
+
});
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Frame,
|
|
3
|
+
animateFrameAssembler,
|
|
4
|
+
createFrame,
|
|
5
|
+
createFrameCircleSettings,
|
|
6
|
+
createFrameCornersSettings,
|
|
7
|
+
createFrameHeaderSettings,
|
|
8
|
+
createFrameKranoxSettings,
|
|
9
|
+
createFrameLinesSettings,
|
|
10
|
+
createFrameNefrexSettings,
|
|
11
|
+
createFrameNeroSettings,
|
|
12
|
+
createFrameOctagonSettings,
|
|
13
|
+
createFrameUnderlineSettings,
|
|
14
|
+
} from '@elyndra/frames';
|
|
15
|
+
import { filterProps } from '@elyndra/tools';
|
|
16
|
+
import type {
|
|
17
|
+
FrameAssemblerSerializableSettings,
|
|
18
|
+
FrameBaseSerializableSettings,
|
|
19
|
+
FrameCircleSerializableSettings,
|
|
20
|
+
FrameCornersSerializableSettings,
|
|
21
|
+
FrameHeaderSerializableSettings,
|
|
22
|
+
FrameKranoxSerializableSettings,
|
|
23
|
+
FrameLinesSerializableSettings,
|
|
24
|
+
FrameNefrexSerializableSettings,
|
|
25
|
+
FrameNeroSerializableSettings,
|
|
26
|
+
FrameOctagonSerializableSettings,
|
|
27
|
+
FrameUnderlineSerializableSettings,
|
|
28
|
+
} from '../types.js';
|
|
29
|
+
|
|
30
|
+
const FRAME_NODE_MARKER = 'data-elyndra-frame-node';
|
|
31
|
+
|
|
32
|
+
interface FrameHandle {
|
|
33
|
+
readonly frame: Frame;
|
|
34
|
+
readonly dispose: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface FrameAssemblerHandle {
|
|
38
|
+
readonly dispose: () => void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const framesByElement = new WeakMap<Element, { dispose: () => void }>();
|
|
42
|
+
|
|
43
|
+
const initFrameElement = (element: SVGSVGElement, create: () => Frame): FrameHandle => {
|
|
44
|
+
framesByElement.get(element)?.dispose();
|
|
45
|
+
|
|
46
|
+
const frame = create();
|
|
47
|
+
|
|
48
|
+
element.setAttribute(FRAME_NODE_MARKER, '');
|
|
49
|
+
|
|
50
|
+
const handle: FrameHandle = {
|
|
51
|
+
frame,
|
|
52
|
+
dispose: () => {
|
|
53
|
+
if (framesByElement.get(element) !== handle) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
framesByElement.delete(element);
|
|
57
|
+
element.removeAttribute(FRAME_NODE_MARKER);
|
|
58
|
+
frame.remove();
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
framesByElement.set(element, handle);
|
|
63
|
+
|
|
64
|
+
return handle;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Hydrates one base frame: the shell `<svg>` itself is the vanilla target,
|
|
69
|
+
* islands run standalone (no animator join). Idempotent: re-running removes
|
|
70
|
+
* the previous frame first.
|
|
71
|
+
*/
|
|
72
|
+
const initFrameBaseElement = (
|
|
73
|
+
element: SVGSVGElement,
|
|
74
|
+
props: FrameBaseSerializableSettings,
|
|
75
|
+
): FrameHandle =>
|
|
76
|
+
initFrameElement(element, () =>
|
|
77
|
+
createFrame(element, {
|
|
78
|
+
elements: props.elements ?? [],
|
|
79
|
+
...filterProps({ contexts: props.contexts }),
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const initFrameCircleElement = (
|
|
84
|
+
element: SVGSVGElement,
|
|
85
|
+
props: FrameCircleSerializableSettings,
|
|
86
|
+
): FrameHandle =>
|
|
87
|
+
initFrameElement(element, () => createFrame(element, createFrameCircleSettings(filterProps(props))));
|
|
88
|
+
|
|
89
|
+
const initFrameCornersElement = (
|
|
90
|
+
element: SVGSVGElement,
|
|
91
|
+
props: FrameCornersSerializableSettings,
|
|
92
|
+
): FrameHandle =>
|
|
93
|
+
initFrameElement(element, () => createFrame(element, createFrameCornersSettings(filterProps(props))));
|
|
94
|
+
|
|
95
|
+
const initFrameHeaderElement = (
|
|
96
|
+
element: SVGSVGElement,
|
|
97
|
+
props: FrameHeaderSerializableSettings,
|
|
98
|
+
): FrameHandle =>
|
|
99
|
+
initFrameElement(element, () => createFrame(element, createFrameHeaderSettings(filterProps(props))));
|
|
100
|
+
|
|
101
|
+
const initFrameKranoxElement = (
|
|
102
|
+
element: SVGSVGElement,
|
|
103
|
+
props: FrameKranoxSerializableSettings,
|
|
104
|
+
): FrameHandle =>
|
|
105
|
+
initFrameElement(element, () => createFrame(element, createFrameKranoxSettings(filterProps(props))));
|
|
106
|
+
|
|
107
|
+
const initFrameLinesElement = (
|
|
108
|
+
element: SVGSVGElement,
|
|
109
|
+
props: FrameLinesSerializableSettings,
|
|
110
|
+
): FrameHandle =>
|
|
111
|
+
initFrameElement(element, () => createFrame(element, createFrameLinesSettings(filterProps(props))));
|
|
112
|
+
|
|
113
|
+
const initFrameNefrexElement = (
|
|
114
|
+
element: SVGSVGElement,
|
|
115
|
+
props: FrameNefrexSerializableSettings,
|
|
116
|
+
): FrameHandle =>
|
|
117
|
+
initFrameElement(element, () => createFrame(element, createFrameNefrexSettings(filterProps(props))));
|
|
118
|
+
|
|
119
|
+
const initFrameNeroElement = (
|
|
120
|
+
element: SVGSVGElement,
|
|
121
|
+
props: FrameNeroSerializableSettings,
|
|
122
|
+
): FrameHandle =>
|
|
123
|
+
initFrameElement(element, () => createFrame(element, createFrameNeroSettings(filterProps(props))));
|
|
124
|
+
|
|
125
|
+
const initFrameOctagonElement = (
|
|
126
|
+
element: SVGSVGElement,
|
|
127
|
+
props: FrameOctagonSerializableSettings,
|
|
128
|
+
): FrameHandle =>
|
|
129
|
+
initFrameElement(element, () => createFrame(element, createFrameOctagonSettings(filterProps(props))));
|
|
130
|
+
|
|
131
|
+
const initFrameUnderlineElement = (
|
|
132
|
+
element: SVGSVGElement,
|
|
133
|
+
props: FrameUnderlineSerializableSettings,
|
|
134
|
+
): FrameHandle =>
|
|
135
|
+
initFrameElement(element, () =>
|
|
136
|
+
createFrame(element, createFrameUnderlineSettings(filterProps(props))),
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Runs one frame assembly on an element (the island replacement for the
|
|
141
|
+
* `useFrameAssembler` hook: a single run instead of an animator
|
|
142
|
+
* subscription). Idempotent: re-running cancels the previous assembly
|
|
143
|
+
* first.
|
|
144
|
+
*/
|
|
145
|
+
const initFrameAssemblerElement = (
|
|
146
|
+
element: HTMLElement | SVGElement,
|
|
147
|
+
props: FrameAssemblerSerializableSettings,
|
|
148
|
+
): FrameAssemblerHandle => {
|
|
149
|
+
framesByElement.get(element)?.dispose();
|
|
150
|
+
|
|
151
|
+
const animation = animateFrameAssembler({
|
|
152
|
+
element,
|
|
153
|
+
duration: props.duration ?? 0.3,
|
|
154
|
+
isEntering: props.isEntering ?? true,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const handle: FrameAssemblerHandle = {
|
|
158
|
+
dispose: () => {
|
|
159
|
+
if (framesByElement.get(element) !== handle) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
framesByElement.delete(element);
|
|
163
|
+
animation.cancel();
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
framesByElement.set(element, handle);
|
|
168
|
+
|
|
169
|
+
return handle;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export {
|
|
173
|
+
FRAME_NODE_MARKER,
|
|
174
|
+
initFrameAssemblerElement,
|
|
175
|
+
initFrameBaseElement,
|
|
176
|
+
initFrameCircleElement,
|
|
177
|
+
initFrameCornersElement,
|
|
178
|
+
initFrameHeaderElement,
|
|
179
|
+
initFrameKranoxElement,
|
|
180
|
+
initFrameLinesElement,
|
|
181
|
+
initFrameNefrexElement,
|
|
182
|
+
initFrameNeroElement,
|
|
183
|
+
initFrameOctagonElement,
|
|
184
|
+
initFrameUnderlineElement,
|
|
185
|
+
};
|
|
186
|
+
export type { FrameAssemblerHandle, FrameHandle };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './renderComponent.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ContainerRenderOptions,
|
|
3
|
+
experimental_AstroContainer as AstroContainer,
|
|
4
|
+
} from 'astro/container';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Renders an `.astro` component to a string. In-repo `.astro` imports are
|
|
8
|
+
* `unknown` (ambient declaration, tests only), so the factory type is
|
|
9
|
+
* inferred from the container itself — no drift if Astro changes it.
|
|
10
|
+
*/
|
|
11
|
+
const renderComponent = async (component: unknown, options?: ContainerRenderOptions): Promise<string> => {
|
|
12
|
+
const container = await AstroContainer.create();
|
|
13
|
+
return container.renderToString(component as Parameters<typeof container.renderToString>[0], options);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export { renderComponent };
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreateFrameCircleSettingsProps,
|
|
3
|
+
CreateFrameCornersSettingsProps,
|
|
4
|
+
CreateFrameHeaderSettingsProps,
|
|
5
|
+
CreateFrameKranoxSettingsProps,
|
|
6
|
+
CreateFrameLinesSettingsProps,
|
|
7
|
+
CreateFrameNefrexSettingsProps,
|
|
8
|
+
CreateFrameNeroSettingsProps,
|
|
9
|
+
CreateFrameOctagonSettingsProps,
|
|
10
|
+
CreateFrameUnderlineSettingsProps,
|
|
11
|
+
FrameSettings,
|
|
12
|
+
} from '@elyndra/frames';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Serializable subsets of the frame settings. Only JSON crosses the Astro
|
|
16
|
+
* server/client boundary (`define:vars`):
|
|
17
|
+
* - `FrameBase` takes plain `elements`/`contexts`: `draw`/`path`/context
|
|
18
|
+
* `animate` function forms are excluded (static settings only).
|
|
19
|
+
* - Variant props (`CreateFrame*SettingsProps`) are already scalar-only.
|
|
20
|
+
* - Excluded everywhere: `animator` nodes (islands run standalone),
|
|
21
|
+
* `container` instances (the vanilla container is created internally),
|
|
22
|
+
* `elementRef` (the shell `<svg>` itself is hydrated), `useFrameAssembler`
|
|
23
|
+
* (hook: use `initFrameAssemblerElement` from the client entry instead).
|
|
24
|
+
*/
|
|
25
|
+
interface FrameBaseSerializableSettings {
|
|
26
|
+
elements?: FrameSettings['elements'];
|
|
27
|
+
contexts?: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface FrameBaseElementProps extends FrameBaseSerializableSettings {
|
|
31
|
+
className?: string;
|
|
32
|
+
preserveAspectRatio?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface FrameShellProps {
|
|
36
|
+
className?: string;
|
|
37
|
+
preserveAspectRatio?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type FrameCircleSerializableSettings = CreateFrameCircleSettingsProps;
|
|
41
|
+
interface FrameCircleElementProps extends FrameCircleSerializableSettings, FrameShellProps {}
|
|
42
|
+
|
|
43
|
+
type FrameCornersSerializableSettings = CreateFrameCornersSettingsProps;
|
|
44
|
+
interface FrameCornersElementProps extends FrameCornersSerializableSettings, FrameShellProps {}
|
|
45
|
+
|
|
46
|
+
type FrameHeaderSerializableSettings = CreateFrameHeaderSettingsProps;
|
|
47
|
+
interface FrameHeaderElementProps extends FrameHeaderSerializableSettings, FrameShellProps {}
|
|
48
|
+
|
|
49
|
+
type FrameKranoxSerializableSettings = CreateFrameKranoxSettingsProps;
|
|
50
|
+
interface FrameKranoxElementProps extends FrameKranoxSerializableSettings, FrameShellProps {}
|
|
51
|
+
|
|
52
|
+
type FrameLinesSerializableSettings = CreateFrameLinesSettingsProps;
|
|
53
|
+
interface FrameLinesElementProps extends FrameLinesSerializableSettings, FrameShellProps {}
|
|
54
|
+
|
|
55
|
+
type FrameNefrexSerializableSettings = CreateFrameNefrexSettingsProps;
|
|
56
|
+
interface FrameNefrexElementProps extends FrameNefrexSerializableSettings, FrameShellProps {}
|
|
57
|
+
|
|
58
|
+
type FrameNeroSerializableSettings = CreateFrameNeroSettingsProps;
|
|
59
|
+
interface FrameNeroElementProps extends FrameNeroSerializableSettings, FrameShellProps {}
|
|
60
|
+
|
|
61
|
+
type FrameOctagonSerializableSettings = CreateFrameOctagonSettingsProps;
|
|
62
|
+
interface FrameOctagonElementProps extends FrameOctagonSerializableSettings, FrameShellProps {}
|
|
63
|
+
|
|
64
|
+
type FrameUnderlineSerializableSettings = CreateFrameUnderlineSettingsProps;
|
|
65
|
+
interface FrameUnderlineElementProps extends FrameUnderlineSerializableSettings, FrameShellProps {}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Serializable settings for the assembler runner (the island replacement
|
|
69
|
+
* for the `useFrameAssembler` hook): a single entering/exiting assembly
|
|
70
|
+
* instead of an animator subscription.
|
|
71
|
+
*/
|
|
72
|
+
interface FrameAssemblerSerializableSettings {
|
|
73
|
+
duration?: number;
|
|
74
|
+
isEntering?: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type {
|
|
78
|
+
FrameAssemblerSerializableSettings,
|
|
79
|
+
FrameBaseElementProps,
|
|
80
|
+
FrameBaseSerializableSettings,
|
|
81
|
+
FrameCircleElementProps,
|
|
82
|
+
FrameCircleSerializableSettings,
|
|
83
|
+
FrameCornersElementProps,
|
|
84
|
+
FrameCornersSerializableSettings,
|
|
85
|
+
FrameHeaderElementProps,
|
|
86
|
+
FrameHeaderSerializableSettings,
|
|
87
|
+
FrameKranoxElementProps,
|
|
88
|
+
FrameKranoxSerializableSettings,
|
|
89
|
+
FrameLinesElementProps,
|
|
90
|
+
FrameLinesSerializableSettings,
|
|
91
|
+
FrameNefrexElementProps,
|
|
92
|
+
FrameNefrexSerializableSettings,
|
|
93
|
+
FrameNeroElementProps,
|
|
94
|
+
FrameNeroSerializableSettings,
|
|
95
|
+
FrameOctagonElementProps,
|
|
96
|
+
FrameOctagonSerializableSettings,
|
|
97
|
+
FrameShellProps,
|
|
98
|
+
FrameUnderlineElementProps,
|
|
99
|
+
FrameUnderlineSerializableSettings,
|
|
100
|
+
};
|