Skip to content
This repository was archived by the owner on Mar 1, 2023. It is now read-only.

Commit 80f19cf

Browse files
committed
feat(3in2): add component swapping support
1 parent 32c98a1 commit 80f19cf

File tree

6 files changed

+151
-33
lines changed

6 files changed

+151
-33
lines changed

3in2/component.html

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
<div {...attrs} ref:root>
2-
<svelte:component this="{Component}" />
3-
</div>
1+
<div {...attrs} ref:target />
42

53
<script>
64
export default {
@@ -15,20 +13,52 @@
1513
attrs : false,
1614
}),
1715

16+
methods : {
17+
instantiate() {
18+
const { component, props } = this.get();
19+
const { target } = this.refs;
20+
21+
// Cleanup any previous component instance first
22+
if(this.instance) {
23+
this.cleanup();
24+
}
25+
26+
if(!component || typeof component !== "function") {
27+
throw new Error("Invalid svelte3 component passed to wrapper");
28+
}
29+
30+
this.instance = new component({
31+
target,
32+
props,
33+
});
34+
},
35+
36+
cleanup() {
37+
this.instance.$destroy();
38+
this.instance = null;
39+
},
40+
},
41+
1842
oncreate() {
19-
const { component, props } = this.get();
43+
const { component } = this.get();
2044

21-
// TODO: someday this should support runtime setting/switching of the component value
22-
if(!component || typeof component !== "function") {
23-
throw new Error("Invalid svelte3 component passed to wrapper");
24-
}
45+
if(component) {
46+
this.instantiate();
47+
}
2548

26-
this.instance = new component({
27-
target : this.refs.root,
28-
props,
29-
});
49+
this.on("state", ({ changed, current }) => {
50+
if(changed.component) {
51+
this.instantiate();
3052

31-
this.on("state", ({ current }) => this.instance.$set(current.props));
53+
return;
54+
}
55+
56+
if(changed.props && this.instance) {
57+
this.instance.$set(current.props)
58+
59+
return;
60+
}
61+
});
3262
},
3363

3464
ondestroy() {

3in2/tests/__snapshots__/component.test.js.snap

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ exports[`3in2 component wrapper should render a svelte3 component 1`] = `
44
55
<div>
66
<p>
7-
The answer is a mystery
7+
a? a!
88
</p>
99
</div>
1010
@@ -14,7 +14,7 @@ exports[`3in2 component wrapper should render a svelte3 component w/ props 1`] =
1414
1515
<div>
1616
<p>
17-
The answer is 42
17+
a? A!
1818
</p>
1919
</div>
2020
@@ -27,7 +27,44 @@ exports[`3in2 component wrapper should set attributes on the wrapper element it
2727
data-foo="data-foo"
2828
>
2929
<p>
30-
The answer is a mystery
30+
a? a!
31+
</p>
32+
</div>
33+
34+
`;
35+
36+
exports[`3in2 component wrapper should support creation without a component 1`] = `
37+
38+
<div>
39+
</div>
40+
41+
`;
42+
43+
exports[`3in2 component wrapper should support creation without a component 2`] = `
44+
45+
<div>
46+
<p>
47+
B? b!
48+
</p>
49+
</div>
50+
51+
`;
52+
53+
exports[`3in2 component wrapper should support swapping out the svelte3 component 1`] = `
54+
55+
<div>
56+
<p>
57+
a? A!
58+
</p>
59+
</div>
60+
61+
`;
62+
63+
exports[`3in2 component wrapper should support swapping out the svelte3 component 2`] = `
64+
65+
<div>
66+
<p>
67+
B? b!
3168
</p>
3269
</div>
3370
@@ -39,7 +76,7 @@ exports[`3in2 component wrapper should update the svelte3 component when props c
3976
4077
<div>
4178
<p>
42-
The answer is 42
79+
a? A!
4380
</p>
4481
</div>
4582
@@ -49,7 +86,7 @@ exports[`3in2 component wrapper should update the svelte3 component when props c
4986
5087
<div>
5188
<p>
52-
The answer is science
89+
a? A2!
5390
</p>
5491
</div>
5592

3in2/tests/component.test.js

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const wait = require("p-immediate");
44

55
describe("3in2 component wrapper", () => {
66
const Wrapper = require("../component.html");
7-
const { default : Component } = require("./specimens/component.svelte");
7+
const { default : ComponentA } = require("./specimens/component-a.svelte");
8+
const { default : ComponentB } = require("./specimens/component-b.svelte");
89

910
let root;
1011

@@ -17,23 +18,28 @@ describe("3in2 component wrapper", () => {
1718
target : root,
1819

1920
data : {
20-
component : Component,
21+
component : ComponentA,
2122
},
2223
});
2324

2425
expect(root.innerHTML).toMatchSnapshot();
2526
});
2627

2728
it("should throw if not given a svelte3 component", async () => {
28-
expect(() => new Wrapper({ target : root })).toThrowErrorMatchingSnapshot();
29+
expect(() => new Wrapper({
30+
target : root,
31+
data : {
32+
component : true
33+
},
34+
})).toThrowErrorMatchingSnapshot();
2935
});
3036

3137
it("should destroy the svelte3 component when the wrapper is destroyed", async () => {
3238
const wrapper = new Wrapper({
3339
target : root,
3440

3541
data : {
36-
component : Component,
42+
component : ComponentA,
3743
},
3844
});
3945

@@ -47,10 +53,10 @@ describe("3in2 component wrapper", () => {
4753
target : root,
4854

4955
data : {
50-
component : Component,
56+
component : ComponentA,
5157

5258
props : {
53-
answer : "42",
59+
a : "A",
5460
},
5561
},
5662
});
@@ -63,10 +69,10 @@ describe("3in2 component wrapper", () => {
6369
target : root,
6470

6571
data : {
66-
component : Component,
72+
component : ComponentA,
6773

6874
props : {
69-
answer : "42",
75+
a : "A",
7076
},
7177
},
7278
});
@@ -75,10 +81,50 @@ describe("3in2 component wrapper", () => {
7581

7682
wrapper.set({
7783
props : {
78-
answer : "science",
84+
a : "A2",
85+
},
86+
});
87+
88+
await wait();
89+
90+
expect(root.innerHTML).toMatchSnapshot();
91+
});
92+
93+
it("should support swapping out the svelte3 component", async () => {
94+
const wrapper = new Wrapper({
95+
target : root,
96+
97+
data : {
98+
component : ComponentA,
99+
100+
props : {
101+
a : "A",
102+
},
79103
},
80104
});
81105

106+
expect(root.innerHTML).toMatchSnapshot();
107+
108+
wrapper.set({
109+
component : ComponentB,
110+
});
111+
112+
await wait();
113+
114+
expect(root.innerHTML).toMatchSnapshot();
115+
});
116+
117+
it("should support creation without a component", async () => {
118+
const wrapper = new Wrapper({
119+
target : root,
120+
});
121+
122+
expect(root.innerHTML).toMatchSnapshot();
123+
124+
wrapper.set({
125+
component : ComponentB,
126+
});
127+
82128
await wait();
83129

84130
expect(root.innerHTML).toMatchSnapshot();
@@ -89,7 +135,7 @@ describe("3in2 component wrapper", () => {
89135
target : root,
90136

91137
data : {
92-
component : Component,
138+
component : ComponentA,
93139

94140
attrs : {
95141
class : "class",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
export let a = "a";
3+
</script>
4+
5+
<p>a? {a}!</p>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
export let b = "b";
3+
</script>
4+
5+
<p>B? {b}!</p>

3in2/tests/specimens/component.svelte

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)