├── .editorconfig
├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── .rollup.js
├── .tape.js
├── CHANGELOG.md
├── CONTRIBUTING.md
├── INSTALL.md
├── LICENSE.md
├── README.md
├── package.json
├── src
├── index.js
└── lib
│ ├── clone-decl.js
│ ├── clone-rule.js
│ ├── match-inset-prefix.js
│ ├── match-side.js
│ ├── match-size.js
│ ├── reduce-values.js
│ ├── split.js
│ ├── transform-border-radius.js
│ ├── transform-border.js
│ ├── transform-directional-shorthands.js
│ ├── transform-float.js
│ ├── transform-inset.js
│ ├── transform-resize.js
│ ├── transform-side.js
│ ├── transform-size.js
│ ├── transform-text-align.js
│ └── transform-transition.js
└── test
├── border.css
├── border.expect.css
├── border.ltr.expect.css
├── border.preserve.expect.css
├── clear.css
├── clear.expect.css
├── clear.ltr.expect.css
├── float.css
├── float.expect.css
├── float.ltr.expect.css
├── inset.css
├── inset.expect.css
├── inset.ltr.expect.css
├── margin.css
├── margin.expect.css
├── margin.ltr.expect.css
├── padding.css
├── padding.expect.css
├── padding.ltr.expect.css
├── resize.css
├── resize.expect.css
├── size.css
├── size.expect.css
├── size.preserve.expect.css
├── text-align.css
├── text-align.expect.css
├── text-align.ltr.expect.css
├── transition.css
├── transition.expect.css
├── transition.ltr.expect.css
└── transition.preserve.ltr.expect.css
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_style = tab
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
13 | [*.{json,md,yml}]
14 | indent_size = 2
15 | indent_style = space
16 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 | on:
3 | push:
4 |
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | node: [12, 16]
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: actions/setup-node@v2
14 | with:
15 | node-version: ${{ matrix.node }}
16 |
17 | - run: yarn install --ignore-scripts
18 | - run: yarn run test
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | index.*.*
3 | package-lock.json
4 | yarn.lock
5 | *.log*
6 | *.result.css
7 | .*
8 | !.editorconfig
9 | !.gitignore
10 | !.rollup.js
11 | !.tape.js
12 | !.github
13 |
--------------------------------------------------------------------------------
/.rollup.js:
--------------------------------------------------------------------------------
1 | import babel from '@rollup/plugin-babel';
2 |
3 | export default {
4 | input: 'src/index.js',
5 | output: [
6 | { file: 'index.cjs.js', format: 'cjs', sourcemap: true, exports: 'default' },
7 | { file: 'index.esm.mjs', format: 'esm', sourcemap: true, exports: 'default' }
8 | ],
9 | plugins: [
10 | babel({
11 | babelHelpers: 'bundled',
12 | presets: [
13 | ['@babel/env', { modules: false, targets: { node: 10 } }]
14 | ]
15 | })
16 | ]
17 | };
18 |
--------------------------------------------------------------------------------
/.tape.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'border': {
3 | message: 'supports logical "border" property values'
4 | },
5 | 'border:ltr': {
6 | message: 'supports logical "border" property values with { dir: "ltr" }',
7 | options: {
8 | dir: 'ltr'
9 | }
10 | },
11 | 'border:preserve': {
12 | message: 'supports logical "border" property values with { preserve: true }',
13 | options: {
14 | preserve: true
15 | }
16 | },
17 | 'clear': {
18 | message: 'supports logical "clear" property values'
19 | },
20 | 'clear:ltr': {
21 | message: 'supports logical "clear" property values with { dir: "ltr" }',
22 | options: {
23 | dir: 'ltr'
24 | }
25 | },
26 | 'float': {
27 | message: 'supports logical "float" property values'
28 | },
29 | 'float:ltr': {
30 | message: 'supports logical "float" property values with { dir: "ltr" }',
31 | options: {
32 | dir: 'ltr'
33 | }
34 | },
35 | 'inset': {
36 | message: 'supports logical "inset" properties'
37 | },
38 | 'inset:ltr': {
39 | message: 'supports logical "inset" properties with { dir: "ltr" }',
40 | options: {
41 | dir: 'ltr'
42 | }
43 | },
44 | 'margin': {
45 | message: 'supports logical "margin" properties'
46 | },
47 | 'margin:ltr': {
48 | message: 'supports logical "margin" properties with { dir: "ltr" }',
49 | options: {
50 | dir: 'ltr'
51 | }
52 | },
53 | 'padding': {
54 | message: 'supports logical "padding" properties'
55 | },
56 | 'padding:ltr': {
57 | message: 'supports logical "padding" properties with { dir: "ltr" }',
58 | options: {
59 | dir: 'ltr'
60 | }
61 | },
62 | 'resize': {
63 | message: 'supports logical "resize" properties'
64 | },
65 | 'size': {
66 | message: 'supports logical "size" properties'
67 | },
68 | 'size:preserve': {
69 | message: 'supports logical "size" properties with { preserve: true }',
70 | options: {
71 | preserve: true
72 | }
73 | },
74 | 'text-align': {
75 | message: 'supports logical "text-align" properties'
76 | },
77 | 'text-align:ltr': {
78 | message: 'supports logical "text-align" properties with { dir: "ltr" }',
79 | options: {
80 | dir: 'ltr'
81 | }
82 | },
83 | 'transition': {
84 | message: 'supports logical "transition" properties'
85 | },
86 | 'transition:ltr': {
87 | message: 'supports logical "transition" properties with { dir: "ltr" }',
88 | options: {
89 | dir: 'ltr'
90 | }
91 | },
92 | 'transition:preserve:ltr': {
93 | message: 'supports logical "transition" properties with { dir: "ltr", preserve: true }',
94 | options: {
95 | dir: 'ltr',
96 | preserve: true
97 | }
98 | }
99 | };
100 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changes to PostCSS Logical Properties
2 |
3 | ### 5.0.0 (September 17, 2021)
4 |
5 | - Updated: Support for PostCS 8+ (major).
6 | - Updated: Support for Node 12+ (major).
7 |
8 | ### 4.0.2 (June 10, 2019)
9 |
10 | - Fixed: Restored transforms for `max-block-size`, `max-inline-size`,
11 | `min-block-size`, and `min-inline-size`.
12 |
13 | ### 4.0.1 (June 10, 2019)
14 |
15 | - Fixed: An issue with `block-size` and `inline-size` being miscalculated.
16 |
17 | ### 4.0.0 (June 5, 2019)
18 |
19 | - Added: Logical border-radius properties, which include
20 | `border-end-end-radius`, `border-end-start-radius`, `border-start-end-radius`,
21 | and `border-start-start-radius`.
22 | - Removed: All unknown logical properties, which include `border-end`,
23 | `border-end-color`, `border-end-style`, `border-end-width`, `border-start`,
24 | `border-start-color`, `border-start-style`, `border-start-width`, `inset-end`,
25 | `inset-start`, `margin-end`, `margin-start`, `padding-end`, `padding-start`
26 | and `border` with `logical`.
27 | - Updated: `transition` and `transition-property` to support the changes.
28 | - Updated: `postcss` to 7.0.16 (patch)
29 | - Updated: Node 8+ compatibility (major)
30 |
31 | ### 3.0.0 (September 20, 2018)
32 |
33 | - Added: Support for logical properties within `transition` and
34 | `transition-property`.
35 | - Changed: Physical rule fallbacks are written as full selectors rather than
36 | as nesting selectors.
37 |
38 | ### 2.0.0 (September 17, 2018)
39 |
40 | - Updated: Support for PostCSS v7+
41 | - Updated: Support for Node v6+
42 |
43 | ### 1.1.1 (March 21, 2017)
44 |
45 | - Fix `dir` option to allow falsey value
46 |
47 | ### 1.1.0 (March 20, 2017)
48 |
49 | - Add `preserve` option to preserve logical properties and values
50 |
51 | ### 1.0.2 (Aug 15, 2017)
52 |
53 | - Improve flow-relative clear support
54 |
55 | ### 1.0.1 (Aug 13, 2017)
56 |
57 | - Improve flow-relative border support
58 |
59 | ### 1.0.0 (Aug 8, 2017)
60 |
61 | - Initial version
62 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to PostCSS Logical Properties
2 |
3 | You want to help? You rock! Now, take a moment to be sure your contributions
4 | make sense to everyone else.
5 |
6 | ## Reporting Issues
7 |
8 | Found a problem? Want a new feature?
9 |
10 | - See if your issue or idea has [already been reported].
11 | - Provide a [reduced test case] or a [live example].
12 |
13 | Remember, a bug is a _demonstrable problem_ caused by _our_ code.
14 |
15 | ## Submitting Pull Requests
16 |
17 | Pull requests are the greatest contributions, so be sure they are focused in
18 | scope and avoid unrelated commits.
19 |
20 | 1. To begin; [fork this project], clone your fork, and add our upstream.
21 | ```bash
22 | # Clone your fork of the repo into the current directory
23 | git clone git@github.com:YOUR_USER/postcss-logical-properties.git
24 |
25 | # Navigate to the newly cloned directory
26 | cd postcss-logical-properties
27 |
28 | # Assign the original repo to a remote called "upstream"
29 | git remote add upstream git@github.com:csstools/postcss-logical-properties.git
30 |
31 | # Install the tools necessary for testing
32 | npm install
33 | ```
34 |
35 | 2. Create a branch for your feature or fix:
36 | ```bash
37 | # Move into a new branch for your feature
38 | git checkout -b feature/thing
39 | ```
40 | ```bash
41 | # Move into a new branch for your fix
42 | git checkout -b fix/something
43 | ```
44 |
45 | 3. If your code follows our practices, then push your feature branch:
46 | ```bash
47 | # Test current code
48 | npm test
49 | ```
50 | ```bash
51 | # Push the branch for your new feature
52 | git push origin feature/thing
53 | ```
54 | ```bash
55 | # Or, push the branch for your update
56 | git push origin update/something
57 | ```
58 |
59 | That’s it! Now [open a pull request] with a clear title and description.
60 |
61 | [already been reported]: issues
62 | [fork this project]: fork
63 | [live example]: https://codepen.io/pen
64 | [open a pull request]: https://help.github.com/articles/using-pull-requests/
65 | [reduced test case]: https://css-tricks.com/reduced-test-cases/
66 |
--------------------------------------------------------------------------------
/INSTALL.md:
--------------------------------------------------------------------------------
1 | # Installing PostCSS
2 |
3 | [PostCSS Logical Properties and Values] runs in all Node environments, with
4 | special instructions for:
5 |
6 | | [Node](#node) | [PostCSS CLI](#postcss-cli) | [Webpack](#webpack) | [Create React App](#create-react-app) | [Gulp](#gulp) | [Grunt](#grunt) |
7 | | --- | --- | --- | --- | --- | --- |
8 |
9 | ## Node
10 |
11 | Add [PostCSS Logical Properties and Values] to your project:
12 |
13 | ```bash
14 | npm install postcss-logical --save-dev
15 | ```
16 |
17 | Use [PostCSS Logical Properties and Values] to process your CSS:
18 |
19 | ```js
20 | const postcssLogical = require('postcss-logical');
21 |
22 | postcssLogical.process(YOUR_CSS /*, processOptions, pluginOptions */);
23 | ```
24 |
25 | Or use it as a [PostCSS] plugin:
26 |
27 | ```js
28 | const postcss = require('postcss');
29 | const postcssLogical = require('postcss-logical');
30 |
31 | postcss([
32 | postcssLogical(/* pluginOptions */)
33 | ]).process(YOUR_CSS /*, processOptions */);
34 | ```
35 |
36 | ## PostCSS CLI
37 |
38 | Add [PostCSS CLI] to your project:
39 |
40 | ```bash
41 | npm install postcss-cli --save-dev
42 | ```
43 |
44 | Use [PostCSS Logical Properties and Values] in your `postcss.config.js`
45 | configuration file:
46 |
47 | ```js
48 | const postcssLogical = require('postcss-logical');
49 |
50 | module.exports = {
51 | plugins: [
52 | postcssLogical(/* pluginOptions */)
53 | ]
54 | }
55 | ```
56 |
57 | ## Webpack
58 |
59 | Add [PostCSS Loader] to your project:
60 |
61 | ```bash
62 | npm install postcss-loader --save-dev
63 | ```
64 |
65 | Use [PostCSS Logical Properties and Values] in your Webpack configuration:
66 |
67 | ```js
68 | const postcssLogical = require('postcss-logical');
69 |
70 | module.exports = {
71 | module: {
72 | rules: [
73 | {
74 | test: /\.css$/,
75 | use: [
76 | 'style-loader',
77 | { loader: 'css-loader', options: { importLoaders: 1 } },
78 | { loader: 'postcss-loader', options: {
79 | ident: 'postcss',
80 | plugins: () => [
81 | postcssLogical(/* pluginOptions */)
82 | ]
83 | } }
84 | ]
85 | }
86 | ]
87 | }
88 | }
89 | ```
90 |
91 | ## Create React App
92 |
93 | Add [React App Rewired] and [React App Rewire PostCSS] to your project:
94 |
95 | ```bash
96 | npm install react-app-rewired react-app-rewire-postcss --save-dev
97 | ```
98 |
99 | Use [React App Rewire PostCSS] and [PostCSS Logical Properties and Values] in
100 | your `config-overrides.js` file:
101 |
102 | ```js
103 | const reactAppRewirePostcss = require('react-app-rewire-postcss');
104 | const postcssLogical = require('postcss-logical');
105 |
106 | module.exports = config => reactAppRewirePostcss(config, {
107 | plugins: () => [
108 | postcssLogical(/* pluginOptions */)
109 | ]
110 | });
111 | ```
112 |
113 | ## Gulp
114 |
115 | Add [Gulp PostCSS] to your project:
116 |
117 | ```bash
118 | npm install gulp-postcss --save-dev
119 | ```
120 |
121 | Use [PostCSS Logical Properties and Values] in your Gulpfile:
122 |
123 | ```js
124 | const postcss = require('gulp-postcss');
125 | const postcssLogical = require('postcss-logical');
126 |
127 | gulp.task('css', () => gulp.src('./src/*.css').pipe(
128 | postcss([
129 | postcssLogical(/* pluginOptions */)
130 | ])
131 | ).pipe(
132 | gulp.dest('.')
133 | ));
134 | ```
135 |
136 | ## Grunt
137 |
138 | Add [Grunt PostCSS] to your project:
139 |
140 | ```bash
141 | npm install grunt-postcss --save-dev
142 | ```
143 |
144 | Use [PostCSS Logical Properties and Values] in your Gruntfile:
145 |
146 | ```js
147 | const postcssLogical = require('postcss-logical');
148 |
149 | grunt.loadNpmTasks('grunt-postcss');
150 |
151 | grunt.initConfig({
152 | postcss: {
153 | options: {
154 | use: [
155 | postcssLogical(/* pluginOptions */)
156 | ]
157 | },
158 | dist: {
159 | src: '*.css'
160 | }
161 | }
162 | });
163 | ```
164 |
165 | [Gulp PostCSS]: https://github.com/postcss/gulp-postcss
166 | [Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
167 | [PostCSS]: https://github.com/postcss/postcss
168 | [PostCSS CLI]: https://github.com/postcss/postcss-cli
169 | [PostCSS Loader]: https://github.com/postcss/postcss-loader
170 | [PostCSS Logical Properties and Values]: https://github.com/csstools/postcss-logical
171 | [React App Rewire PostCSS]: https://github.com/csstools/react-app-rewire-postcss
172 | [React App Rewired]: https://github.com/timarney/react-app-rewired
173 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # CC0 1.0 Universal
2 |
3 | ## Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an “owner”) of an original work of
8 | authorship and/or a database (each, a “Work”).
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific works
12 | (“Commons”) that the public can reliably and without fear of later claims of
13 | infringement build upon, modify, incorporate in other works, reuse and
14 | redistribute as freely as possible in any form whatsoever and for any purposes,
15 | including without limitation commercial purposes. These owners may contribute
16 | to the Commons to promote the ideal of a free culture and the further
17 | production of creative, cultural and scientific works, or to gain reputation or
18 | greater distribution for their Work in part through the use and efforts of
19 | others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation of
22 | additional consideration or compensation, the person associating CC0 with a
23 | Work (the “Affirmer”), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and
25 | publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights (“Copyright and
31 | Related Rights”). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 | 1. the right to reproduce, adapt, distribute, perform, display, communicate,
34 | and translate a Work;
35 | 2. moral rights retained by the original author(s) and/or performer(s);
36 | 3. publicity and privacy rights pertaining to a person’s image or likeness
37 | depicted in a Work;
38 | 4. rights protecting against unfair competition in regards to a Work,
39 | subject to the limitations in paragraph 4(i), below;
40 | 5. rights protecting the extraction, dissemination, use and reuse of data in
41 | a Work;
42 | 6. database rights (such as those arising under Directive 96/9/EC of the
43 | European Parliament and of the Council of 11 March 1996 on the legal
44 | protection of databases, and under any national implementation thereof,
45 | including any amended or successor version of such directive); and
46 | 7. other similar, equivalent or corresponding rights throughout the world
47 | based on applicable law or treaty, and any national implementations
48 | thereof.
49 |
50 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
51 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
52 | unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright
53 | and Related Rights and associated claims and causes of action, whether now
54 | known or unknown (including existing as well as future claims and causes of
55 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
56 | duration provided by applicable law or treaty (including future time
57 | extensions), (iii) in any current or future medium and for any number of
58 | copies, and (iv) for any purpose whatsoever, including without limitation
59 | commercial, advertising or promotional purposes (the “Waiver”). Affirmer
60 | makes the Waiver for the benefit of each member of the public at large and
61 | to the detriment of Affirmer’s heirs and successors, fully intending that
62 | such Waiver shall not be subject to revocation, rescission, cancellation,
63 | termination, or any other legal or equitable action to disrupt the quiet
64 | enjoyment of the Work by the public as contemplated by Affirmer’s express
65 | Statement of Purpose.
66 |
67 | 3. Public License Fallback. Should any part of the Waiver for any reason be
68 | judged legally invalid or ineffective under applicable law, then the Waiver
69 | shall be preserved to the maximum extent permitted taking into account
70 | Affirmer’s express Statement of Purpose. In addition, to the extent the
71 | Waiver is so judged Affirmer hereby grants to each affected person a
72 | royalty-free, non transferable, non sublicensable, non exclusive,
73 | irrevocable and unconditional license to exercise Affirmer’s Copyright and
74 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
75 | maximum duration provided by applicable law or treaty (including future time
76 | extensions), (iii) in any current or future medium and for any number of
77 | copies, and (iv) for any purpose whatsoever, including without limitation
78 | commercial, advertising or promotional purposes (the “License”). The License
79 | shall be deemed effective as of the date CC0 was applied by Affirmer to the
80 | Work. Should any part of the License for any reason be judged legally
81 | invalid or ineffective under applicable law, such partial invalidity or
82 | ineffectiveness shall not invalidate the remainder of the License, and in
83 | such case Affirmer hereby affirms that he or she will not (i) exercise any
84 | of his or her remaining Copyright and Related Rights in the Work or (ii)
85 | assert any associated claims and causes of action with respect to the Work,
86 | in either case contrary to Affirmer’s express Statement of Purpose.
87 |
88 | 4. Limitations and Disclaimers.
89 | 1. No trademark or patent rights held by Affirmer are waived, abandoned,
90 | surrendered, licensed or otherwise affected by this document.
91 | 2. Affirmer offers the Work as-is and makes no representations or warranties
92 | of any kind concerning the Work, express, implied, statutory or
93 | otherwise, including without limitation warranties of title,
94 | merchantability, fitness for a particular purpose, non infringement, or
95 | the absence of latent or other defects, accuracy, or the present or
96 | absence of errors, whether or not discoverable, all to the greatest
97 | extent permissible under applicable law.
98 | 3. Affirmer disclaims responsibility for clearing rights of other persons
99 | that may apply to the Work or any use thereof, including without
100 | limitation any person’s Copyright and Related Rights in the Work.
101 | Further, Affirmer disclaims responsibility for obtaining any necessary
102 | consents, permissions or other rights required for any use of the Work.
103 | 4. Affirmer understands and acknowledges that Creative Commons is not a
104 | party to this document and has no duty or obligation with respect to this
105 | CC0 or use of the Work.
106 |
107 | For more information, please see
108 | http://creativecommons.org/publicdomain/zero/1.0/.
109 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
3 |
4 | # PostCSS Logical Properties and Values [
][postcss]
5 |
6 | [![NPM Version][npm-img]][npm-url]
7 | [![CSS Standard Status][css-img]][css-url]
8 | [![Build Status][cli-img]][cli-url]
9 | [![Support Chat][git-img]][git-url]
10 |
11 | [PostCSS Logical Properties and Values] lets you use logical, rather than
12 | physical, direction and dimension mappings in CSS, following the
13 | [CSS Logical Properties and Values] specification.
14 |
15 | [](https://caniuse.com/#feat=css-logical-props)
16 |
17 | ```pcss
18 | .banner {
19 | color: #222222;
20 | inset: logical 0 5px 10px;
21 | padding-inline: 20px 40px;
22 | resize: block;
23 | transition: color 200ms;
24 | }
25 |
26 | /* becomes */
27 |
28 | .banner:dir(ltr) {
29 | padding-left: 20px; padding-right: 40px;
30 | }
31 |
32 | .banner:dir(rtl) {
33 | padding-right: 20px; padding-left: 40px;
34 | }
35 |
36 | .banner {
37 | resize: vertical;
38 | transition: color 200ms;
39 | }
40 |
41 | /* or, when used with { dir: 'ltr' } */
42 |
43 | .banner {
44 | color: #222222;
45 | top: 0; left: 5px; bottom: 10px; right: 5px;
46 | padding-left: 20px; padding-right: 40px;
47 | resize: vertical;
48 | transition: color 200ms;
49 | }
50 |
51 | /* or, when used with { preserve: true } */
52 |
53 | .banner:dir(ltr) {
54 | padding-left: 20px; padding-right: 40px;
55 | }
56 |
57 | .banner:dir(rtl) {
58 | padding-right: 20px; padding-left: 40px;
59 | }
60 |
61 | .banner {
62 | color: #222222;
63 | top: 0; left: 5px; bottom: 10px; right: 5px;
64 | inset: logical 0 5px 10px;
65 | padding-inline: 20px 40px;
66 | resize: block;
67 | resize: vertical;
68 | transition: color 200ms;
69 | }
70 | ```
71 |
72 | These shorthand properties set values for physical properties by default.
73 | Specifying the `logical` keyboard at the beginning of the property value will
74 | transform the flow-relative values afterward into both physical LTR and RTL
75 | properties:
76 |
77 | #### Logical Borders
78 |
79 | - `border`, `border-block`, `border-block-start`, `border-block-end`,
80 | `border-inline`, `border-inline-start`, `border-inline-end`, `border-start`,
81 | `border-end`, `border-color`, `border-block-color`,
82 | `border-block-start-color`, `border-block-end-color`, `border-inline-color`,
83 | `border-inline-start-color`, `border-inline-end-color`, `border-start-color`,
84 | `border-end-color`, `border-style`, `border-block-style`,
85 | `border-block-start-style`, `border-block-end-style`, `border-inline-style`,
86 | `border-inline-start-style`, `border-inline-end-style`, `border-start-style`,
87 | `border-end-style`, `border-width`, `border-block-width`,
88 | `border-block-start-width`, `border-block-end-width`, `border-inline-width`,
89 | `border-inline-start-width`, `border-inline-end-width`, `border-start-width`,
90 | `border-end-width`, `border-start-start-radius`, `border-start-end-radius`,
91 | `border-end-start-radius`, `border-end-end-radius`
92 |
93 | #### Logical Offsets
94 |
95 | - `inset`, `inset-block`, `inset-block-start`, `inset-block-end`,
96 | `inset-inline`, `inset-inline-start`, `inset-inline-end`, `inset-start`,
97 | `inset-end`
98 |
99 | #### Logical Margins
100 |
101 | - `margin`, `margin-block`, `margin-block-start`, `margin-block-end`,
102 | `margin-inline`, `margin-inline-start`, `margin-inline-end`, `margin-start`,
103 | `margin-end`
104 |
105 | #### Logical Paddings
106 |
107 | - `padding`, `padding-block`, `padding-block-start`, `padding-block-end`,
108 | `padding-inline`, `padding-inline-start`, `padding-inline-end`,
109 | `padding-start`, `padding-end`
110 |
111 | #### Logical Sizes
112 |
113 | - `block-size`, `max-block-size`, `min-block-size`, `inline-size`, `max-inline-size`, `min-inline-size`
114 |
115 | #### Flow-Relative Values
116 |
117 | - `clear: inline-start`, `clear: inline-end`, `float: inline-start`,
118 | `float: inline-end`, `text-align: start`, `text-align: end`
119 |
120 | ---
121 |
122 | By default, [PostCSS Logical Properties and Values] creates fallback selectors
123 | which require at least one `[dir]` attribute in your HTML. If you don’t have
124 | any `[dir]` attributes, consider using the following JavaScript:
125 |
126 | ```js
127 | // force at least one dir attribute (this can run at any time)
128 | document.documentElement.dir=document.documentElement.dir||'ltr';
129 | ```
130 |
131 | Otherwise, consider using the `dir` option to transform all logical properties
132 | and values to a specific direction.
133 |
134 | ```js
135 | require('postcss-logical')({
136 | dir: 'ltr'
137 | });
138 | ```
139 |
140 | ## Usage
141 |
142 | Add [PostCSS Logical Properties and Values] to your project:
143 |
144 | ```bash
145 | npm install postcss-logical --save-dev
146 | ```
147 |
148 | Use [PostCSS Logical Properties and Values] to process your CSS:
149 |
150 | ```js
151 | const postcssLogical = require('postcss-logical');
152 |
153 | postcssLogical.process(YOUR_CSS /*, processOptions, pluginOptions */);
154 | ```
155 |
156 | Or use it as a [PostCSS] plugin:
157 |
158 | ```js
159 | const postcss = require('postcss');
160 | const postcssLogical = require('postcss-logical');
161 |
162 | postcss([
163 | postcssLogical(/* pluginOptions */)
164 | ]).process(YOUR_CSS /*, processOptions */);
165 | ```
166 |
167 | [PostCSS Logical Properties and Values] runs in all Node environments, with
168 | special instructions for:
169 |
170 | | [Node](INSTALL.md#node) | [PostCSS CLI](INSTALL.md#postcss-cli) | [Webpack](INSTALL.md#webpack) | [Create React App](INSTALL.md#create-react-app) | [Gulp](INSTALL.md#gulp) | [Grunt](INSTALL.md#grunt) |
171 | | --- | --- | --- | --- | --- | --- |
172 |
173 | ## Options
174 |
175 | ### dir
176 |
177 | The `dir` option determines how directional fallbacks should be added to CSS.
178 | By default, fallbacks replace the logical declaration with nested `:dir`
179 | pseudo-classes. If `dir` is defined as `ltr` or `rtl` then only the left or
180 | right directional fallbacks will replace the logical declarations. If
181 | `preserve` is defined as `true`, then the `dir` option will be ignored.
182 |
183 | ### preserve
184 |
185 | The `preserve` option determines whether directional fallbacks should be added
186 | before logical declarations without replacing them. By default, directional
187 | fallbacks replace logical declaration. If `preserve` is defined as `true`, then
188 | the `dir` option will be ignored.
189 |
190 | [css-img]: https://cssdb.org/badge/logical-properties-and-values.svg
191 | [css-url]: https://cssdb.org/#logical-properties-and-values
192 | [cli-img]: https://github.com/csstools/postcss-logical/workflows/test/badge.svg
193 | [cli-url]: https://github.com/csstools/postcss-logical/actions/workflows/test.yml?query=workflow/test
194 | [git-img]: https://img.shields.io/badge/support-chat-blue.svg
195 | [git-url]: https://gitter.im/postcss/postcss
196 | [npm-img]: https://img.shields.io/npm/v/postcss-logical.svg
197 | [npm-url]: https://www.npmjs.com/package/postcss-logical
198 |
199 | [CSS Logical Properties and Values]: https://drafts.csswg.org/css-logical/
200 | [Gulp PostCSS]: https://github.com/postcss/gulp-postcss
201 | [Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
202 | [PostCSS]: https://github.com/postcss/postcss
203 | [PostCSS Loader]: https://github.com/postcss/postcss-loader
204 | [PostCSS Logical Properties and Values]: https://github.com/csstools/postcss-logical
205 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postcss-logical",
3 | "version": "5.0.0",
4 | "description": "Use logical properties and values in CSS",
5 | "author": "Jonathan Neal ",
6 | "license": "CC0-1.0",
7 | "repository": "csstools/postcss-logical",
8 | "homepage": "https://github.com/csstools/postcss-logical#readme",
9 | "bugs": "https://github.com/csstools/postcss-logical/issues",
10 | "main": "index.cjs.js",
11 | "module": "index.esm.mjs",
12 | "files": [
13 | "index.cjs.js",
14 | "index.cjs.js.map",
15 | "index.esm.mjs",
16 | "index.esm.mjs.map"
17 | ],
18 | "scripts": {
19 | "build": "rollup --config .rollup.js --silent",
20 | "prepublishOnly": "npm test",
21 | "pretest:tape": "npm run build",
22 | "test": "npm run test:js && npm run test:tape",
23 | "test:js": "eslint src/{*,**/*}.js --cache --ignore-path .gitignore --quiet",
24 | "test:tape": "postcss-tape"
25 | },
26 | "engines": {
27 | "node": ">=12"
28 | },
29 | "peerDependencies": {
30 | "postcss": "^8.3"
31 | },
32 | "devDependencies": {
33 | "@babel/core": "7.15.5",
34 | "@babel/preset-env": "7.15.6",
35 | "@rollup/plugin-babel": "5.3.0",
36 | "eslint": "7.32.0",
37 | "postcss": "8.3.6",
38 | "postcss-tape": "6.0.1",
39 | "pre-commit": "1.2.2",
40 | "rollup": "2.56.3"
41 | },
42 | "eslintConfig": {
43 | "env": {
44 | "browser": true,
45 | "es6": true,
46 | "node": true
47 | },
48 | "extends": "eslint:recommended",
49 | "parserOptions": {
50 | "ecmaVersion": 2020,
51 | "impliedStrict": true,
52 | "sourceType": "module"
53 | },
54 | "root": true
55 | },
56 | "keywords": [
57 | "postcss",
58 | "css",
59 | "postcss-plugin",
60 | "logical",
61 | "flow",
62 | "relative",
63 | "property",
64 | "properties",
65 | "values",
66 | "ltr",
67 | "rtl",
68 | "dir",
69 | "directions",
70 | "directional",
71 | "inline",
72 | "block",
73 | "start",
74 | "end",
75 | "align",
76 | "border",
77 | "clear",
78 | "float",
79 | "margin",
80 | "padding",
81 | "size",
82 | "text"
83 | ]
84 | }
85 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import transformBorder from './lib/transform-border';
2 | import transformBorderRadius from './lib/transform-border-radius';
3 | import transformDirectionalShorthands from './lib/transform-directional-shorthands';
4 | import transformFloat from './lib/transform-float';
5 | import transformInset from './lib/transform-inset';
6 | import transformResize from './lib/transform-resize';
7 | import transformSide from './lib/transform-side';
8 | import transformSize from './lib/transform-size';
9 | import transformTextAlign from './lib/transform-text-align';
10 | import transformTransition from './lib/transform-transition';
11 | import { splitBySpace } from './lib/split';
12 |
13 | // plugin
14 | function postcssLogicalProperties(opts) {
15 | opts = Object(opts);
16 |
17 | const preserve = Boolean(opts.preserve);
18 | const dir = !preserve && typeof opts.dir === 'string'
19 | ? /^rtl$/i.test(opts.dir)
20 | ? 'rtl'
21 | : 'ltr'
22 | : false;
23 |
24 | const makeTransform = (transform) => {
25 | return (decl) => {
26 | const parent = decl.parent;
27 | const values = splitBySpace(decl.value, true);
28 | transform(decl, values, dir, preserve);
29 | if (!parent.nodes.length) {
30 | parent.remove();
31 | }
32 | }
33 | }
34 |
35 | const makeTransformWithoutSplittingValues = (transform) => {
36 | return (decl) => {
37 | const parent = decl.parent;
38 | const values = [decl.value];
39 | transform(decl, values, dir, preserve);
40 | if (!parent.nodes.length) {
41 | parent.remove();
42 | }
43 | }
44 | }
45 |
46 | return {
47 | postcssPlugin: 'postcss-logical-properties',
48 | Declaration: {
49 | // Flow-Relative Values
50 | 'clear': makeTransform(transformFloat),
51 | 'float': makeTransform(transformFloat),
52 | 'resize': makeTransform(transformResize),
53 | 'text-align': makeTransform(transformTextAlign),
54 |
55 | // Logical Height and Logical Width
56 | 'block-size': makeTransform(transformSize),
57 | 'max-block-size': makeTransform(transformSize),
58 | 'min-block-size': makeTransform(transformSize),
59 | 'inline-size': makeTransform(transformSize),
60 | 'max-inline-size': makeTransform(transformSize),
61 | 'min-inline-size': makeTransform(transformSize),
62 |
63 | // Flow-relative Margins
64 | 'margin': makeTransform(transformDirectionalShorthands),
65 | 'margin-inline': makeTransform(transformSide['inline']),
66 | 'margin-inline-end': makeTransform(transformSide['inline-end']),
67 | 'margin-inline-start': makeTransform(transformSide['inline-start']),
68 | 'margin-block': makeTransform(transformSide['block']),
69 | 'margin-block-end': makeTransform(transformSide['block-end']),
70 | 'margin-block-start': makeTransform(transformSide['block-start']),
71 |
72 | // Flow-relative Offsets
73 | 'inset': makeTransform(transformInset),
74 | 'inset-inline': makeTransform(transformSide['inline']),
75 | 'inset-inline-end': makeTransform(transformSide['inline-end']),
76 | 'inset-inline-start': makeTransform(transformSide['inline-start']),
77 | 'inset-block': makeTransform(transformSide['block']),
78 | 'inset-block-end': makeTransform(transformSide['block-end']),
79 | 'inset-block-start': makeTransform(transformSide['block-start']),
80 |
81 | // Flow-relative Padding
82 | 'padding': makeTransform(transformDirectionalShorthands),
83 | 'padding-inline': makeTransform(transformSide['inline']),
84 | 'padding-inline-end': makeTransform(transformSide['inline-end']),
85 | 'padding-inline-start': makeTransform(transformSide['inline-start']),
86 | 'padding-block': makeTransform(transformSide['block']),
87 | 'padding-block-end': makeTransform(transformSide['block-end']),
88 | 'padding-block-start': makeTransform(transformSide['block-start']),
89 |
90 | // Flow-relative Borders
91 | 'border-block': makeTransformWithoutSplittingValues(transformBorder['border-block']),
92 | 'border-block-color': makeTransform(transformBorder['border-block']),
93 | 'border-block-style': makeTransform(transformBorder['border-block']),
94 | 'border-block-width': makeTransform(transformBorder['border-block']),
95 | 'border-block-end': makeTransformWithoutSplittingValues(transformBorder['border-block-end']),
96 | 'border-block-end-color': makeTransform(transformBorder['border-block-end']),
97 | 'border-block-end-style': makeTransform(transformBorder['border-block-end']),
98 | 'border-block-end-width': makeTransform(transformBorder['border-block-end']),
99 | 'border-block-start': makeTransformWithoutSplittingValues(transformBorder['border-block-start']),
100 | 'border-block-start-color': makeTransform(transformBorder['border-block-start']),
101 | 'border-block-start-style': makeTransform(transformBorder['border-block-start']),
102 | 'border-block-start-width': makeTransform(transformBorder['border-block-start']),
103 | 'border-inline': makeTransformWithoutSplittingValues(transformBorder['border-inline']),
104 | 'border-inline-color': makeTransform(transformBorder['border-inline']),
105 | 'border-inline-style': makeTransform(transformBorder['border-inline']),
106 | 'border-inline-width': makeTransform(transformBorder['border-inline']),
107 | 'border-inline-end': makeTransformWithoutSplittingValues(transformBorder['border-inline-end']),
108 | 'border-inline-end-color': makeTransform(transformBorder['border-inline-end']),
109 | 'border-inline-end-style': makeTransform(transformBorder['border-inline-end']),
110 | 'border-inline-end-width': makeTransform(transformBorder['border-inline-end']),
111 | 'border-inline-start': makeTransformWithoutSplittingValues(transformBorder['border-inline-start']),
112 | 'border-inline-start-color': makeTransform(transformBorder['border-inline-start']),
113 | 'border-inline-start-style': makeTransform(transformBorder['border-inline-start']),
114 | 'border-inline-start-width': makeTransform(transformBorder['border-inline-start']),
115 |
116 | // Flow-relative Corner Rounding
117 | 'border-end-end-radius': makeTransform(transformBorderRadius),
118 | 'border-end-start-radius': makeTransform(transformBorderRadius),
119 | 'border-start-end-radius': makeTransform(transformBorderRadius),
120 | 'border-start-start-radius': makeTransform(transformBorderRadius),
121 |
122 | // Four-Directional Shorthand Border Properties
123 | 'border-color': makeTransform(transformDirectionalShorthands),
124 | 'border-style': makeTransform(transformDirectionalShorthands),
125 | 'border-width': makeTransform(transformDirectionalShorthands),
126 |
127 | // Transition helpers
128 | 'transition': makeTransform(transformTransition),
129 | 'transition-property': makeTransform(transformTransition)
130 | }
131 | };
132 | }
133 | postcssLogicalProperties.postcss = true;
134 |
135 | export default postcssLogicalProperties;
136 |
--------------------------------------------------------------------------------
/src/lib/clone-decl.js:
--------------------------------------------------------------------------------
1 | import matchSide from './match-side';
2 | import matchInsetPrefix from './match-inset-prefix';
3 |
4 | export default (decl, suffix, value) => decl.cloneBefore({
5 | prop: `${decl.prop.replace(matchSide, '$1')}${suffix}`.replace(matchInsetPrefix, ''),
6 | value
7 | });
8 |
--------------------------------------------------------------------------------
/src/lib/clone-rule.js:
--------------------------------------------------------------------------------
1 | import postcss from 'postcss';
2 |
3 | export default (decl, dir) => {
4 | const rule = Object(decl.parent).type === 'rule' ? decl.parent.cloneBefore({
5 | raws: {}
6 | }).removeAll() : postcss.rule({ selector: '&' });
7 |
8 | rule.assign({'selectors': rule.selectors.map(selector => `${selector}:dir(${dir})`)})
9 |
10 | return rule;
11 | };
12 |
--------------------------------------------------------------------------------
/src/lib/match-inset-prefix.js:
--------------------------------------------------------------------------------
1 | export default /^inset-/i;
2 |
--------------------------------------------------------------------------------
/src/lib/match-side.js:
--------------------------------------------------------------------------------
1 | export default /^(inset|margin|padding)(?:-(block|block-start|block-end|inline|inline-start|inline-end|start|end))$/i;
2 |
--------------------------------------------------------------------------------
/src/lib/match-size.js:
--------------------------------------------------------------------------------
1 | export default /^(min-|max-)?(block|inline)-(size)$/i;
2 |
--------------------------------------------------------------------------------
/src/lib/reduce-values.js:
--------------------------------------------------------------------------------
1 | export default values => {
2 | const reducedValues = values.slice();
3 |
4 | // reduce [A, B, C, B] to [A, B, C]
5 | if (reducedValues.length === 4 && reducedValues[3] === reducedValues[1]) {
6 | reducedValues.pop();
7 | }
8 |
9 | // reduce [A, B, A] to [A, B]
10 | if (reducedValues.length === 3 && reducedValues[2] === reducedValues[0]) {
11 | reducedValues.pop();
12 | }
13 |
14 | // reduce [A, A] to [A]
15 | if (reducedValues.length === 2 && reducedValues[1] === reducedValues[0]) {
16 | reducedValues.pop();
17 | }
18 |
19 | return reducedValues;
20 | };
21 |
--------------------------------------------------------------------------------
/src/lib/split.js:
--------------------------------------------------------------------------------
1 | export function splitByComma(string, isTrimmed) {
2 | return splitByRegExp(string, /^,$/, isTrimmed);
3 | }
4 |
5 | export function splitBySpace(string, isTrimmed) {
6 | return splitByRegExp(string, /^\s$/, isTrimmed);
7 | }
8 |
9 | export function splitBySlash(string, isTrimmed) {
10 | return splitByRegExp(string, /^\/$/, isTrimmed);
11 | }
12 |
13 | function splitByRegExp(string, re, isTrimmed) {
14 | const array = [];
15 | let buffer = '';
16 | let split = false;
17 | let func = 0;
18 | let i = -1;
19 |
20 | while (++i < string.length) {
21 | const char = string[i];
22 |
23 | if (char === '(') {
24 | func += 1;
25 | } else if (char === ')') {
26 | if (func > 0) {
27 | func -= 1;
28 | }
29 | } else if (func === 0) {
30 | if (re.test(char)) {
31 | split = true;
32 | }
33 | }
34 |
35 | if (split) {
36 | if (!isTrimmed || buffer.trim()) {
37 | array.push(isTrimmed ? buffer.trim() : buffer);
38 | }
39 |
40 | if (!isTrimmed) {
41 | array.push(char);
42 | }
43 |
44 | buffer = '';
45 | split = false;
46 | } else {
47 | buffer += char
48 | }
49 | }
50 |
51 | if (buffer !== '') {
52 | array.push(isTrimmed ? buffer.trim() : buffer);
53 | }
54 |
55 | return array;
56 | }
57 |
--------------------------------------------------------------------------------
/src/lib/transform-border-radius.js:
--------------------------------------------------------------------------------
1 | import cloneRule from './clone-rule';
2 |
3 | const logicalRadii = /^(border-)(end-end|end-start|start-end|start-start)(-radius)$/i;
4 | const ltrRadii = { 'end-end': 'bottom-right', 'end-start': 'bottom-left', 'start-end': 'top-right', 'start-start': 'top-left' };
5 | const rtlRadii = { 'end-end': 'bottom-left', 'end-start': 'bottom-right', 'start-end': 'top-left', 'start-start': 'top-right' };
6 |
7 | export default (decl, values, dir, preserve) => {
8 | if (dir === 'ltr') {
9 | lDecl(decl);
10 | clean(decl, preserve);
11 | return;
12 | }
13 |
14 | if (dir === 'rtl') {
15 | rDecl(decl);
16 | clean(decl, preserve);
17 | return;
18 | }
19 |
20 | cloneRule(decl, 'ltr').append(lDecl(decl));
21 | cloneRule(decl, 'rtl').append(rDecl(decl));
22 | clean(decl, preserve);
23 | };
24 |
25 | function lDecl(decl) {
26 | return decl.cloneBefore({
27 | prop: decl.prop.replace(logicalRadii, ($, prefix, direction, suffix) => `${prefix}${ltrRadii[direction]}${suffix}`)
28 | });
29 | }
30 |
31 | function rDecl(decl) {
32 | return decl.cloneBefore({
33 | prop: decl.prop.replace(logicalRadii, ($, prefix, direction, suffix) => `${prefix}${rtlRadii[direction]}${suffix}`)
34 | });
35 | }
36 |
37 | function clean(decl, preserve) {
38 | if (!preserve) decl.remove();
39 | }
40 |
--------------------------------------------------------------------------------
/src/lib/transform-border.js:
--------------------------------------------------------------------------------
1 | import cloneRule from './clone-rule';
2 |
3 | const matchLogicalBorderSide = /^border-(block|block-start|block-end|inline|inline-start|inline-end)(-(width|style|color))?$/i;
4 |
5 | export default {
6 | // border-block
7 | 'border-block': (decl, values, dir, preserve) => {
8 | decl.cloneBefore({
9 | prop: `border-top${decl.prop.replace(matchLogicalBorderSide, '$2')}`,
10 | value: values[0]
11 | });
12 | decl.cloneBefore({
13 | prop: `border-bottom${decl.prop.replace(matchLogicalBorderSide, '$2')}`,
14 | value: values[1] || values[0]
15 | });
16 | clean(decl, preserve);
17 | },
18 |
19 | // border-block-start
20 | 'border-block-start': (decl, values, dir, preserve) => {
21 | decl.cloneBefore({
22 | prop: `border-top${decl.prop.replace(matchLogicalBorderSide, '$2')}`,
23 | });
24 | clean(decl, preserve);
25 | },
26 |
27 | // border-block-end
28 | 'border-block-end': (decl, values, dir, preserve) => {
29 | decl.cloneBefore({
30 | prop: `border-bottom${decl.prop.replace(matchLogicalBorderSide, '$2')}`,
31 | });
32 | clean(decl, preserve);
33 | },
34 |
35 | // border-inline
36 | 'border-inline': (decl, values, dir, preserve) => {
37 | const ltrDecls = () => {
38 | return [
39 | decl.cloneBefore({
40 | prop: `border-left${decl.prop.replace(matchLogicalBorderSide, '$2')}`,
41 | value: values[0]
42 | }),
43 | decl.cloneBefore({
44 | prop: `border-right${decl.prop.replace(matchLogicalBorderSide, '$2')}`,
45 | value: values[1] || values[0]
46 | })
47 | ];
48 | };
49 |
50 | const rtlDecls = () => {
51 | return [
52 | decl.clone({
53 | prop: `border-right${decl.prop.replace(matchLogicalBorderSide, '$2')}`,
54 | value: values[0]
55 | }),
56 | decl.clone({
57 | prop: `border-left${decl.prop.replace(matchLogicalBorderSide, '$2')}`,
58 | value: values[1] || values[0]
59 | })
60 | ];
61 | };
62 |
63 | const isLTR = 1 === values.length || 2 === values.length && values[0] === values[1];
64 | if (isLTR || dir === 'ltr') {
65 | ltrDecls();
66 | clean(decl, preserve);
67 | return;
68 | } else if (dir === 'rtl') {
69 | rtlDecls();
70 | clean(decl, preserve);
71 | return;
72 | } else {
73 | cloneRule(decl, 'ltr').append(ltrDecls());
74 | cloneRule(decl, 'rtl').append(rtlDecls());
75 | clean(decl, preserve);
76 | return;
77 | }
78 | },
79 |
80 | // border-inline-start
81 | 'border-inline-start': (decl, values, dir, preserve) => {
82 | const ltrDecl = () => {
83 | return decl.cloneBefore({
84 | prop: `border-left${decl.prop.replace(matchLogicalBorderSide, '$2')}`
85 | });
86 | };
87 |
88 | const rtlDecl = () => {
89 | return decl.cloneBefore({
90 | prop: `border-right${decl.prop.replace(matchLogicalBorderSide, '$2')}`
91 | });
92 | };
93 |
94 | if (dir === 'ltr') {
95 | ltrDecl();
96 | clean(decl, preserve);
97 | return;
98 | } else if (dir === 'rtl') {
99 | rtlDecl();
100 | clean(decl, preserve);
101 | return;
102 | } else {
103 | cloneRule(decl, 'ltr').append(ltrDecl());
104 | cloneRule(decl, 'rtl').append(rtlDecl());
105 | clean(decl, preserve);
106 | return;
107 | }
108 | },
109 |
110 | // border-inline-end
111 | 'border-inline-end': (decl, values, dir, preserve) => {
112 | const ltrDecl = () => {
113 | return decl.cloneBefore({
114 | prop: `border-right${decl.prop.replace(matchLogicalBorderSide, '$2')}`
115 | });
116 | };
117 |
118 | const rtlDecl = () => {
119 | return decl.cloneBefore({
120 | prop: `border-left${decl.prop.replace(matchLogicalBorderSide, '$2')}`
121 | });
122 | };
123 |
124 | if (dir === 'ltr') {
125 | ltrDecl();
126 | clean(decl, preserve);
127 | return;
128 | } else if (dir === 'rtl') {
129 | rtlDecl();
130 | clean(decl, preserve);
131 | return;
132 | } else {
133 | cloneRule(decl, 'ltr').append(ltrDecl());
134 | cloneRule(decl, 'rtl').append(rtlDecl());
135 | clean(decl, preserve);
136 | return;
137 | }
138 | }
139 | };
140 |
141 | function clean(decl, preserve) {
142 | if (!preserve) decl.remove();
143 | }
144 |
--------------------------------------------------------------------------------
/src/lib/transform-directional-shorthands.js:
--------------------------------------------------------------------------------
1 | import cloneRule from './clone-rule';
2 | import reduceValues from './reduce-values';
3 |
4 | export default (decl, values, dir, preserve) => {
5 | if ('logical' !== values[0]) {
6 | return null;
7 | }
8 |
9 | // get logical directions as all, inline, block-end, then inline-end
10 | const [, all, inline, blockEnd, inlineEnd ] = values;
11 |
12 | // get left-to-right relative directions from logical directions as:
13 | // → top from all
14 | // → right from inline-end, inline, or all
15 | // → bottom from block-end, block, or all
16 | // → left from inline, or all
17 | const ltrValues = reduceValues([
18 | all,
19 | inlineEnd || inline || all,
20 | blockEnd || all,
21 | inline || all
22 | ]);
23 |
24 | const ltrDecl = () => {
25 | return decl.cloneBefore({
26 | value: ltrValues.join(' ')
27 | });
28 | };
29 |
30 | // return the ltr values if the values are flow agnostic (where no second inline value was needed)
31 | const isFlowAgnostic = ltrValues.length < 4;
32 |
33 | if (isFlowAgnostic || dir === 'ltr') {
34 | ltrDecl();
35 | clean(decl, preserve);
36 | return;
37 | }
38 |
39 | // get right-to-left relative directions from logical directions as:
40 | // → top from all
41 | // → right from inline, or all
42 | // → bottom from block-end, block, or all
43 | // → left from inline-end, inline, or all
44 | const rtlValues = reduceValues([
45 | all,
46 | inline || all,
47 | blockEnd || all,
48 | inlineEnd || inline || all
49 | ]);
50 |
51 | const rtlDecl = () => {
52 | return decl.cloneBefore({
53 | value: rtlValues.join(' ')
54 | });
55 | };
56 |
57 | if (dir === 'rtl') {
58 | rtlDecl();
59 | clean(decl, preserve);
60 | return;
61 | }
62 |
63 | cloneRule(decl, 'ltr').append(ltrDecl());
64 | cloneRule(decl, 'rtl').append(rtlDecl());
65 | clean(decl, preserve);
66 | }
67 |
68 | function clean(decl, preserve) {
69 | if (!preserve) decl.remove();
70 | }
71 |
--------------------------------------------------------------------------------
/src/lib/transform-float.js:
--------------------------------------------------------------------------------
1 | import cloneRule from './clone-rule';
2 |
3 | export default (decl, values, dir, preserve) => {
4 | if (/^inline-start$/i.test(decl.value)) {
5 | if (dir === 'ltr') {
6 | lDecl(decl);
7 | clean(decl, preserve);
8 | return;
9 | } else if (dir === 'rtl') {
10 | rDecl(decl);
11 | clean(decl, preserve);
12 | return;
13 | } else {
14 | cloneRule(decl, 'ltr').append(lDecl(decl));
15 | cloneRule(decl, 'rtl').append(rDecl(decl));
16 | clean(decl, preserve);
17 | return;
18 | }
19 | } if (/^inline-end$/i.test(decl.value)) {
20 | if (dir === 'ltr') {
21 | rDecl(decl);
22 | clean(decl, preserve);
23 | return;
24 | } else if (dir === 'rtl') {
25 | lDecl(decl);
26 | clean(decl, preserve);
27 | return;
28 | } else {
29 | cloneRule(decl, 'ltr').append(rDecl(decl));
30 | cloneRule(decl, 'rtl').append(lDecl(decl));
31 | clean(decl, preserve);
32 | return;
33 | }
34 | }
35 | };
36 |
37 | function lDecl(decl) {
38 | return decl.cloneBefore({ value: 'left' });
39 | }
40 |
41 | function rDecl(decl) {
42 | return decl.cloneBefore({ value: 'right' });
43 | }
44 |
45 | function clean(decl, preserve) {
46 | if (!preserve) decl.remove();
47 | }
48 |
--------------------------------------------------------------------------------
/src/lib/transform-inset.js:
--------------------------------------------------------------------------------
1 | import cloneRule from './clone-rule';
2 |
3 | export default (decl, values, dir, preserve) => {
4 | if ('logical' !== values[0]) {
5 | decl.cloneBefore({ prop: 'top', value: values[0] });
6 | decl.cloneBefore({ prop: 'right', value: values[1] || values[0] });
7 | decl.cloneBefore({ prop: 'bottom', value: values[2] || values[0] });
8 | decl.cloneBefore({ prop: 'left', value: values[3] || values[1] || values[0] });
9 | clean(decl, preserve);
10 | return;
11 | }
12 |
13 | const isLTR = !values[4] || values[4] === values[2];
14 |
15 | if (isLTR || dir === 'ltr') {
16 | lDecl(decl, values);
17 | clean(decl, preserve);
18 | return;
19 | } else if (dir === 'rtl') {
20 | rDecl(decl, values);
21 | clean(decl, preserve);
22 | return;
23 | } else {
24 | cloneRule(decl, 'ltr').append(lDecl(decl, values));
25 | cloneRule(decl, 'rtl').append(rDecl(decl, values));
26 | clean(decl, preserve);
27 | return;
28 | }
29 | }
30 |
31 | function lDecl(decl, values) {
32 | return [
33 | decl.cloneBefore({ prop: 'top', value: values[1] }),
34 | decl.cloneBefore({ prop: 'left', value: values[2] || values[1] }),
35 | decl.cloneBefore({ prop: 'bottom', value: values[3] || values[1] }),
36 | decl.cloneBefore({ prop: 'right', value: values[4] || values[2] || values[1] })
37 | ];
38 | }
39 |
40 | function rDecl(decl, values) {
41 | return [
42 | decl.cloneBefore({ prop: 'top', value: values[1] }),
43 | decl.cloneBefore({ prop: 'right', value: values[2] || values[1] }),
44 | decl.cloneBefore({ prop: 'bottom', value: values[3] || values[1] }),
45 | decl.cloneBefore({ prop: 'left', value: values[4] || values[2] || values[1] })
46 | ];
47 | }
48 |
49 | function clean(decl, preserve) {
50 | if (!preserve) decl.remove();
51 | }
52 |
--------------------------------------------------------------------------------
/src/lib/transform-resize.js:
--------------------------------------------------------------------------------
1 | export default (decl, values, dir, preserve) => {
2 | if (/^block$/i.test(decl.value)) {
3 | decl.cloneBefore({ value: 'vertical' });
4 | clean(decl, preserve);
5 | return;
6 | } else if (/^inline$/i.test(decl.value)) {
7 | decl.cloneBefore({ value: 'horizontal' });
8 | clean(decl, preserve);
9 | return;
10 | }
11 | }
12 |
13 | function clean(decl, preserve) {
14 | if (!preserve) decl.remove();
15 | }
16 |
--------------------------------------------------------------------------------
/src/lib/transform-side.js:
--------------------------------------------------------------------------------
1 | import cloneDeclBefore from './clone-decl';
2 | import cloneRule from './clone-rule';
3 | import matchSide from './match-side';
4 |
5 | import matchInsetPrefix from './match-inset-prefix';
6 |
7 | export default {
8 | // inset-block, margin-block, padding-block
9 | 'block': (decl, values, dir, preserve) => {
10 | cloneDeclBefore(decl, '-top', values[0]);
11 | cloneDeclBefore(decl, '-bottom', values[1] || values[0]);
12 | clean(decl, preserve);
13 | },
14 |
15 | // inset-block-start, margin-block-start, padding-block-start
16 | 'block-start': (decl, values, dir, preserve) => {
17 | decl.cloneBefore({ prop: decl.prop.replace(matchSide, '$1-top').replace(matchInsetPrefix, '') });
18 | clean(decl, preserve);
19 | },
20 |
21 | // inset-block-end, margin-block-end, padding-block-end
22 | 'block-end': (decl, values, dir, preserve) => {
23 | decl.cloneBefore({ prop: decl.prop.replace(matchSide, '$1-bottom').replace(matchInsetPrefix, '') });
24 | clean(decl, preserve);
25 | },
26 |
27 | // inset-inline, margin-inline, padding-inline
28 | 'inline': (decl, values, dir, preserve) => {
29 | const ltrDecls = () => {
30 | return [
31 | cloneDeclBefore(decl, '-left', values[0]),
32 | cloneDeclBefore(decl, '-right', values[1] || values[0])
33 | ];
34 | };
35 |
36 | const rtlDecls = () => {
37 | return [
38 | cloneDeclBefore(decl, '-right', values[0]),
39 | cloneDeclBefore(decl, '-left', values[1] || values[0])
40 | ];
41 | };
42 |
43 | const isLTR = 1 === values.length || 2 === values.length && values[0] === values[1];
44 | if (isLTR || dir === 'ltr') {
45 | ltrDecls();
46 | clean(decl, preserve);
47 | return;
48 | } else if (dir === 'rtl') {
49 | rtlDecls();
50 | clean(decl, preserve);
51 | return;
52 | } else {
53 | cloneRule(decl, 'ltr').append(ltrDecls());
54 | cloneRule(decl, 'rtl').append(rtlDecls());
55 | clean(decl, preserve);
56 | return;
57 | }
58 | },
59 |
60 | // inset-inline-start, margin-inline-start, padding-inline-start
61 | 'inline-start': (decl, values, dir, preserve) => {
62 | const ltrDecl = () => {
63 | return cloneDeclBefore(decl, '-left', decl.value);
64 | };
65 | const rtlDecl = () => {
66 | return cloneDeclBefore(decl, '-right', decl.value);
67 | };
68 |
69 | if (dir === 'ltr') {
70 | ltrDecl();
71 | clean(decl, preserve);
72 | return;
73 | } else if (dir === 'rtl') {
74 | rtlDecl();
75 | clean(decl, preserve);
76 | return;
77 | } else {
78 | cloneRule(decl, 'ltr').append(ltrDecl());
79 | cloneRule(decl, 'rtl').append(rtlDecl());
80 | clean(decl, preserve);
81 | return;
82 | }
83 | },
84 |
85 | // inset-inline-end, margin-inline-end, padding-inline-end
86 | 'inline-end': (decl, values, dir, preserve) => {
87 | const ltrDecl = () => {
88 | return cloneDeclBefore(decl, '-right', decl.value);
89 | };
90 | const rtlDecl = () => {
91 | return cloneDeclBefore(decl, '-left', decl.value);
92 | };
93 |
94 | if (dir === 'ltr') {
95 | ltrDecl();
96 | clean(decl, preserve);
97 | return;
98 | } else if (dir === 'rtl') {
99 | rtlDecl();
100 | clean(decl, preserve);
101 | return;
102 | } else {
103 | cloneRule(decl, 'ltr').append(ltrDecl());
104 | cloneRule(decl, 'rtl').append(rtlDecl());
105 | clean(decl, preserve);
106 | return;
107 | }
108 | }
109 | }
110 |
111 | function clean(decl, preserve) {
112 | if (!preserve) decl.remove();
113 | }
114 |
--------------------------------------------------------------------------------
/src/lib/transform-size.js:
--------------------------------------------------------------------------------
1 | import matchSize from './match-size';
2 |
3 | export default (decl, values, dir, preserve) => {
4 | decl.cloneBefore({
5 | prop: decl.prop.replace(
6 | matchSize,
7 | ($0, minmax, flow) => `${minmax || ''}${'block' === flow ? 'height' : 'width'}`
8 | )
9 | });
10 |
11 | if (!preserve) {
12 | decl.remove();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/transform-text-align.js:
--------------------------------------------------------------------------------
1 | import cloneRule from './clone-rule';
2 |
3 | export default (decl, values, dir, preserve) => {
4 | if (/^start$/i.test(decl.value)) {
5 | if (dir === 'ltr') {
6 | lDecl(decl);
7 | clean(decl, preserve);
8 | return;
9 | } else if (dir === 'rtl') {
10 | rDecl(decl);
11 | clean(decl, preserve);
12 | return;
13 | } else {
14 | cloneRule(decl, 'ltr').append(lDecl(decl));
15 | cloneRule(decl, 'rtl').append(rDecl(decl));
16 | clean(decl, preserve);
17 | return;
18 | }
19 | } else if (/^end$/i.test(decl.value)) {
20 | if (dir === 'ltr') {
21 | rDecl(decl);
22 | clean(decl, preserve);
23 | return;
24 | } else if (dir === 'rtl') {
25 | lDecl(decl);
26 | clean(decl, preserve);
27 | return;
28 | } else {
29 | cloneRule(decl, 'ltr').append(rDecl(decl));
30 | cloneRule(decl, 'rtl').append(lDecl(decl));
31 | clean(decl, preserve);
32 | return;
33 | }
34 | }
35 | };
36 |
37 | function lDecl(decl) {
38 | return decl.cloneBefore({ value: 'left' });
39 | }
40 |
41 | function rDecl(decl) {
42 | return decl.cloneBefore({ value: 'right' });
43 | }
44 |
45 | function clean(decl, preserve) {
46 | if (!preserve) decl.remove();
47 | }
48 |
--------------------------------------------------------------------------------
/src/lib/transform-transition.js:
--------------------------------------------------------------------------------
1 | import cloneRule from './clone-rule';
2 | import { splitByComma, splitBySpace } from './split';
3 |
4 | export default (decl, notValues, dir, preserve) => {
5 | const ltrValues = [];
6 | const rtlValues = [];
7 |
8 | splitByComma(decl.value).forEach(value => {
9 | let hasBeenSplit = false;
10 |
11 | splitBySpace(value).forEach((word, index, words) => {
12 | if (word in valueMap) {
13 | hasBeenSplit = true;
14 |
15 | valueMap[word].ltr.forEach(replacement => {
16 | const clone = words.slice();
17 |
18 | clone.splice(index, 1, replacement);
19 |
20 | if (ltrValues.length && !/^,$/.test(ltrValues[ltrValues.length - 1])) {
21 | ltrValues.push(',');
22 | }
23 |
24 | ltrValues.push(clone.join(''));
25 | });
26 |
27 | valueMap[word].rtl.forEach(replacement => {
28 | const clone = words.slice();
29 |
30 | clone.splice(index, 1, replacement);
31 |
32 | if (rtlValues.length && !/^,$/.test(rtlValues[rtlValues.length - 1])) {
33 | rtlValues.push(',');
34 | }
35 |
36 | rtlValues.push(clone.join(''));
37 | });
38 | }
39 | });
40 |
41 | if (!hasBeenSplit) {
42 | ltrValues.push(value);
43 | rtlValues.push(value);
44 | }
45 | });
46 |
47 | if (ltrValues.length && dir === 'ltr') {
48 | if (preserve) {
49 | decl.cloneBefore({});
50 | }
51 | decl.assign({ value: ltrValues.join('') });
52 | return;
53 | } else if (rtlValues.length && dir === 'rtl') {
54 | if (preserve) {
55 | decl.cloneBefore({});
56 | }
57 | decl.assign({ value: rtlValues.join('') });
58 | return;
59 | } else if (ltrValues.join('') !== rtlValues.join('')) {
60 |
61 | cloneRule(decl, 'ltr').append(decl.cloneBefore({ value: ltrValues.join('') }));
62 | cloneRule(decl, 'rtl').append(decl.cloneBefore({ value: rtlValues.join('') }));
63 | clean(decl, preserve);
64 | return;
65 | }
66 | };
67 |
68 | function clean(decl, preserve) {
69 | if (!preserve) decl.remove();
70 | }
71 |
72 | const valueMap = {
73 | // Logical Height and Logical Width
74 | 'block-size': { ltr: ['height'], rtl: ['height'] },
75 | 'inline-size': { ltr: ['width'], rtl: ['width'] },
76 |
77 | // Flow-relative Margins
78 | 'margin-block-end': { ltr: ['margin-bottom'], rtl: ['margin-bottom'] },
79 | 'margin-block-start': { ltr: ['margin-top'], rtl: ['margin-top'] },
80 | 'margin-block': { ltr: ['margin-top', 'margin-bottom'], rtl: ['margin-top', 'margin-bottom'] },
81 | 'margin-inline-end': { ltr: ['margin-right'], rtl: ['margin-left'] },
82 | 'margin-inline-start': { ltr: ['margin-left'], rtl: ['margin-right'] },
83 | 'margin-inline': { ltr: ['margin-left', 'margin-right'], rtl: ['margin-left', 'margin-right'] },
84 |
85 | // Flow-relative Offsets
86 | 'inset-block-end': { ltr: ['bottom'], rtl: ['bottom'] },
87 | 'inset-block-start': { ltr: ['top'], rtl: ['top'] },
88 | 'inset-block': { ltr: ['top', 'bottom'], rtl: ['top', 'bottom'] },
89 | 'inset-inline-end': { ltr: ['right'], rtl: ['left'] },
90 | 'inset-inline-start': { ltr: ['left'], rtl: ['right'] },
91 | 'inset-inline': { ltr: ['left', 'right'], rtl: ['left', 'right'] },
92 | 'inset': { ltr: ['top', 'right', 'bottom', 'left'], rtl: ['top', 'right', 'bottom', 'left'] },
93 |
94 | // Flow-relative Padding
95 | 'padding-block-end': { ltr: ['padding-bottom'], rtl: ['padding-bottom'] },
96 | 'padding-block-start': { ltr: ['padding-top'], rtl: ['padding-top'] },
97 | 'padding-block': { ltr: ['padding-top', 'padding-bottom'], rtl: ['padding-top', 'padding-bottom'] },
98 | 'padding-inline-end': { ltr: ['padding-right'], rtl: ['padding-left'] },
99 | 'padding-inline-start': { ltr: ['padding-left'], rtl: ['padding-right'] },
100 | 'padding-inline': { ltr: ['padding-left', 'padding-right'], rtl: ['padding-left', 'padding-right'] },
101 |
102 | // Flow-relative Borders
103 | 'border-block-color': { ltr: ['border-top-color', 'border-bottom-color'], rtl: ['border-top-color', 'border-bottom-color'] },
104 | 'border-block-end-color': { ltr: ['border-bottom-color'], rtl: ['border-bottom-color'] },
105 | 'border-block-end-style': { ltr: ['border-bottom-style'], rtl: ['border-bottom-style'] },
106 | 'border-block-end-width': { ltr: ['border-bottom-width'], rtl: ['border-bottom-width'] },
107 | 'border-block-end': { ltr: ['border-bottom'], rtl: ['border-bottom'] },
108 | 'border-block-start-color': { ltr: ['border-top-color'], rtl: ['border-top-color'] },
109 | 'border-block-start-style': { ltr: ['border-top-style'], rtl: ['border-top-style'] },
110 | 'border-block-start-width': { ltr: ['border-top-width'], rtl: ['border-top-width'] },
111 | 'border-block-start': { ltr: ['border-top'], rtl: ['border-top'] },
112 | 'border-block-style': { ltr: ['border-top-style', 'border-bottom-style'], rtl: ['border-top-style', 'border-bottom-style'] },
113 | 'border-block-width': { ltr: ['border-top-width', 'border-bottom-width'], rtl: ['border-top-width', 'border-bottom-width'] },
114 | 'border-block': { ltr: ['border-top', 'border-bottom'], rtl: ['border-top', 'border-bottom'] },
115 | 'border-inline-color': { ltr: ['border-left-color', 'border-right-color'], rtl: ['border-left-color', 'border-right-color'] },
116 | 'border-inline-end-color': { ltr: ['border-right-color'], rtl: ['border-left-color'] },
117 | 'border-inline-end-style': { ltr: ['border-right-style'], rtl: ['border-left-style'] },
118 | 'border-inline-end-width': { ltr: ['border-right-width'], rtl: ['border-left-width'] },
119 | 'border-inline-end': { ltr: ['border-right'], rtl: ['border-left'] },
120 | 'border-inline-start-color': { ltr: ['border-left-color'], rtl: ['border-right-color'] },
121 | 'border-inline-start-style': { ltr: ['border-left-style'], rtl: ['border-right-style'] },
122 | 'border-inline-start-width': { ltr: ['border-left-width'], rtl: ['border-right-width'] },
123 | 'border-inline-start': { ltr: ['border-left'], rtl: ['border-right'] },
124 | 'border-inline-style': { ltr: ['border-left-style', 'border-right-style'], rtl: ['border-left-style', 'border-right-style'] },
125 | 'border-inline-width': { ltr: ['border-left-width', 'border-right-width'], rtl: ['border-left-width', 'border-right-width'] },
126 | 'border-inline': { ltr: ['border-left', 'border-right'], rtl: ['border-left', 'border-right'] },
127 |
128 | // Flow-relative Corner Rounding
129 | 'border-end-end-radius': { ltr: ['border-bottom-right-radius'], rtl: ['border-bottom-left-radius'] },
130 | 'border-end-start-radius': { ltr: ['border-bottom-left-radius'], rtl: ['border-bottom-right-radius'] },
131 | 'border-start-end-radius': { ltr: ['border-top-right-radius'], rtl: ['border-top-left-radius'] },
132 | 'border-start-start-radius': { ltr: ['border-top-left-radius'], rtl: ['border-top-right-radius'] }
133 | };
134 |
--------------------------------------------------------------------------------
/test/border.css:
--------------------------------------------------------------------------------
1 | test-border {
2 | border: inherit;
3 | border-block: 1px solid black;
4 | border: inherit;
5 | border-block-start: 2px solid black;
6 | border: inherit;
7 | border-block-end: 3px solid black;
8 | border: inherit;
9 | border-inline: 4px solid black;
10 | border: inherit;
11 | }
12 |
13 | test-flowing-border {
14 | border: inherit;
15 | border-inline-start: 1px solid black;
16 | border: inherit;
17 | border-inline-end: 2px solid black;
18 | border: inherit;
19 | }
20 |
21 | test-border-color {
22 | border-color: inherit;
23 | border-color: logical red;
24 | border-color: inherit;
25 | border-color: logical orange yellow;
26 | border-color: inherit;
27 | border-color: logical green blue indigo;
28 | border-color: inherit;
29 | border-block-color: violet;
30 | border-color: inherit;
31 | border-block-start-color: white;
32 | border-color: inherit;
33 | border-block-end-color: black;
34 | border-color: inherit;
35 | border-inline-color: grey;
36 | border-color: inherit;
37 | }
38 |
39 | test-flowing-border-width {
40 | border-width: logical 1px 2px 3px 4px;
41 | border-width: inherit;
42 | border-inline-width: 2px 4px;
43 | border-width: inherit;
44 | border-inline-start-width: 2px;
45 | border-width: inherit;
46 | border-inline-end-width: 4px;
47 | border-width: inherit;
48 | border-block-width: 2px 4px;
49 | }
50 |
51 | test-flowing-border-radius {
52 | border-start-start-radius: 1px;
53 | border-start-end-radius: 2px;
54 | border-end-start-radius: 3px;
55 | border-end-end-radius: 4px;
56 | }
57 |
--------------------------------------------------------------------------------
/test/border.expect.css:
--------------------------------------------------------------------------------
1 | test-border {
2 | border: inherit;
3 | border-top: 1px solid black;
4 | border-bottom: 1px solid black;
5 | border: inherit;
6 | border-top: 2px solid black;
7 | border: inherit;
8 | border-bottom: 3px solid black;
9 | border: inherit;
10 | border-left: 4px solid black;
11 | border-right: 4px solid black;
12 | border: inherit;
13 | }
14 |
15 | test-flowing-border:dir(ltr) {
16 | border-left: 1px solid black;
17 | }
18 |
19 | test-flowing-border:dir(rtl) {
20 | border-right: 1px solid black;
21 | }
22 |
23 | test-flowing-border:dir(ltr) {
24 | border-right: 2px solid black;
25 | }
26 |
27 | test-flowing-border:dir(rtl) {
28 | border-left: 2px solid black;
29 | }
30 |
31 | test-flowing-border {
32 | border: inherit;
33 | border: inherit;
34 | border: inherit;
35 | }
36 |
37 | test-border-color {
38 | border-color: inherit;
39 | border-color: red;
40 | border-color: inherit;
41 | border-color: orange yellow;
42 | border-color: inherit;
43 | border-color: green blue indigo;
44 | border-color: inherit;
45 | border-top-color: violet;
46 | border-bottom-color: violet;
47 | border-color: inherit;
48 | border-top-color: white;
49 | border-color: inherit;
50 | border-bottom-color: black;
51 | border-color: inherit;
52 | border-left-color: grey;
53 | border-right-color: grey;
54 | border-color: inherit;
55 | }
56 |
57 | test-flowing-border-width:dir(ltr) {
58 | border-width: 1px 4px 3px 2px;
59 | }
60 |
61 | test-flowing-border-width:dir(rtl) {
62 | border-width: 1px 2px 3px 4px;
63 | }
64 |
65 | test-flowing-border-width:dir(ltr) {
66 | border-left-width: 2px;
67 | border-right-width: 4px;
68 | }
69 |
70 | test-flowing-border-width:dir(rtl) {
71 | border-right-width: 2px;
72 | border-left-width: 4px;
73 | }
74 |
75 | test-flowing-border-width:dir(ltr) {
76 | border-left-width: 2px;
77 | }
78 |
79 | test-flowing-border-width:dir(rtl) {
80 | border-right-width: 2px;
81 | }
82 |
83 | test-flowing-border-width:dir(ltr) {
84 | border-right-width: 4px;
85 | }
86 |
87 | test-flowing-border-width:dir(rtl) {
88 | border-left-width: 4px;
89 | }
90 |
91 | test-flowing-border-width {
92 | border-width: inherit;
93 | border-width: inherit;
94 | border-width: inherit;
95 | border-width: inherit;
96 | border-top-width: 2px;
97 | border-bottom-width: 4px;
98 | }
99 |
100 | test-flowing-border-radius:dir(ltr) {
101 | border-top-left-radius: 1px;
102 | }
103 |
104 | test-flowing-border-radius:dir(rtl) {
105 | border-top-right-radius: 1px;
106 | }
107 |
108 | test-flowing-border-radius:dir(ltr) {
109 | border-top-right-radius: 2px;
110 | }
111 |
112 | test-flowing-border-radius:dir(rtl) {
113 | border-top-left-radius: 2px;
114 | }
115 |
116 | test-flowing-border-radius:dir(ltr) {
117 | border-bottom-left-radius: 3px;
118 | }
119 |
120 | test-flowing-border-radius:dir(rtl) {
121 | border-bottom-right-radius: 3px;
122 | }
123 |
124 | test-flowing-border-radius:dir(ltr) {
125 | border-bottom-right-radius: 4px;
126 | }
127 |
128 | test-flowing-border-radius:dir(rtl) {
129 | border-bottom-left-radius: 4px;
130 | }
131 |
--------------------------------------------------------------------------------
/test/border.ltr.expect.css:
--------------------------------------------------------------------------------
1 | test-border {
2 | border: inherit;
3 | border-top: 1px solid black;
4 | border-bottom: 1px solid black;
5 | border: inherit;
6 | border-top: 2px solid black;
7 | border: inherit;
8 | border-bottom: 3px solid black;
9 | border: inherit;
10 | border-left: 4px solid black;
11 | border-right: 4px solid black;
12 | border: inherit;
13 | }
14 |
15 | test-flowing-border {
16 | border: inherit;
17 | border-left: 1px solid black;
18 | border: inherit;
19 | border-right: 2px solid black;
20 | border: inherit;
21 | }
22 |
23 | test-border-color {
24 | border-color: inherit;
25 | border-color: red;
26 | border-color: inherit;
27 | border-color: orange yellow;
28 | border-color: inherit;
29 | border-color: green blue indigo;
30 | border-color: inherit;
31 | border-top-color: violet;
32 | border-bottom-color: violet;
33 | border-color: inherit;
34 | border-top-color: white;
35 | border-color: inherit;
36 | border-bottom-color: black;
37 | border-color: inherit;
38 | border-left-color: grey;
39 | border-right-color: grey;
40 | border-color: inherit;
41 | }
42 |
43 | test-flowing-border-width {
44 | border-width: 1px 4px 3px 2px;
45 | border-width: inherit;
46 | border-left-width: 2px;
47 | border-right-width: 4px;
48 | border-width: inherit;
49 | border-left-width: 2px;
50 | border-width: inherit;
51 | border-right-width: 4px;
52 | border-width: inherit;
53 | border-top-width: 2px;
54 | border-bottom-width: 4px;
55 | }
56 |
57 | test-flowing-border-radius {
58 | border-top-left-radius: 1px;
59 | border-top-right-radius: 2px;
60 | border-bottom-left-radius: 3px;
61 | border-bottom-right-radius: 4px;
62 | }
63 |
--------------------------------------------------------------------------------
/test/border.preserve.expect.css:
--------------------------------------------------------------------------------
1 | test-border {
2 | border: inherit;
3 | border-top: 1px solid black;
4 | border-bottom: 1px solid black;
5 | border-block: 1px solid black;
6 | border: inherit;
7 | border-top: 2px solid black;
8 | border-block-start: 2px solid black;
9 | border: inherit;
10 | border-bottom: 3px solid black;
11 | border-block-end: 3px solid black;
12 | border: inherit;
13 | border-left: 4px solid black;
14 | border-right: 4px solid black;
15 | border-inline: 4px solid black;
16 | border: inherit;
17 | }
18 |
19 | test-flowing-border:dir(ltr) {
20 | border-left: 1px solid black;
21 | }
22 |
23 | test-flowing-border:dir(rtl) {
24 | border-right: 1px solid black;
25 | }
26 |
27 | test-flowing-border:dir(ltr) {
28 | border-right: 2px solid black;
29 | }
30 |
31 | test-flowing-border:dir(rtl) {
32 | border-left: 2px solid black;
33 | }
34 |
35 | test-flowing-border {
36 | border: inherit;
37 | border-inline-start: 1px solid black;
38 | border: inherit;
39 | border-inline-end: 2px solid black;
40 | border: inherit;
41 | }
42 |
43 | test-border-color {
44 | border-color: inherit;
45 | border-color: red;
46 | border-color: logical red;
47 | border-color: inherit;
48 | border-color: orange yellow;
49 | border-color: logical orange yellow;
50 | border-color: inherit;
51 | border-color: green blue indigo;
52 | border-color: logical green blue indigo;
53 | border-color: inherit;
54 | border-top-color: violet;
55 | border-bottom-color: violet;
56 | border-block-color: violet;
57 | border-color: inherit;
58 | border-top-color: white;
59 | border-block-start-color: white;
60 | border-color: inherit;
61 | border-bottom-color: black;
62 | border-block-end-color: black;
63 | border-color: inherit;
64 | border-left-color: grey;
65 | border-right-color: grey;
66 | border-inline-color: grey;
67 | border-color: inherit;
68 | }
69 |
70 | test-flowing-border-width:dir(ltr) {
71 | border-width: 1px 4px 3px 2px;
72 | }
73 |
74 | test-flowing-border-width:dir(rtl) {
75 | border-width: 1px 2px 3px 4px;
76 | }
77 |
78 | test-flowing-border-width:dir(ltr) {
79 | border-left-width: 2px;
80 | border-right-width: 4px;
81 | }
82 |
83 | test-flowing-border-width:dir(rtl) {
84 | border-right-width: 2px;
85 | border-left-width: 4px;
86 | }
87 |
88 | test-flowing-border-width:dir(ltr) {
89 | border-left-width: 2px;
90 | }
91 |
92 | test-flowing-border-width:dir(rtl) {
93 | border-right-width: 2px;
94 | }
95 |
96 | test-flowing-border-width:dir(ltr) {
97 | border-right-width: 4px;
98 | }
99 |
100 | test-flowing-border-width:dir(rtl) {
101 | border-left-width: 4px;
102 | }
103 |
104 | test-flowing-border-width {
105 | border-width: logical 1px 2px 3px 4px;
106 | border-width: inherit;
107 | border-inline-width: 2px 4px;
108 | border-width: inherit;
109 | border-inline-start-width: 2px;
110 | border-width: inherit;
111 | border-inline-end-width: 4px;
112 | border-width: inherit;
113 | border-top-width: 2px;
114 | border-bottom-width: 4px;
115 | border-block-width: 2px 4px;
116 | }
117 |
118 | test-flowing-border-radius:dir(ltr) {
119 | border-top-left-radius: 1px;
120 | }
121 |
122 | test-flowing-border-radius:dir(rtl) {
123 | border-top-right-radius: 1px;
124 | }
125 |
126 | test-flowing-border-radius:dir(ltr) {
127 | border-top-right-radius: 2px;
128 | }
129 |
130 | test-flowing-border-radius:dir(rtl) {
131 | border-top-left-radius: 2px;
132 | }
133 |
134 | test-flowing-border-radius:dir(ltr) {
135 | border-bottom-left-radius: 3px;
136 | }
137 |
138 | test-flowing-border-radius:dir(rtl) {
139 | border-bottom-right-radius: 3px;
140 | }
141 |
142 | test-flowing-border-radius:dir(ltr) {
143 | border-bottom-right-radius: 4px;
144 | }
145 |
146 | test-flowing-border-radius:dir(rtl) {
147 | border-bottom-left-radius: 4px;
148 | }
149 |
150 | test-flowing-border-radius {
151 | border-start-start-radius: 1px;
152 | border-start-end-radius: 2px;
153 | border-end-start-radius: 3px;
154 | border-end-end-radius: 4px;
155 | }
156 |
--------------------------------------------------------------------------------
/test/clear.css:
--------------------------------------------------------------------------------
1 | test-clear {
2 | clear: both;
3 | clear: left;
4 | clear: inline-start;
5 | clear: inline-end;
6 | clear: right;
7 | }
8 |
--------------------------------------------------------------------------------
/test/clear.expect.css:
--------------------------------------------------------------------------------
1 | test-clear:dir(ltr) {
2 | clear: left;
3 | }
4 | test-clear:dir(rtl) {
5 | clear: right;
6 | }
7 | test-clear:dir(ltr) {
8 | clear: right;
9 | }
10 | test-clear:dir(rtl) {
11 | clear: left;
12 | }
13 | test-clear {
14 | clear: both;
15 | clear: left;
16 | clear: right;
17 | }
18 |
--------------------------------------------------------------------------------
/test/clear.ltr.expect.css:
--------------------------------------------------------------------------------
1 | test-clear {
2 | clear: both;
3 | clear: left;
4 | clear: left;
5 | clear: right;
6 | clear: right;
7 | }
8 |
--------------------------------------------------------------------------------
/test/float.css:
--------------------------------------------------------------------------------
1 | test-float {
2 | float: left;
3 | float: inline-start;
4 | float: inline-end;
5 | float: right;
6 | }
7 |
--------------------------------------------------------------------------------
/test/float.expect.css:
--------------------------------------------------------------------------------
1 | test-float:dir(ltr) {
2 | float: left;
3 | }
4 | test-float:dir(rtl) {
5 | float: right;
6 | }
7 | test-float:dir(ltr) {
8 | float: right;
9 | }
10 | test-float:dir(rtl) {
11 | float: left;
12 | }
13 | test-float {
14 | float: left;
15 | float: right;
16 | }
17 |
--------------------------------------------------------------------------------
/test/float.ltr.expect.css:
--------------------------------------------------------------------------------
1 | test-float {
2 | float: left;
3 | float: left;
4 | float: right;
5 | float: right;
6 | }
7 |
--------------------------------------------------------------------------------
/test/inset.css:
--------------------------------------------------------------------------------
1 | test-inset {
2 | inset: 0;
3 | inset: logical 1px;
4 | inset: logical 2px 3px;
5 | inset: logical 4px 5px 6px;
6 | inset: logical 7px 8px 9px 8px;
7 | }
8 |
9 | test-flowing-inset {
10 | inset: auto;
11 | inset: logical 1px 2px 3px 4px;
12 | inset: auto;
13 | inset-inline: 5px 6px;
14 | inset: auto;
15 | inset-inline-start: 7px;
16 | inset: auto;
17 | inset-inline-end: 8px;
18 | inset: auto;
19 | }
20 |
--------------------------------------------------------------------------------
/test/inset.expect.css:
--------------------------------------------------------------------------------
1 | test-inset {
2 | top: 0;
3 | right: 0;
4 | bottom: 0;
5 | left: 0;
6 | top: 1px;
7 | left: 1px;
8 | bottom: 1px;
9 | right: 1px;
10 | top: 2px;
11 | left: 3px;
12 | bottom: 2px;
13 | right: 3px;
14 | top: 4px;
15 | left: 5px;
16 | bottom: 6px;
17 | right: 5px;
18 | top: 7px;
19 | left: 8px;
20 | bottom: 9px;
21 | right: 8px;
22 | }
23 |
24 | test-flowing-inset:dir(ltr) {
25 | top: 1px;
26 | left: 2px;
27 | bottom: 3px;
28 | right: 4px;
29 | }
30 |
31 | test-flowing-inset:dir(rtl) {
32 | top: 1px;
33 | right: 2px;
34 | bottom: 3px;
35 | left: 4px;
36 | }
37 |
38 | test-flowing-inset:dir(ltr) {
39 | left: 5px;
40 | right: 6px;
41 | }
42 |
43 | test-flowing-inset:dir(rtl) {
44 | right: 5px;
45 | left: 6px;
46 | }
47 |
48 | test-flowing-inset:dir(ltr) {
49 | left: 7px;
50 | }
51 |
52 | test-flowing-inset:dir(rtl) {
53 | right: 7px;
54 | }
55 |
56 | test-flowing-inset:dir(ltr) {
57 | right: 8px;
58 | }
59 |
60 | test-flowing-inset:dir(rtl) {
61 | left: 8px;
62 | }
63 |
64 | test-flowing-inset {
65 | top: auto;
66 | right: auto;
67 | bottom: auto;
68 | left: auto;
69 | top: auto;
70 | right: auto;
71 | bottom: auto;
72 | left: auto;
73 | top: auto;
74 | right: auto;
75 | bottom: auto;
76 | left: auto;
77 | top: auto;
78 | right: auto;
79 | bottom: auto;
80 | left: auto;
81 | top: auto;
82 | right: auto;
83 | bottom: auto;
84 | left: auto;
85 | }
86 |
--------------------------------------------------------------------------------
/test/inset.ltr.expect.css:
--------------------------------------------------------------------------------
1 | test-inset {
2 | top: 0;
3 | right: 0;
4 | bottom: 0;
5 | left: 0;
6 | top: 1px;
7 | left: 1px;
8 | bottom: 1px;
9 | right: 1px;
10 | top: 2px;
11 | left: 3px;
12 | bottom: 2px;
13 | right: 3px;
14 | top: 4px;
15 | left: 5px;
16 | bottom: 6px;
17 | right: 5px;
18 | top: 7px;
19 | left: 8px;
20 | bottom: 9px;
21 | right: 8px;
22 | }
23 |
24 | test-flowing-inset {
25 | top: auto;
26 | right: auto;
27 | bottom: auto;
28 | left: auto;
29 | top: 1px;
30 | left: 2px;
31 | bottom: 3px;
32 | right: 4px;
33 | top: auto;
34 | right: auto;
35 | bottom: auto;
36 | left: auto;
37 | left: 5px;
38 | right: 6px;
39 | top: auto;
40 | right: auto;
41 | bottom: auto;
42 | left: auto;
43 | left: 7px;
44 | top: auto;
45 | right: auto;
46 | bottom: auto;
47 | left: auto;
48 | right: 8px;
49 | top: auto;
50 | right: auto;
51 | bottom: auto;
52 | left: auto;
53 | }
54 |
--------------------------------------------------------------------------------
/test/margin.css:
--------------------------------------------------------------------------------
1 | test-margin {
2 | margin: logical 1px;
3 | margin: logical 2px 3px;
4 | margin: logical 4px 5px 6px;
5 | margin: logical 7px 8px 9px 8px;
6 | margin-inline: 10px;
7 | margin-inline: 11px 11px;
8 | margin-block: 12px;
9 | margin-block: 13px 14px;
10 | margin-block-start: 15px;
11 | margin-block-end: 16px;
12 | }
13 |
14 | test-flowing-margin {
15 | margin: auto;
16 | margin: logical 1px 2px 3px 4px;
17 | margin: auto;
18 | margin-inline: 5px 6px;
19 | margin: auto;
20 | margin-inline-start: 7px;
21 | margin: auto;
22 | margin-inline-end: 8px;
23 | margin: auto;
24 | }
25 |
--------------------------------------------------------------------------------
/test/margin.expect.css:
--------------------------------------------------------------------------------
1 | test-margin {
2 | margin: 1px;
3 | margin: 2px 3px;
4 | margin: 4px 5px 6px;
5 | margin: 7px 8px 9px;
6 | margin-left: 10px;
7 | margin-right: 10px;
8 | margin-left: 11px;
9 | margin-right: 11px;
10 | margin-top: 12px;
11 | margin-bottom: 12px;
12 | margin-top: 13px;
13 | margin-bottom: 14px;
14 | margin-top: 15px;
15 | margin-bottom: 16px;
16 | }
17 |
18 | test-flowing-margin:dir(ltr) {
19 | margin: 1px 4px 3px 2px;
20 | }
21 |
22 | test-flowing-margin:dir(rtl) {
23 | margin: 1px 2px 3px 4px;
24 | }
25 |
26 | test-flowing-margin:dir(ltr) {
27 | margin-left: 5px;
28 | margin-right: 6px;
29 | }
30 |
31 | test-flowing-margin:dir(rtl) {
32 | margin-right: 5px;
33 | margin-left: 6px;
34 | }
35 |
36 | test-flowing-margin:dir(ltr) {
37 | margin-left: 7px;
38 | }
39 |
40 | test-flowing-margin:dir(rtl) {
41 | margin-right: 7px;
42 | }
43 |
44 | test-flowing-margin:dir(ltr) {
45 | margin-right: 8px;
46 | }
47 |
48 | test-flowing-margin:dir(rtl) {
49 | margin-left: 8px;
50 | }
51 |
52 | test-flowing-margin {
53 | margin: auto;
54 | margin: auto;
55 | margin: auto;
56 | margin: auto;
57 | margin: auto;
58 | }
59 |
--------------------------------------------------------------------------------
/test/margin.ltr.expect.css:
--------------------------------------------------------------------------------
1 | test-margin {
2 | margin: 1px;
3 | margin: 2px 3px;
4 | margin: 4px 5px 6px;
5 | margin: 7px 8px 9px;
6 | margin-left: 10px;
7 | margin-right: 10px;
8 | margin-left: 11px;
9 | margin-right: 11px;
10 | margin-top: 12px;
11 | margin-bottom: 12px;
12 | margin-top: 13px;
13 | margin-bottom: 14px;
14 | margin-top: 15px;
15 | margin-bottom: 16px;
16 | }
17 |
18 | test-flowing-margin {
19 | margin: auto;
20 | margin: 1px 4px 3px 2px;
21 | margin: auto;
22 | margin-left: 5px;
23 | margin-right: 6px;
24 | margin: auto;
25 | margin-left: 7px;
26 | margin: auto;
27 | margin-right: 8px;
28 | margin: auto;
29 | }
30 |
--------------------------------------------------------------------------------
/test/padding.css:
--------------------------------------------------------------------------------
1 | test-padding {
2 | padding: logical 1px;
3 | padding: logical 2px 3px;
4 | padding: logical 4px 5px 6px;
5 | padding: logical 7px 8px 9px 8px;
6 | padding-inline: 10px;
7 | padding-inline: 11px 11px;
8 | padding-block: 12px;
9 | padding-block: 13px 14px;
10 | padding-block-start: 15px;
11 | padding-block-end: 16px;
12 | }
13 |
14 | test-flowing-padding {
15 | padding: auto;
16 | padding: logical 1px 2px 3px 4px;
17 | padding: auto;
18 | padding-inline: 5px 6px;
19 | padding: auto;
20 | padding-inline-start: 7px;
21 | padding: auto;
22 | padding-inline-end: 8px;
23 | padding: auto;
24 | padding-start: 9px;
25 | padding: auto;
26 | padding-start: 10px 11px;
27 | padding: auto;
28 | padding-end: 12px;
29 | padding: auto;
30 | padding-end: 13px 14px;
31 | padding: auto;
32 | }
33 |
--------------------------------------------------------------------------------
/test/padding.expect.css:
--------------------------------------------------------------------------------
1 | test-padding {
2 | padding: 1px;
3 | padding: 2px 3px;
4 | padding: 4px 5px 6px;
5 | padding: 7px 8px 9px;
6 | padding-left: 10px;
7 | padding-right: 10px;
8 | padding-left: 11px;
9 | padding-right: 11px;
10 | padding-top: 12px;
11 | padding-bottom: 12px;
12 | padding-top: 13px;
13 | padding-bottom: 14px;
14 | padding-top: 15px;
15 | padding-bottom: 16px;
16 | }
17 |
18 | test-flowing-padding:dir(ltr) {
19 | padding: 1px 4px 3px 2px;
20 | }
21 |
22 | test-flowing-padding:dir(rtl) {
23 | padding: 1px 2px 3px 4px;
24 | }
25 |
26 | test-flowing-padding:dir(ltr) {
27 | padding-left: 5px;
28 | padding-right: 6px;
29 | }
30 |
31 | test-flowing-padding:dir(rtl) {
32 | padding-right: 5px;
33 | padding-left: 6px;
34 | }
35 |
36 | test-flowing-padding:dir(ltr) {
37 | padding-left: 7px;
38 | }
39 |
40 | test-flowing-padding:dir(rtl) {
41 | padding-right: 7px;
42 | }
43 |
44 | test-flowing-padding:dir(ltr) {
45 | padding-right: 8px;
46 | }
47 |
48 | test-flowing-padding:dir(rtl) {
49 | padding-left: 8px;
50 | }
51 |
52 | test-flowing-padding {
53 | padding: auto;
54 | padding: auto;
55 | padding: auto;
56 | padding: auto;
57 | padding: auto;
58 | padding-start: 9px;
59 | padding: auto;
60 | padding-start: 10px 11px;
61 | padding: auto;
62 | padding-end: 12px;
63 | padding: auto;
64 | padding-end: 13px 14px;
65 | padding: auto;
66 | }
67 |
--------------------------------------------------------------------------------
/test/padding.ltr.expect.css:
--------------------------------------------------------------------------------
1 | test-padding {
2 | padding: 1px;
3 | padding: 2px 3px;
4 | padding: 4px 5px 6px;
5 | padding: 7px 8px 9px;
6 | padding-left: 10px;
7 | padding-right: 10px;
8 | padding-left: 11px;
9 | padding-right: 11px;
10 | padding-top: 12px;
11 | padding-bottom: 12px;
12 | padding-top: 13px;
13 | padding-bottom: 14px;
14 | padding-top: 15px;
15 | padding-bottom: 16px;
16 | }
17 |
18 | test-flowing-padding {
19 | padding: auto;
20 | padding: 1px 4px 3px 2px;
21 | padding: auto;
22 | padding-left: 5px;
23 | padding-right: 6px;
24 | padding: auto;
25 | padding-left: 7px;
26 | padding: auto;
27 | padding-right: 8px;
28 | padding: auto;
29 | padding-start: 9px;
30 | padding: auto;
31 | padding-start: 10px 11px;
32 | padding: auto;
33 | padding-end: 12px;
34 | padding: auto;
35 | padding-end: 13px 14px;
36 | padding: auto;
37 | }
38 |
--------------------------------------------------------------------------------
/test/resize.css:
--------------------------------------------------------------------------------
1 | test-resize {
2 | resize: block;
3 | resize: inline;
4 | }
5 |
--------------------------------------------------------------------------------
/test/resize.expect.css:
--------------------------------------------------------------------------------
1 | test-resize {
2 | resize: vertical;
3 | resize: horizontal;
4 | }
5 |
--------------------------------------------------------------------------------
/test/size.css:
--------------------------------------------------------------------------------
1 | test-size {
2 | block-size: 320px;
3 | inline-size: 180px;
4 | }
5 |
6 | text-max-size {
7 | max-block-size: 320px;
8 | max-inline-size: 180px;
9 | }
10 |
11 | text-min-size {
12 | min-block-size: 320px;
13 | min-inline-size: 180px;
14 | }
15 |
--------------------------------------------------------------------------------
/test/size.expect.css:
--------------------------------------------------------------------------------
1 | test-size {
2 | height: 320px;
3 | width: 180px;
4 | }
5 |
6 | text-max-size {
7 | max-height: 320px;
8 | max-width: 180px;
9 | }
10 |
11 | text-min-size {
12 | min-height: 320px;
13 | min-width: 180px;
14 | }
15 |
--------------------------------------------------------------------------------
/test/size.preserve.expect.css:
--------------------------------------------------------------------------------
1 | test-size {
2 | height: 320px;
3 | block-size: 320px;
4 | width: 180px;
5 | inline-size: 180px;
6 | }
7 |
8 | text-max-size {
9 | max-height: 320px;
10 | max-block-size: 320px;
11 | max-width: 180px;
12 | max-inline-size: 180px;
13 | }
14 |
15 | text-min-size {
16 | min-height: 320px;
17 | min-block-size: 320px;
18 | min-width: 180px;
19 | min-inline-size: 180px;
20 | }
21 |
--------------------------------------------------------------------------------
/test/text-align.css:
--------------------------------------------------------------------------------
1 | test-text-align {
2 | text-align: left;
3 | text-align: start;
4 | text-align: end;
5 | text-align: right;
6 | }
7 |
--------------------------------------------------------------------------------
/test/text-align.expect.css:
--------------------------------------------------------------------------------
1 | test-text-align:dir(ltr) {
2 | text-align: left;
3 | }
4 | test-text-align:dir(rtl) {
5 | text-align: right;
6 | }
7 | test-text-align:dir(ltr) {
8 | text-align: right;
9 | }
10 | test-text-align:dir(rtl) {
11 | text-align: left;
12 | }
13 | test-text-align {
14 | text-align: left;
15 | text-align: right;
16 | }
17 |
--------------------------------------------------------------------------------
/test/text-align.ltr.expect.css:
--------------------------------------------------------------------------------
1 | test-text-align {
2 | text-align: left;
3 | text-align: left;
4 | text-align: right;
5 | text-align: right;
6 | }
7 |
--------------------------------------------------------------------------------
/test/transition.css:
--------------------------------------------------------------------------------
1 | .transition {
2 | transition: 1s opacity ease;
3 | }
4 |
5 | .transition-block {
6 | transition: 1s inset-block ease;
7 | transition: 1s margin-block ease;
8 | transition: 1s padding-block ease;
9 | transition-property: border-block, border-block-color, border-block-style, border-block-width;
10 | }
11 |
12 | .transition-inline {
13 | transition: 1s inset-inline ease;
14 | transition: 1s margin-inline ease;
15 | transition: 1s padding-inline ease;
16 | transition-property: border-inline, border-inline-color, border-inline-style, border-inline-width;
17 | }
18 |
19 | .transition-block-start {
20 | transition: 1s inset-block-start ease;
21 | transition: 1s margin-block-start ease;
22 | transition: 1s padding-block-start ease;
23 | }
24 |
25 | .transition-inline-end {
26 | transition: 1s inset-inline-end ease;
27 | transition: 1s margin-inline-end ease;
28 | transition: 1s padding-inline-end ease;
29 | }
30 |
31 | .transition-mixed {
32 | transition: 1s opacity ease, 1s inset-inline-start ease;
33 | }
34 |
--------------------------------------------------------------------------------
/test/transition.expect.css:
--------------------------------------------------------------------------------
1 | .transition {
2 | transition: 1s opacity ease;
3 | }
4 |
5 | .transition-block {
6 | transition: 1s inset-block ease;
7 | transition: 1s margin-block ease;
8 | transition: 1s padding-block ease;
9 | transition-property: border-block, border-block-color, border-block-style, border-block-width;
10 | }
11 |
12 | .transition-inline {
13 | transition: 1s inset-inline ease;
14 | transition: 1s margin-inline ease;
15 | transition: 1s padding-inline ease;
16 | transition-property: border-inline, border-inline-color, border-inline-style, border-inline-width;
17 | }
18 |
19 | .transition-block-start {
20 | transition: 1s inset-block-start ease;
21 | transition: 1s margin-block-start ease;
22 | transition: 1s padding-block-start ease;
23 | }
24 |
25 | .transition-inline-end:dir(ltr) {
26 | transition: 1s right ease;
27 | }
28 |
29 | .transition-inline-end:dir(rtl) {
30 | transition: 1s left ease;
31 | }
32 |
33 | .transition-inline-end:dir(ltr) {
34 | transition: 1s margin-right ease;
35 | }
36 |
37 | .transition-inline-end:dir(rtl) {
38 | transition: 1s margin-left ease;
39 | }
40 |
41 | .transition-inline-end:dir(ltr) {
42 | transition: 1s padding-right ease;
43 | }
44 |
45 | .transition-inline-end:dir(rtl) {
46 | transition: 1s padding-left ease;
47 | }
48 |
49 | .transition-mixed:dir(ltr) {
50 | transition: 1s opacity ease, 1s left ease;
51 | }
52 |
53 | .transition-mixed:dir(rtl) {
54 | transition: 1s opacity ease, 1s right ease;
55 | }
56 |
--------------------------------------------------------------------------------
/test/transition.ltr.expect.css:
--------------------------------------------------------------------------------
1 | .transition {
2 | transition: 1s opacity ease;
3 | }
4 |
5 | .transition-block {
6 | transition: 1s top ease,1s bottom ease;
7 | transition: 1s margin-top ease,1s margin-bottom ease;
8 | transition: 1s padding-top ease,1s padding-bottom ease;
9 | transition-property: border-top,border-bottom, border-top-color, border-bottom-color, border-top-style, border-bottom-style, border-top-width, border-bottom-width;
10 | }
11 |
12 | .transition-inline {
13 | transition: 1s left ease,1s right ease;
14 | transition: 1s margin-left ease,1s margin-right ease;
15 | transition: 1s padding-left ease,1s padding-right ease;
16 | transition-property: border-left,border-right, border-left-color, border-right-color, border-left-style, border-right-style, border-left-width, border-right-width;
17 | }
18 |
19 | .transition-block-start {
20 | transition: 1s top ease;
21 | transition: 1s margin-top ease;
22 | transition: 1s padding-top ease;
23 | }
24 |
25 | .transition-inline-end {
26 | transition: 1s right ease;
27 | transition: 1s margin-right ease;
28 | transition: 1s padding-right ease;
29 | }
30 |
31 | .transition-mixed {
32 | transition: 1s opacity ease, 1s left ease;
33 | }
34 |
--------------------------------------------------------------------------------
/test/transition.preserve.ltr.expect.css:
--------------------------------------------------------------------------------
1 | .transition {
2 | transition: 1s opacity ease;
3 | }
4 |
5 | .transition-block {
6 | transition: 1s inset-block ease;
7 | transition: 1s margin-block ease;
8 | transition: 1s padding-block ease;
9 | transition-property: border-block, border-block-color, border-block-style, border-block-width;
10 | }
11 |
12 | .transition-inline {
13 | transition: 1s inset-inline ease;
14 | transition: 1s margin-inline ease;
15 | transition: 1s padding-inline ease;
16 | transition-property: border-inline, border-inline-color, border-inline-style, border-inline-width;
17 | }
18 |
19 | .transition-block-start {
20 | transition: 1s inset-block-start ease;
21 | transition: 1s margin-block-start ease;
22 | transition: 1s padding-block-start ease;
23 | }
24 |
25 | .transition-inline-end:dir(ltr) {
26 | transition: 1s right ease;
27 | }
28 |
29 | .transition-inline-end:dir(rtl) {
30 | transition: 1s left ease;
31 | }
32 |
33 | .transition-inline-end:dir(ltr) {
34 | transition: 1s margin-right ease;
35 | }
36 |
37 | .transition-inline-end:dir(rtl) {
38 | transition: 1s margin-left ease;
39 | }
40 |
41 | .transition-inline-end:dir(ltr) {
42 | transition: 1s padding-right ease;
43 | }
44 |
45 | .transition-inline-end:dir(rtl) {
46 | transition: 1s padding-left ease;
47 | }
48 |
49 | .transition-inline-end {
50 | transition: 1s inset-inline-end ease;
51 | transition: 1s margin-inline-end ease;
52 | transition: 1s padding-inline-end ease;
53 | }
54 |
55 | .transition-mixed:dir(ltr) {
56 | transition: 1s opacity ease, 1s left ease;
57 | }
58 |
59 | .transition-mixed:dir(rtl) {
60 | transition: 1s opacity ease, 1s right ease;
61 | }
62 |
63 | .transition-mixed {
64 | transition: 1s opacity ease, 1s inset-inline-start ease;
65 | }
66 |
--------------------------------------------------------------------------------