Skip to content

Commit 85b575c

Browse files
author
Michael Vurchio
committed
Merge branch 'release/1.2.1'
2 parents f070e7e + 57f505a commit 85b575c

File tree

6 files changed

+254
-240
lines changed

6 files changed

+254
-240
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Svelte preprocess CSS Modules, changelog
22

3-
## 1.2.0 (Sept 21, 2020)
3+
## 1.2.1 (Oct 31, 2020)
4+
- Fix class chaining and pseudo selector [pull request #8](https://github.com/micantoine/svelte-preprocess-cssmodules/pull/8)
5+
6+
## 1.2.0 (Sept 21, 2020)
47
- Add support for `getLocalIdent()` [issue #6](https://github.com/micantoine/svelte-preprocess-cssmodules/issues/6) - [pull request #7](https://github.com/micantoine/svelte-preprocess-cssmodules/pull/7)
58

69
## 1.1.1

README.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ Pass an object of the following properties
6666
| `localIdentName` | `{String}` | `"[local]-[hash:base64:6]"` | A rule using any available token from [webpack interpolateName](https://github.com/webpack/loader-utils#interpolatename) |
6767
| `includePaths` | `{Array}` | `[]` (Any) | An array of paths to be processed |
6868
| `getLocalIdent` | `Function` | `undefined` | Generate the classname by specifying a function instead of using the built-in interpolation |
69-
| `strict` | `Boolean` | `false` | When true, an exception is raised when a class is used while not being defined in `<style>`
69+
| `strict` | `{Boolean}` | `false` | When true, an exception is raised when a class is used while not being defined in `<style>`
7070

7171
#### `getLocalIdent`
7272

73-
Function to generate the classname instead of the built-in function.
73+
Function to generate the classname instead of relying on the built-in function.
7474

7575
```js
7676
function getLocalIdent(
@@ -150,7 +150,7 @@ The component will be transformed to
150150

151151
### Replace only the required class
152152

153-
CSS Modules classname are generated to the html class values prefixed by `$style.`. The rest is left untouched.
153+
CSS Modules classname are generated to the html class values prefixed by `$style.`. The rest is left untouched and will use the default svelte scoped class.
154154

155155
*Before*
156156

@@ -169,18 +169,18 @@ CSS Modules classname are generated to the html class values prefixed by `$style
169169

170170
```html
171171
<style>
172-
.blue { color: blue;}
172+
.blue.svelte-1s2ez3w { color: blue;}
173173
.red-2iBDzf { color: red; }
174-
.text-center { text-align: center; }
174+
.text-center.svelte-1s2ez3w { text-align: center; }
175175
</style>
176176

177-
<p class="blue text-center">My blue text</p>
178-
<p class="red-2iBDzf text-center">My red text</p>
177+
<p class="blue text-center svelte-1s2ez3w">My blue text</p>
178+
<p class="red-2iBDzf text-center svelte-1s2ez3w">My red text</p>
179179
```
180180

181181
### Remove unspecified class
182182

183-
If a CSS Modules class has no css style attached, it will be removed from the class attribute.
183+
On non strict mode, if a CSS Modules class has no css style attached, it will be removed from the class attribute.
184184

185185
*Before*
186186

@@ -196,10 +196,10 @@ If a CSS Modules class has no css style attached, it will be removed from the cl
196196

197197
```html
198198
<style>
199-
.text-center { text-align: center; }
199+
.text-center.svelte-1s2ez3w { text-align: center; }
200200
</style>
201201

202-
<p class="text-center">My blue text</p>
202+
<p class="text-center svelte-1s2ez3w">My blue text</p>
203203
```
204204

205205
### Target any classname format
@@ -405,25 +405,25 @@ export default {
405405
background-color: #fff;
406406
transform: translateX(-50%) translateY(-50%);
407407
}
408-
section {
408+
section.svelte-1s2ez3w {
409409
flex: 0 1 auto;
410410
flex-direction: column;
411411
display: flex;
412412
height: 100%;
413413
}
414-
header {
414+
header.svelte-1s2ez3w {
415415
padding: 1rem;
416416
border-bottom: 1px solid #d9d9d9;
417417
}
418418
._1HPUBXtzNG {
419419
padding: 1rem;
420420
flex: 1 0 0;
421421
}
422-
footer {
422+
footer.svelte-1s2ez3w {
423423
padding: 1rem;
424424
border-top: 1px solid #d9d9d9;
425425
}
426-
button {
426+
button.svelte-1s2ez3w {
427427
background: #fff;
428428
border: 1px solid #ccc;
429429
border-radius: 5px;
@@ -447,11 +447,11 @@ export default {
447447
</div>
448448
```
449449

450-
**Note:** The svelte scoped classes are still being applied to the html elements with a style.
450+
**Note:** The svelte scoped class is still being applied to the html elements with a style.
451451

452452
## Why CSS Modules on Svelte
453453

454-
While the native CSS Scoped system should be largely enough to avoid class conflict, it could find its limit when working on a hybrid project. On a non full Svelte application where it is used to enhance pieces of the page; the thought on the class naming is no less different than the one on a regular html page to avoid conflict and unwilling inheritance. For example, on the modal component above, It would have been wiser to namespace some of the classes such as `.modal-body` and `.modal-cancel` to avoid inheriting styles from other `.body` and `.cancel`.
454+
While the native CSS Scoped system should be largely enough to avoid class conflict, it could find its limit when working on a hybrid project. On a non full Svelte application, the thought on the class naming would not be less different than what we would do on a regular html page. For example, on the modal component above, It would have been wiser to namespace some of the classes such as `.modal-body` and `.modal-cancel` in order to prevent inheriting styles from other `.body` and `.cancel` classes.
455455

456456
## License
457457

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "svelte-preprocess-cssmodules",
3-
"version": "1.2.0",
3+
"version": "1.2.1",
44
"description": "Svelte preprocessor to generate CSS Modules classname on Svelte components",
55
"keywords": [
66
"svelte",

test/chaining-selector.test.js

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
const compiler = require('./compiler.js');
2+
3+
describe('combining multiple classes', () => {
4+
const style = '<style>span.red.large:hover { font-size: 20px; } \n.red { color: red; }</style>';
5+
const source = style + '\n<span class="$style.red $style.large">Red</span>';
6+
7+
const expectedStyle =
8+
'<style>:global(span.red-123456.large-123456:hover) { font-size: 20px; } \n:global(.red-123456) { color: red; }</style>';
9+
const expectedOutput = expectedStyle + '\n<span class="red-123456 large-123456">Red</span>';
10+
11+
test('Generate CSS Modules from HTML attributes, Replace CSS className', async () => {
12+
const output = await compiler(
13+
{
14+
source,
15+
},
16+
{
17+
localIdentName: '[local]-123456',
18+
}
19+
);
20+
21+
expect(output).toBe(expectedOutput);
22+
});
23+
});
24+
25+
describe('Classname is part of a selector', () => {
26+
27+
test('CSS Modules class targetting children', async () => {
28+
const source =
29+
'<style>\n' +
30+
'div.red > sup { font-size: 12px; }\n' +
31+
'.red { color: red; }\n' +
32+
'</style>\n' +
33+
'<div class="$style.red">Red<sup>*</sup></div>';
34+
35+
const expectedOutput =
36+
'<style>\n' +
37+
':global(div.red-123) > sup { font-size: 12px; }\n' +
38+
':global(.red-123) { color: red; }\n' +
39+
'</style>\n' +
40+
'<div class="red-123">Red<sup>*</sup></div>';
41+
42+
const output = await compiler(
43+
{
44+
source,
45+
},
46+
{
47+
localIdentName: '[local]-123',
48+
}
49+
);
50+
51+
expect(output).toBe(expectedOutput);
52+
});
53+
54+
test('CSS Modules class has a parent', async () => {
55+
const source =
56+
'<style>\n' +
57+
'div .semibold .red { font-size: 20px; }\n' +
58+
'.red { color: red; }\n' +
59+
'.semibold { font-weight: 600; }\n' +
60+
'</style>\n' +
61+
'<div><strong class="$style.semibold"><span class="$style.red">Red</span></strong></div>';
62+
63+
const expectedOutput =
64+
'<style>\n' +
65+
'div :global(.semibold-123) :global(.red-123) { font-size: 20px; }\n' +
66+
':global(.red-123) { color: red; }\n' +
67+
':global(.semibold-123) { font-weight: 600; }\n' +
68+
'</style>\n' +
69+
'<div><strong class="semibold-123"><span class="red-123">Red</span></strong></div>';
70+
71+
const output = await compiler(
72+
{
73+
source,
74+
},
75+
{
76+
localIdentName: '[local]-123',
77+
}
78+
);
79+
80+
expect(output).toBe(expectedOutput);
81+
});
82+
83+
test('CSS Modules class has a global parent', async () => {
84+
const source =
85+
'<style>\n' +
86+
':global(div) .red { font-size: 20px; }\n' +
87+
'.red { color: red; }\n' +
88+
'</style>\n' +
89+
'<div><span class="$style.red">Red</span></div>';
90+
91+
const expectedOutput =
92+
'<style>\n' +
93+
':global(div) :global(.red-123) { font-size: 20px; }\n' +
94+
':global(.red-123) { color: red; }\n' +
95+
'</style>\n' +
96+
'<div><span class="red-123">Red</span></div>';
97+
98+
const output = await compiler(
99+
{
100+
source,
101+
},
102+
{
103+
localIdentName: '[local]-123',
104+
}
105+
);
106+
107+
expect(output).toBe(expectedOutput);
108+
});
109+
110+
test('CSS Modules class is used within a media query', async () => {
111+
const source =
112+
'<style>\n' +
113+
'@media (min-width: 37.5em) {\n' +
114+
'.red { color: red; }\n' +
115+
'div.bold { font-weight: bold; }\n' +
116+
'}\n' +
117+
'</style>\n' +
118+
'<div class="$style.bold"><span class="$style.red">Red</span></div>';
119+
120+
const expectedOutput =
121+
'<style>\n' +
122+
'@media (min-width: 37.5em) {\n' +
123+
':global(.red-123) { color: red; }\n' +
124+
':global(div.bold-123) { font-weight: bold; }\n' +
125+
'}\n' +
126+
'</style>\n' +
127+
'<div class="bold-123"><span class="red-123">Red</span></div>';
128+
129+
const output = await compiler(
130+
{
131+
source,
132+
},
133+
{
134+
localIdentName: '[local]-123',
135+
}
136+
);
137+
138+
expect(output).toBe(expectedOutput);
139+
});
140+
});

test/dynamic.test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const compiler = require('./compiler.js');
2+
3+
describe('using dynamic classes', () => {
4+
describe('when matched class is empty', () => {
5+
// The parser will identify a class named ''
6+
const source =
7+
'<style>.red { font-size: 20px; }</style>' + '<span class={`$style.${color}`}>Red</span>';
8+
9+
test('throws an exception', async () => {
10+
await expect(compiler({ source })).rejects.toThrow(
11+
'Invalid class name in file src/App.svelte.\nThis usually happens when using dynamic classes with svelte-preprocess-cssmodules.'
12+
);
13+
});
14+
});
15+
16+
describe('when matched class could be a valid class but does not match any style definition', () => {
17+
// The parser will identify a class named 'color'
18+
const source =
19+
'<style>.colorred { font-size: 20px; }</style>' +
20+
'<span class={`$style.color${color}`}>Red</span>';
21+
22+
it('in strict mode, it throw an exception', async () => {
23+
await expect(compiler({ source }, { strict: true })).rejects.toThrow(
24+
'Classname "color" was not found in declared src/App.svelte <style>'
25+
);
26+
});
27+
28+
// TODO: fix, this is probably not a result one would expect
29+
it('in non-strict mode, it removes the resulting class', async () => {
30+
const output = await compiler({ source }, { strict: false });
31+
expect(output).toEqual(
32+
'<style>.colorred { font-size: 20px; }</style><span class={`${color}`}>Red</span>'
33+
);
34+
});
35+
});
36+
37+
describe('when matched class is an invalid class', () => {
38+
// The parser will identify a class named 'color-'
39+
const source =
40+
'<style>.color-red { font-size: 20px; }</style>' +
41+
'<span class={`$style.color-${color}`}>Red</span>';
42+
43+
it('throws an exception when resulting class is invalid', async () => {
44+
await expect(compiler({ source })).rejects.toThrow('Classname "color-" in file src/App.svelte is not valid');
45+
});
46+
});
47+
});

0 commit comments

Comments
 (0)