Skip to content

Commit 2521408

Browse files
committed
Implement a freeze directive
1 parent 34b6d93 commit 2521408

File tree

85 files changed

+3030
-21
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+3030
-21
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [5.6.0] - 2024-12-13
4+
5+
- Add new directives to freeze rules and declarations `/*rtl:freeze*/`, `/*rtl:begin:freeze*/` and `/*rtl:end:freeze*/`
6+
37
## [5.5.1] - 2024-11-24
48

59
- Small refactor to avoid a circular dependency between two parsers

README.md

Lines changed: 161 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ Examples
144144
}
145145
```
146146

147-
#### Output using the combined mode (default)
147+
#### Output using the combined mode (default and recommended)
148148

149149
This is the recommended method, it will generate more CSS code but each direction will have their specific CSS declarations and there is no need of overriding properties.
150150

@@ -187,6 +187,9 @@ This is the recommended method, it will generate more CSS code but each directio
187187

188188
#### Output using the override mode
189189

190+
>[!IMPORTANT]
191+
>This method is not recommended, check below why
192+
190193
This is one of the alternative methods to override. It will generate less code because it lets the main rule intact most of the time and generates shorter specific rules to override the properties that are affected by the direction of the text.
191194

192195
```css
@@ -223,6 +226,9 @@ This is one of the alternative methods to override. It will generate less code b
223226

224227
#### Output using the diff mode
225228

229+
>[!IMPORTANT]
230+
>This method is not recommended, check below why
231+
226232
This is the second alternative method to override. It generates the minimum amount of code because it only outputs the rules that have been flipped and without prefixing them. The intention of this method is to generate a separate stylesheet file that will be loaded on top of the original one to override those rules that need to be flipped in certain direction.
227233

228234
```css
@@ -239,12 +245,16 @@ This is the second alternative method to override. It generates the minimum amou
239245
}
240246
```
241247

242-
But the two methods to override have a disadvantage:
248+
>[!IMPORTANT]
249+
>But the two methods to override have disadvantages:
243250
244-
<details><summary>Disadvantage of the override methods</summary>
251+
<details><summary>Disadvantages of the override methods</summary>
245252
<p>
246253

247-
Use these methods carefully. They can override a property that is coming from another class if multiple classes are used at the same time. Take a look at the next `HTML` and `CSS` codes:
254+
The methods to override are discouraged because:
255+
256+
1. Some directives as `/*rtl:freeze*/`, `/*rtl:begin:freeze*/` and `/*rtl:end:freeze*/` do not work with these methods
257+
2. They can override a property that is coming from another class if multiple classes are used at the same time. Take a look at the next `HTML` and `CSS` codes:
248258

249259
```html
250260
<div class="test1 test2">
@@ -312,7 +322,7 @@ And using the `diff` method the generated code will be the next one:
312322
}
313323
```
314324

315-
Now the `div` has a padding of `20px 10px 20px 20px` in `LTR` and `20px 0 20px 10px` in `RTL`, because when the class `test2` is overriden, it is not taken into account that it could be used with `test1` having the same properties. The solution, in this case, is to provide the property that has been inherited:
325+
Now the `div` has a padding of `20px 10px 20px 20px` in `LTR` and `20px 0 20px 10px` in `RTL`, because when the class `test2` is overriden, it is not taken into account that it could be used with `test1` having the same properties. The workaround, in this case, is to provide the property that has been inherited:
316326

