ripple 0.2.165 → 0.2.167
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 +2 -2
- package/src/compiler/phases/1-parse/index.js +30 -1
- package/src/compiler/phases/1-parse/style.js +36 -1
- package/src/compiler/phases/2-analyze/css-analyze.js +145 -0
- package/src/compiler/phases/2-analyze/index.js +7 -0
- package/src/compiler/phases/2-analyze/prune.js +165 -11
- package/src/compiler/phases/2-analyze/validation.js +156 -0
- package/src/compiler/phases/3-transform/client/index.js +62 -12
- package/src/compiler/phases/3-transform/stylesheet.js +102 -3
- package/src/runtime/internal/client/index.js +1 -0
- package/src/runtime/internal/client/operations.js +0 -6
- package/src/runtime/internal/client/render.js +22 -16
- package/tests/client/css/global-additional-cases.test.ripple +702 -0
- package/tests/client/css/global-advanced-selectors.test.ripple +229 -0
- package/tests/client/css/global-at-rules.test.ripple +126 -0
- package/tests/client/css/global-basic.test.ripple +165 -0
- package/tests/client/css/global-classes-ids.test.ripple +179 -0
- package/tests/client/css/global-combinators.test.ripple +124 -0
- package/tests/client/css/global-complex-nesting.test.ripple +221 -0
- package/tests/client/css/global-edge-cases.test.ripple +200 -0
- package/tests/client/css/global-keyframes.test.ripple +101 -0
- package/tests/client/css/global-nested.test.ripple +150 -0
- package/tests/client/css/global-pseudo.test.ripple +155 -0
- package/tests/client/css/global-scoping.test.ripple +229 -0
- package/tests/client/dynamic-elements.test.ripple +0 -1
- package/tests/server/streaming-ssr.test.ripple +9 -6
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { compile } from 'ripple/compiler';
|
|
2
|
+
|
|
3
|
+
describe('CSS :global with combinators', () => {
|
|
4
|
+
it('handles :global with child combinator', () => {
|
|
5
|
+
const source = `
|
|
6
|
+
export component Test() {
|
|
7
|
+
<div>
|
|
8
|
+
<span>{'content'}</span>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<style>
|
|
12
|
+
div > :global(span) {
|
|
13
|
+
color: red;
|
|
14
|
+
}
|
|
15
|
+
</style>
|
|
16
|
+
}`;
|
|
17
|
+
const { css } = compile(source, 'test.ripple');
|
|
18
|
+
|
|
19
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ > span {/);
|
|
20
|
+
expect(css).not.toMatch(/span\.ripple-[a-z0-9]+/);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('handles :global with adjacent sibling combinator', () => {
|
|
24
|
+
const source = `
|
|
25
|
+
export component Test() {
|
|
26
|
+
<div>
|
|
27
|
+
<span>{'one'}</span>
|
|
28
|
+
<span>{'two'}</span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<style>
|
|
32
|
+
span + :global(span) {
|
|
33
|
+
color: red;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
:global(div) + span {
|
|
37
|
+
color: blue;
|
|
38
|
+
}
|
|
39
|
+
</style>
|
|
40
|
+
}`;
|
|
41
|
+
const { css } = compile(source, 'test.ripple');
|
|
42
|
+
|
|
43
|
+
expect(css).toMatch(/span\.ripple-[a-z0-9]+ \+ span {/);
|
|
44
|
+
expect(css).toContain('(unused) :global(div) + span {');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('handles :global with general sibling combinator', () => {
|
|
48
|
+
const source = `
|
|
49
|
+
export component Test() {
|
|
50
|
+
<div>
|
|
51
|
+
<span>{'one'}</span>
|
|
52
|
+
<span>{'two'}</span>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<style>
|
|
56
|
+
span ~ :global(span) {
|
|
57
|
+
color: red;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:global(div) ~ span {
|
|
61
|
+
color: blue;
|
|
62
|
+
}
|
|
63
|
+
</style>
|
|
64
|
+
}`;
|
|
65
|
+
const { css } = compile(source, 'test.ripple');
|
|
66
|
+
|
|
67
|
+
expect(css).toContain('~');
|
|
68
|
+
|
|
69
|
+
expect(css).toMatch(/span\.ripple-[a-z0-9]+ ~ span {/);
|
|
70
|
+
expect(css).toMatch('(unused) :global(div) ~ span {');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('handles complex combinator chains with :global', () => {
|
|
74
|
+
const source = `
|
|
75
|
+
export component Test() {
|
|
76
|
+
<div>
|
|
77
|
+
<span>
|
|
78
|
+
<button>{'nested button'}</button>
|
|
79
|
+
</span>
|
|
80
|
+
<button>{'sibling button'}</button>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<style>
|
|
84
|
+
div > :global(span > button) {
|
|
85
|
+
color: red;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
:global(div) > span + button {
|
|
89
|
+
color: blue;
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
92
|
+
}`;
|
|
93
|
+
const { css } = compile(source, 'test.ripple');
|
|
94
|
+
|
|
95
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ > span > button {/);
|
|
96
|
+
expect(css).toMatch(/div > span\.ripple-[a-z0-9]+ \+ button:where\(\.ripple-[a-z0-9]+\) {/);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('handles :global with descendant combinator', () => {
|
|
100
|
+
const source = `
|
|
101
|
+
export component Test() {
|
|
102
|
+
<div>
|
|
103
|
+
<span>
|
|
104
|
+
<button>{'click'}</button>
|
|
105
|
+
</span>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<style>
|
|
109
|
+
div :global(span button) {
|
|
110
|
+
color: red;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
:global(div) span button {
|
|
114
|
+
color: blue;
|
|
115
|
+
}
|
|
116
|
+
</style>
|
|
117
|
+
}`;
|
|
118
|
+
|
|
119
|
+
const { css } = compile(source, 'test.ripple');
|
|
120
|
+
|
|
121
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ span button {/);
|
|
122
|
+
expect(css).toMatch(/div span\.ripple-[a-z0-9]+ button:where\(\.ripple-[a-z0-9]+\) {/);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { compile } from 'ripple/compiler';
|
|
2
|
+
|
|
3
|
+
describe('CSS :global with complex nesting', () => {
|
|
4
|
+
it('handles :global block with nested selectors', () => {
|
|
5
|
+
const source = `
|
|
6
|
+
export component Test() {
|
|
7
|
+
<div>
|
|
8
|
+
<span>
|
|
9
|
+
<button>{'click'}</button>
|
|
10
|
+
</span>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<style>
|
|
14
|
+
:global {
|
|
15
|
+
div {
|
|
16
|
+
span {
|
|
17
|
+
color: red;
|
|
18
|
+
|
|
19
|
+
button {
|
|
20
|
+
color: blue;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
26
|
+
}`;
|
|
27
|
+
const { css } = compile(source, 'test.ripple');
|
|
28
|
+
|
|
29
|
+
expect(css).not.toMatch(/div\.ripple-[a-z0-9]+ {/);
|
|
30
|
+
expect(css).not.toMatch(/span\.ripple-[a-z0-9]+ {/);
|
|
31
|
+
expect(css).not.toMatch(/button\.ripple-[a-z0-9]+ {/);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('handles local block with :global nested inside', () => {
|
|
35
|
+
const source = `
|
|
36
|
+
export component Test() {
|
|
37
|
+
<div>
|
|
38
|
+
<span>{'content'}</span>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<style>
|
|
42
|
+
div {
|
|
43
|
+
color: red;
|
|
44
|
+
|
|
45
|
+
:global(span) {
|
|
46
|
+
color: blue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
p {
|
|
50
|
+
color: green;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
</style>
|
|
54
|
+
}`;
|
|
55
|
+
const { css } = compile(source, 'test.ripple');
|
|
56
|
+
|
|
57
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ {/);
|
|
58
|
+
expect(css).not.toMatch(/span\.ripple-[a-z0-9]+ {/);
|
|
59
|
+
expect(css).toContain('(unused) p {');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('handles :global block with local nested inside', () => {
|
|
63
|
+
const source = `
|
|
64
|
+
export component Test() {
|
|
65
|
+
<div>
|
|
66
|
+
<span>
|
|
67
|
+
<button>{'click'}</button>
|
|
68
|
+
</span>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<style>
|
|
72
|
+
:global {
|
|
73
|
+
div {
|
|
74
|
+
.local {
|
|
75
|
+
color: red;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
80
|
+
}`;
|
|
81
|
+
const { css } = compile(source, 'test.ripple');
|
|
82
|
+
|
|
83
|
+
expect(css).toContain('div {');
|
|
84
|
+
expect(css).toContain('.local {');
|
|
85
|
+
expect(css).not.toMatch(/div\.ripple-[a-z0-9]+ {/);
|
|
86
|
+
expect(css).not.toMatch(/\.local\.ripple-[a-z0-9]+ {/);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('handles alternating :global and local nesting', () => {
|
|
90
|
+
const source = `
|
|
91
|
+
export component Test() {
|
|
92
|
+
<div>
|
|
93
|
+
<span>
|
|
94
|
+
<button>
|
|
95
|
+
<em>{'text'}</em>
|
|
96
|
+
</button>
|
|
97
|
+
</span>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<style>
|
|
101
|
+
div {
|
|
102
|
+
:global(span) {
|
|
103
|
+
button {
|
|
104
|
+
:global(em) {
|
|
105
|
+
color: red;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
111
|
+
}`;
|
|
112
|
+
const { css } = compile(source, 'test.ripple');
|
|
113
|
+
|
|
114
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ {/);
|
|
115
|
+
expect(css).toMatch(/button\.ripple-[a-z0-9]+ {/);
|
|
116
|
+
expect(css).toContain('span {');
|
|
117
|
+
expect(css).toContain('em {');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('handles deeply nested :global blocks', () => {
|
|
121
|
+
const source = `
|
|
122
|
+
export component Test() {
|
|
123
|
+
<div>
|
|
124
|
+
<span>
|
|
125
|
+
<button>{'click'}</button>
|
|
126
|
+
</span>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<style>
|
|
130
|
+
div {
|
|
131
|
+
:global {
|
|
132
|
+
span {
|
|
133
|
+
:global {
|
|
134
|
+
button {
|
|
135
|
+
color: red;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
142
|
+
}`;
|
|
143
|
+
const { css } = compile(source, 'test.ripple');
|
|
144
|
+
|
|
145
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ {/);
|
|
146
|
+
expect(css).toContain('span {');
|
|
147
|
+
expect(css).toContain('button {');
|
|
148
|
+
expect(css).not.toMatch(/span\.ripple-[a-z0-9]+/);
|
|
149
|
+
expect(css).not.toMatch(/button\.ripple-[a-z0-9]+/);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('handles :global with nesting combinator &', () => {
|
|
153
|
+
const source = `
|
|
154
|
+
export component Test() {
|
|
155
|
+
<div class="container">
|
|
156
|
+
<button class="active">{'click'}</button>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<style>
|
|
160
|
+
.container {
|
|
161
|
+
:global {
|
|
162
|
+
&.active {
|
|
163
|
+
color: red;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
button {
|
|
168
|
+
:global(&.pressed) {
|
|
169
|
+
color: blue;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
</style>
|
|
174
|
+
}`;
|
|
175
|
+
const { css } = compile(source, 'test.ripple');
|
|
176
|
+
|
|
177
|
+
expect(css).toMatch(/\.container\.ripple-[a-z0-9]+ {/);
|
|
178
|
+
expect(css).toMatch(/button\.ripple-[a-z0-9]+ {/);
|
|
179
|
+
expect(css).toContain('&.active {');
|
|
180
|
+
expect(css).toContain('&.pressed {');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('handles complex :global nesting with multiple levels', () => {
|
|
184
|
+
const source = `
|
|
185
|
+
export component Test() {
|
|
186
|
+
<div>
|
|
187
|
+
<nav>
|
|
188
|
+
<ul>
|
|
189
|
+
<li>
|
|
190
|
+
<a href="#">{'link'}</a>
|
|
191
|
+
</li>
|
|
192
|
+
</ul>
|
|
193
|
+
</nav>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<style>
|
|
197
|
+
div {
|
|
198
|
+
:global(nav) {
|
|
199
|
+
ul {
|
|
200
|
+
:global(li) {
|
|
201
|
+
a {
|
|
202
|
+
color: red;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
</style>
|
|
209
|
+
}`;
|
|
210
|
+
const { css } = compile(source, 'test.ripple');
|
|
211
|
+
|
|
212
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ {/);
|
|
213
|
+
expect(css).toMatch(/ul\.ripple-[a-z0-9]+ {/);
|
|
214
|
+
expect(css).toMatch(/a\.ripple-[a-z0-9]+ {/);
|
|
215
|
+
|
|
216
|
+
expect(css).toContain('nav {');
|
|
217
|
+
expect(css).toContain('li {');
|
|
218
|
+
expect(css).not.toMatch(/nav\.ripple-[a-z0-9]+ {/);
|
|
219
|
+
expect(css).not.toMatch(/li\.ripple-[a-z0-9]+ {/);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { compile } from 'ripple/compiler';
|
|
2
|
+
|
|
3
|
+
describe('CSS :global edge cases', () => {
|
|
4
|
+
it('handles multiple :global selectors in one rule', () => {
|
|
5
|
+
const source = `
|
|
6
|
+
export component Test() {
|
|
7
|
+
<div>{'content'}</div>
|
|
8
|
+
|
|
9
|
+
<style>
|
|
10
|
+
:global(div), :global(span), p {
|
|
11
|
+
color: red;
|
|
12
|
+
}
|
|
13
|
+
</style>
|
|
14
|
+
}`;
|
|
15
|
+
const { css } = compile(source, 'test.ripple');
|
|
16
|
+
|
|
17
|
+
expect(css).toContain('div, span ');
|
|
18
|
+
expect(css).toContain('(unused) p');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('handles :global with attribute selectors', () => {
|
|
22
|
+
const source = `
|
|
23
|
+
export component Test() {
|
|
24
|
+
<div data-test="value">{'content'}</div>
|
|
25
|
+
|
|
26
|
+
<style>
|
|
27
|
+
:global([data-test]) {
|
|
28
|
+
color: red;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
div:global([data-foo="bar"]) {
|
|
32
|
+
color: blue;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
35
|
+
}`;
|
|
36
|
+
const { css } = compile(source, 'test.ripple');
|
|
37
|
+
|
|
38
|
+
expect(css).toContain('[data-test] {');
|
|
39
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+\[data-foo="bar"\]/);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('handles :global with universal selector', () => {
|
|
43
|
+
const source = `
|
|
44
|
+
export component Test() {
|
|
45
|
+
<div>{'content'}</div>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
:global(*) {
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
div :global(*) {
|
|
53
|
+
margin: 0;
|
|
54
|
+
}
|
|
55
|
+
</style>
|
|
56
|
+
}`;
|
|
57
|
+
const { css } = compile(source, 'test.ripple');
|
|
58
|
+
|
|
59
|
+
expect(css).toContain('* {');
|
|
60
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ \* {/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('handles :global with ID selectors', () => {
|
|
64
|
+
const source = `
|
|
65
|
+
export component Test() {
|
|
66
|
+
<div id="test">{'content'}</div>
|
|
67
|
+
|
|
68
|
+
<style>
|
|
69
|
+
:global(#app) {
|
|
70
|
+
width: 100%;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
div :global(#test) {
|
|
74
|
+
color: red;
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
77
|
+
}`;
|
|
78
|
+
const { css } = compile(source, 'test.ripple');
|
|
79
|
+
|
|
80
|
+
expect(css).toContain('#app {');
|
|
81
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ #test {/);
|
|
82
|
+
expect(css).not.toMatch(/#app\.ripple-[a-z0-9]+/);
|
|
83
|
+
expect(css).not.toMatch(/#test\.ripple-[a-z0-9]+/);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('handles :global with pseudo-elements', () => {
|
|
87
|
+
const source = `
|
|
88
|
+
export component Test() {
|
|
89
|
+
<div>{'content'}</div>
|
|
90
|
+
|
|
91
|
+
<style>
|
|
92
|
+
:global(div)::before {
|
|
93
|
+
content: "before";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
div :global(span)::after {
|
|
97
|
+
content: "after";
|
|
98
|
+
}
|
|
99
|
+
</style>
|
|
100
|
+
}`;
|
|
101
|
+
const { css } = compile(source, 'test.ripple');
|
|
102
|
+
|
|
103
|
+
expect(css).toContain('div::before {');
|
|
104
|
+
``;
|
|
105
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ span::after {/);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('handles empty :global blocks', () => {
|
|
109
|
+
const source = `
|
|
110
|
+
export component Test() {
|
|
111
|
+
<div>{'content'}</div>
|
|
112
|
+
|
|
113
|
+
<style>
|
|
114
|
+
div {
|
|
115
|
+
:global {
|
|
116
|
+
}
|
|
117
|
+
color: red;
|
|
118
|
+
}
|
|
119
|
+
</style>
|
|
120
|
+
}`;
|
|
121
|
+
const { css } = compile(source, 'test.ripple');
|
|
122
|
+
|
|
123
|
+
expect(css).toContain('color: red');
|
|
124
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ {/);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('handles :global with complex selector chains', () => {
|
|
128
|
+
const source = `
|
|
129
|
+
export component Test() {
|
|
130
|
+
<div class="container">
|
|
131
|
+
<span class="wrapper foo">
|
|
132
|
+
<button class="bar"><span>{'click'}</span></button>
|
|
133
|
+
</span>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<style>
|
|
137
|
+
:global(div.container) > span.wrapper + :global(button[disabled]) {
|
|
138
|
+
color: red;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
:global(.foo > .bar) span {
|
|
142
|
+
color: blue;
|
|
143
|
+
}
|
|
144
|
+
</style>
|
|
145
|
+
}`;
|
|
146
|
+
const { css } = compile(source, 'test.ripple');
|
|
147
|
+
|
|
148
|
+
expect(css).toMatch(/div\.container > span.wrapper\.ripple-[a-z0-9]+ \+ button\[disabled\] {/);
|
|
149
|
+
expect(css).toMatch(/\.foo > \.bar span\.ripple-[a-z0-9]+ {/);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('rejects :global in the middle of a selector sequence', () => {
|
|
153
|
+
const source = `
|
|
154
|
+
export component Test() {
|
|
155
|
+
<div>
|
|
156
|
+
<span class="foo">
|
|
157
|
+
<button class="bar">{'click'}</button>
|
|
158
|
+
</span>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<style>
|
|
162
|
+
div :global(.foo > .bar) span {
|
|
163
|
+
color: red;
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
166
|
+
}`;
|
|
167
|
+
|
|
168
|
+
expect(() => compile(source, 'test.ripple')).toThrow(
|
|
169
|
+
':global(...) can be at the start or end of a selector sequence, but not in the middle',
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('handles :global at start and end of selector', () => {
|
|
174
|
+
const source = `
|
|
175
|
+
export component Test() {
|
|
176
|
+
<div>
|
|
177
|
+
<span>{'content'}</span>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<style>
|
|
181
|
+
:global(html) div span {
|
|
182
|
+
color: red;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
div span :global(strong) {
|
|
186
|
+
color: blue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
:global(body) div :global(em) {
|
|
190
|
+
color: green;
|
|
191
|
+
}
|
|
192
|
+
</style>
|
|
193
|
+
}`;
|
|
194
|
+
const { css } = compile(source, 'test.ripple');
|
|
195
|
+
|
|
196
|
+
expect(css).toMatch(/html div\.ripple-[a-z0-9]+ span:where\(\.ripple-[a-z0-9]+\) {/);
|
|
197
|
+
expect(css).toMatch(/div\.ripple-[a-z0-9]+ span:where\(\.ripple-[a-z0-9]+\) strong {/);
|
|
198
|
+
expect(css).toMatch(/body div\.ripple-[a-z0-9]+ em {/);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { compile } from 'ripple/compiler';
|
|
2
|
+
|
|
3
|
+
describe('CSS :global with keyframes', () => {
|
|
4
|
+
it('handles -global- prefix for keyframes', () => {
|
|
5
|
+
const source = `
|
|
6
|
+
export component Test() {
|
|
7
|
+
<div>{'animated'}</div>
|
|
8
|
+
|
|
9
|
+
<style>
|
|
10
|
+
@keyframes -global-foo {
|
|
11
|
+
0% { opacity: 0; }
|
|
12
|
+
100% { opacity: 1; }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
div {
|
|
16
|
+
animation: foo 1s;
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
}`;
|
|
20
|
+
const { css } = compile(source, 'test.ripple');
|
|
21
|
+
|
|
22
|
+
expect(css).toContain('@keyframes foo');
|
|
23
|
+
expect(css).not.toContain('-global-foo');
|
|
24
|
+
expect(css).toContain('animation: foo 1s;');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('handles scoped keyframes without -global- prefix', () => {
|
|
28
|
+
const source = `
|
|
29
|
+
export component Test() {
|
|
30
|
+
<div>{'animated'}</div>
|
|
31
|
+
|
|
32
|
+
<style>
|
|
33
|
+
@keyframes foo {
|
|
34
|
+
0% { opacity: 0; }
|
|
35
|
+
100% { opacity: 1; }
|
|
36
|
+
}
|
|
37
|
+
</style>
|
|
38
|
+
}`;
|
|
39
|
+
const { css } = compile(source, 'test.ripple');
|
|
40
|
+
|
|
41
|
+
expect(css).toMatch(/@keyframes ripple-[a-z0-9]+-foo/);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('handles mix of global and scoped keyframes', () => {
|
|
45
|
+
const source = `
|
|
46
|
+
export component Test() {
|
|
47
|
+
<div class="global-anim">{'one'}</div>
|
|
48
|
+
<div class="scoped-anim">{'two'}</div>
|
|
49
|
+
|
|
50
|
+
<style>
|
|
51
|
+
@keyframes -global-fadeIn {
|
|
52
|
+
0% { opacity: 0; }
|
|
53
|
+
100% { opacity: 1; }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@keyframes slideIn {
|
|
57
|
+
0% { transform: translateX(-100%); }
|
|
58
|
+
100% { transform: translateX(0); }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.global-anim {
|
|
62
|
+
animation: fadeIn 1s;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.scoped-anim {
|
|
66
|
+
animation: slideIn 1s;
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
69
|
+
}`;
|
|
70
|
+
const { css } = compile(source, 'test.ripple');
|
|
71
|
+
|
|
72
|
+
expect(css).toContain('@keyframes fadeIn');
|
|
73
|
+
expect(css).not.toContain('-global-fadeIn');
|
|
74
|
+
expect(css).toMatch(/@keyframes ripple-[a-z0-9]+-slideIn/);
|
|
75
|
+
expect(css).toMatch(/\.scoped-anim\.ripple-[a-z0-9]+/);
|
|
76
|
+
expect(css).toMatch(/\.global-anim\.ripple-[a-z0-9]+/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('handles multiple animations with global keyframes', () => {
|
|
80
|
+
const source = `
|
|
81
|
+
export component Test() {
|
|
82
|
+
<div>{'animated'}</div>
|
|
83
|
+
|
|
84
|
+
<style>
|
|
85
|
+
@keyframes -global-foo {
|
|
86
|
+
0% { opacity: 0; }
|
|
87
|
+
100% { opacity: 1; }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@keyframes -global-bar {
|
|
91
|
+
0% { transform: scale(0); }
|
|
92
|
+
100% { transform: scale(1); }
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
95
|
+
}`;
|
|
96
|
+
const { css } = compile(source, 'test.ripple');
|
|
97
|
+
|
|
98
|
+
expect(css).toContain('@keyframes foo');
|
|
99
|
+
expect(css).toContain('@keyframes bar');
|
|
100
|
+
});
|
|
101
|
+
});
|