317327
```css
318328
.test1 {
@@ -1516,9 +1526,12 @@ Control directives are placed between rules or declarations. They can target a s
15161526
| `/*rtl:ignore*/` | Ignores processing of the following rule or declaration |
15171527
| `/*rtl:begin:ignore*/` | Starts an ignoring block |
15181528
| `/*rtl:end:ignore*/` | Ends an ignoring block |
1529+
| `/*rtl:freeze*/` | Freezes the rule or declaration in the current direction but does nothing with the counterpart direction if there are flippable declarations |
1530+
| `/*rtl:begin:freeze*/` | Starts a freeze block |
1531+
| `/*rtl:end:freeze*/` | Ends a freeze block |
15191532
| `/*rtl:urls*/` | This directive set the `processUrls` option to `true` in the next declaration or in the declarations of the next rule no mattering the value of the global `processUrls` option |
1520-
| `/*rtl:begin:urls*/` | Starts a `processUrls` block block |
1521-
| `/*rtl:end:urls*/` | Ends a `processUrls` block block |
1533+
| `/*rtl:begin:urls*/` | Starts a `processUrls` block block |
1534+
| `/*rtl:end:urls*/` | Ends a `processUrls` block block |
15221535
| `/*rtl:rules*/` | This directive set the `processRuleNames` option to `true` in the next rule no mattering the value of the global `processRuleNames` option |
15231536
| `/*rtl:begin:rules*/` | Starts a `processRuleNames` block block |
15241537
| `/*rtl:end:rules*/` | Ends a `processRuleNames` block block |
@@ -1668,6 +1681,147 @@ Ignoring multiple declarations:
16681681

16691682
---
16701683

1684+
#### `/*rtl:freeze*/`
1685+
1686+
<details><summary>Expand</summary>
1687+
<p>
1688+
1689+
>[!IMPORTANT]
1690+
>1. This directive only works in `combined` mode. If you use it in `override` or `diff` mode it will be ignored.
1691+
>2. If you use this directive with declarations that are not affected by page direction, it is recommended that you set the [safeBothPrefix](#safebothprefix) option in `true`.
1692+
1693+
This directive freezes the rule or declaration in the current direction but does nothing with the counterpart direction if there are flippable declarations. When used with a rule, it will freeze it in the current direction even if it is doesn't contain flippable declarations. When it is used in a declration, it will freeze the declaration in the current direction even if it is not flippable.
1694+
1695+
##### input
1696+
1697+
```css
1698+
/*rtl:freeze*/
1699+
.test1, .test2 {
1700+
color: red;
1701+
text-align: left;
1702+
left: 10px;
1703+
}
1704+
1705+
.test3 {
1706+
/*rtl:freeze*/
1707+
text-align: center;
1708+
/*rtl:freeze*/
1709+
padding: 10px 20px 30px 40px;
1710+
margin: 1px 2px 3px 4px;
1711+
}
1712+
```
1713+
1714+
##### output
1715+
1716+
```css
1717+
[dir="ltr"] .test1, [dir="ltr"] .test2 {
1718+
color: red;
1719+
text-align: left;
1720+
left: 10px;
1721+
}
1722+
1723+
[dir="ltr"] .test3 {
1724+
text-align: center;
1725+
padding: 10px 40px 30px 20px;
1726+
margin: 1px 4px 3px 2px;
1727+
}
1728+
1729+
[dir="rtl"] .test3 {
1730+
margin: 1px 4px 3px 2px;
1731+
}
1732+
```
1733+
1734+
</p>
1735+
1736+
</details>
1737+
1738+
---
1739+
1740+
#### `/*rtl:begin:freeze*/` and `/*rtl:end:freeze*/`
1741+
1742+
<details><summary>Expand</summary>
1743+
<p>
1744+
1745+
>[!IMPORTANT]
1746+
>1. This directive only works in `combined` mode. If you use it in `override` or `diff` mode it will be ignored.
1747+
>2. If you use these directives with declarations that are not affected by page direction, it is recommended that you set the [safeBothPrefix](#safebothprefix) option in `true`.
1748+
1749+
These directives should be used together, they will provide the beginning and the end for freezing rules or declarations. The rules or delclarations between these blocks, will be frozen in the current direction even if there are no flippable declarations involved.
1750+
1751+
Freezing multiple rules:
1752+
1753+
##### input
1754+
1755+
```css
1756+
/*rtl:begin:freeze*/
1757+
.test1, .test2 {
1758+
color: #FFF;
1759+
left: 10px;
1760+
text-align: left;
1761+
}
1762+
1763+
.test3 {
1764+
padding: 1px 2px 3px 4px;
1765+
}
1766+
/*rtl:end:freeze*/
1767+
```
1768+
1769+
##### output
1770+
1771+
```css
1772+
[dir="ltr"] .test1, [dir="ltr"] .test2 {
1773+
color: #FFF;
1774+
left: 10px;
1775+
text-align: left;
1776+
}
1777+
1778+
[dir="ltr"] .test3 {
1779+
padding: 1px 2px 3px 4px;
1780+
}
1781+
```
1782+
1783+
Freezing multiple declarations:
1784+
1785+
##### input
1786+
1787+
```css
1788+
.test1, .test2 {
1789+
color: red;
1790+
left: 10px;
1791+
/*rtl:begin:freeze*/
1792+
margin-left: 4em;
1793+
padding: 1px 2px 3px 4px;
1794+
/*rtl:end:freeze*/
1795+
text-align: left;
1796+
}
1797+
```
1798+
1799+
##### output
1800+
1801+
```css
1802+
.test1, .test2 {
1803+
color: red;
1804+
}
1805+
1806+
[dir="ltr"] .test1, [dir="ltr"] .test2 {
1807+
left: 10px;
1808+
margin-left: 4em;
1809+
padding: 1px 2px 3px 4px;
1810+
text-align: left;
1811+
}
1812+
1813+
[dir="rtl"] .test1, [dir="rtl"] .test2 {
1814+
right: 10px;
1815+
text-align: right;
1816+
}
1817+
```
1818+
1819+
</p>
1820+
1821+
</details>
1822+
1823+
---
1824+
16711825
#### `/*rtl:urls*/`
16721826

16731827
<details><summary>Expand</summary>

src/@types/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,15 @@ export type RuleParser = (
152152
parsers: Parsers,
153153
container: Container,
154154
parentSourceDirective?: string,
155+
parentFreezeDirectiveActive?: boolean,
155156
hasParentRule?: boolean
156157
) => void;
157158

158159
export type AtRuleParser = (
159160
parsers: Parsers,
160161
container: Container,
161162
parentSourceDirective?: string,
163+
parentFreezeDirectiveActive?: boolean,
162164
hasParentRule?: boolean
163165
) => void;
164166

@@ -170,6 +172,7 @@ export type DeclarationParser = (
170172
container: DeclarationContainer,
171173
hasParentRule: boolean,
172174
ruleSourceDirectiveValue: string,
175+
parentFreezeDirectiveActive: boolean,
173176
processRule: boolean,
174177
rename: boolean
175178
) => void;

src/constants/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export enum TYPEOF {
2727

2828
export enum CONTROL_DIRECTIVE {
2929
IGNORE = 'ignore',
30+
FREEZE = 'freeze',
3031
URLS = 'urls',
3132
RULES = 'rules',
3233
SOURCE = 'source',

src/parsers/atrules.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const parseAtRules = (
2222
parsers: Parsers,
2323
container: Container,
2424
parentSourceDirective: string = undefined,
25+
parentFreezeDirectiveActive: boolean = false,
2526
hasParentRule = false
2627
): void => {
2728

@@ -54,6 +55,11 @@ export const parseAtRules = (
5455
parentSourceDirective
5556
);
5657

58+
const freezeDirectiveActive = (
59+
checkDirective(controlDirectives, CONTROL_DIRECTIVE.FREEZE) ||
60+
parentFreezeDirectiveActive
61+
);
62+
5763
if (
5864
hasParentRule &&
5965
node.nodes
@@ -62,6 +68,7 @@ export const parseAtRules = (
6268
node,
6369
hasParentRule,
6470
sourceDirectiveValue,
71+
freezeDirectiveActive,
6572
checkDirective(controlDirectives, CONTROL_DIRECTIVE.RULES),
6673
checkDirective(controlDirectives, CONTROL_DIRECTIVE.URLS)
6774
);
@@ -70,14 +77,16 @@ export const parseAtRules = (
7077
parsers.parseAtRules(
7178
parsers,
7279
node,
73-
parentSourceDirective,
80+
sourceDirectiveValue,
81+
freezeDirectiveActive,
7482
hasParentRule
7583
);
7684

7785
parsers.parseRules(
7886
parsers,
7987
node,
8088
sourceDirectiveValue,
89+
freezeDirectiveActive,
8190
hasParentRule
8291
);
8392

src/parsers/declarations.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export const parseDeclarations = (
4747
container: DeclarationContainer,
4848
hasParentRule: boolean,
4949
ruleSourceDirectiveValue: string,
50+
ruleFreezeDirectiveActive: boolean,
5051
processRule: boolean,
5152
rename: boolean
5253
): void => {
@@ -151,11 +152,11 @@ export const parseDeclarations = (
151152
return;
152153
}
153154

154-
const processUrlDirective = checkDirective(controlDirectives, CONTROL_DIRECTIVE.URLS);
155+
const isProcessUrlDirectiveActive = checkDirective(controlDirectives, CONTROL_DIRECTIVE.URLS);
155156

156157
const declString = `${decl.toString()};`;
157158
const declFlippedString = rtlcss.process(declString, {
158-
processUrls: processUrls || processUrlDirective || rename,
159+
processUrls: processUrls || isProcessUrlDirectiveActive || rename,
159160
processEnv,
160161
useCalc,
161162
stringMap,
@@ -215,6 +216,18 @@ export const parseDeclarations = (
215216
!sourceDirectiveValue ||
216217
sourceDirectiveValue === source ||
217218
mode === Mode.diff;
219+
220+
if (
221+
checkDirective(controlDirectives, CONTROL_DIRECTIVE.FREEZE) ||
222+
ruleFreezeDirectiveActive
223+
) {
224+
if (mode === Mode.combined) {
225+
appendDeclarationToRule(decl, containerFlipped);
226+
declarationsProps.push(declPropUnprefixed);
227+
deleteDeclarations.push(decl);
228+
}
229+
return;
230+
}
218231

219232
if (
220233
declProp === declFlippedProp &&

0 commit comments

Comments
 (0)