├── .editorconfig
├── .gitignore
├── .rollup.js
├── .tape.js
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── INSTALL.md
├── LICENSE.md
├── README.md
├── package.json
├── src
├── index.js
└── lib
│ ├── is.js
│ ├── new.js
│ └── transforms.js
└── test
├── basic.css
├── basic.expect.css
└── basic.precision.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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .*
2 | !.editorconfig
3 | !.gitignore
4 | !.rollup.js
5 | !.tape.js
6 | !.travis.yml
7 | *.log*
8 | *.result.css
9 | /index.*
10 | node_modules
11 | package-lock.json
12 |
--------------------------------------------------------------------------------
/.rollup.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 |
3 | export default {
4 | input: 'src/index.js',
5 | output: [
6 | { file: 'index.js', format: 'cjs', sourcemap: true },
7 | { file: 'index.mjs', format: 'esm', sourcemap: true }
8 | ],
9 | plugins: [
10 | babel({
11 | presets: [
12 | ['@babel/env', { modules: false, targets: { node: 6 } }]
13 | ]
14 | })
15 | ]
16 | };
17 |
--------------------------------------------------------------------------------
/.tape.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'basic': {
3 | message: 'supports basic usage'
4 | },
5 | 'basic:precision': {
6 | message: 'supports { precision } usage',
7 | options: {
8 | precision: 3
9 | }
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # https://docs.travis-ci.com/user/travis-lint
2 |
3 | language: node_js
4 |
5 | node_js:
6 | - 6
7 |
8 | install:
9 | - npm install --ignore-scripts
10 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changes to PostCSS Trig
2 |
3 | ### 1.0.0 (February 28, 2019)
4 |
5 | - Initial version
6 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to PostCSS Trig
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-trig.git
24 |
25 | # Navigate to the newly cloned directory
26 | cd postcss-trig
27 |
28 | # Assign the original repo to a remote called "upstream"
29 | git remote add upstream git@github.com:csstools/postcss-trig.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 Trig
2 |
3 | [PostCSS Trig] runs in all Node environments, with special instructions for:
4 |
5 | | [Node](#node) | [PostCSS CLI](#postcss-cli) | [Webpack](#webpack) | [Create React App](#create-react-app) | [Gulp](#gulp) | [Grunt](#grunt) |
6 | | --- | --- | --- | --- | --- | --- |
7 |
8 | ## Node
9 |
10 | Add [PostCSS Trig] to your project:
11 |
12 | ```bash
13 | npm install postcss-trig --save-dev
14 | ```
15 |
16 | Use [PostCSS Trig] to process your CSS:
17 |
18 | ```js
19 | const postcssTrig = require('postcss-trig');
20 |
21 | postcssTrig.process(YOUR_CSS /*, processOptions, pluginOptions */);
22 | ```
23 |
24 | Or use it as a [PostCSS] plugin:
25 |
26 | ```js
27 | const postcss = require('postcss');
28 | const postcssTrig = require('postcss-trig');
29 |
30 | postcss([
31 | postcssTrig(/* pluginOptions */)
32 | ]).process(YOUR_CSS /*, processOptions */);
33 | ```
34 |
35 | ## PostCSS CLI
36 |
37 | Add [PostCSS CLI] to your project:
38 |
39 | ```bash
40 | npm install postcss-cli --save-dev
41 | ```
42 |
43 | Use [PostCSS Trig] in your `postcss.config.js` configuration file:
44 |
45 | ```js
46 | const postcssTrig = require('postcss-trig');
47 |
48 | module.exports = {
49 | plugins: [
50 | postcssTrig(/* pluginOptions */)
51 | ]
52 | }
53 | ```
54 |
55 | ## Webpack
56 |
57 | Add [PostCSS Loader] to your project:
58 |
59 | ```bash
60 | npm install postcss-loader --save-dev
61 | ```
62 |
63 | Use [PostCSS Trig] in your Webpack configuration:
64 |
65 | ```js
66 | const postcssTrig = require('postcss-trig');
67 |
68 | module.exports = {
69 | module: {
70 | rules: [
71 | {
72 | test: /\.css$/,
73 | use: [
74 | 'style-loader',
75 | { loader: 'css-loader', options: { importLoaders: 1 } },
76 | { loader: 'postcss-loader', options: {
77 | ident: 'postcss',
78 | plugins: () => [
79 | postcssTrig(/* pluginOptions */)
80 | ]
81 | } }
82 | ]
83 | }
84 | ]
85 | }
86 | }
87 | ```
88 |
89 | ## Create React App
90 |
91 | Add [React App Rewired] and [React App Rewire PostCSS] to your project:
92 |
93 | ```bash
94 | npm install react-app-rewired react-app-rewire-postcss --save-dev
95 | ```
96 |
97 | Use [React App Rewire PostCSS] and [PostCSS Trig] in your
98 | `config-overrides.js` file:
99 |
100 | ```js
101 | const reactAppRewirePostcss = require('react-app-rewire-postcss');
102 | const postcssTrig = require('postcss-trig');
103 |
104 | module.exports = config => reactAppRewirePostcss(config, {
105 | plugins: () => [
106 | postcssTrig(/* pluginOptions */)
107 | ]
108 | });
109 | ```
110 |
111 | ## Gulp
112 |
113 | Add [Gulp PostCSS] to your project:
114 |
115 | ```bash
116 | npm install gulp-postcss --save-dev
117 | ```
118 |
119 | Use [PostCSS Trig] in your Gulpfile:
120 |
121 | ```js
122 | const postcss = require('gulp-postcss');
123 | const postcssTrig = require('postcss-trig');
124 |
125 | gulp.task('css', () => gulp.src('./src/*.css').pipe(
126 | postcss([
127 | postcssTrig(/* pluginOptions */)
128 | ])
129 | ).pipe(
130 | gulp.dest('.')
131 | ));
132 | ```
133 |
134 | ## Grunt
135 |
136 | Add [Grunt PostCSS] to your project:
137 |
138 | ```bash
139 | npm install grunt-postcss --save-dev
140 | ```
141 |
142 | Use [PostCSS Trig] in your Gruntfile:
143 |
144 | ```js
145 | const postcssTrig = require('postcss-trig');
146 |
147 | grunt.loadNpmTasks('grunt-postcss');
148 |
149 | grunt.initConfig({
150 | postcss: {
151 | options: {
152 | use: [
153 | postcssTrig(/* pluginOptions */)
154 | ]
155 | },
156 | dist: {
157 | src: '*.css'
158 | }
159 | }
160 | });
161 | ```
162 |
163 | [Gulp PostCSS]: https://github.com/postcss/gulp-postcss
164 | [Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
165 | [PostCSS]: https://github.com/postcss/postcss
166 | [PostCSS CLI]: https://github.com/postcss/postcss-cli
167 | [PostCSS Loader]: https://github.com/postcss/postcss-loader
168 | [PostCSS Trig]: https://github.com/csstools/postcss-trig
169 | [React App Rewire PostCSS]: https://github.com/csstools/react-app-rewire-postcss
170 | [React App Rewired]: https://github.com/timarney/react-app-rewired
171 |
--------------------------------------------------------------------------------
/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 |
⚠️ PostCSS Trig is no longer maintained ⚠️
There's a new plugin that handles trigonometric which you can find in
@csstools/postcss-plugins.
2 |
3 | # PostCSS Trig [
][postcss]
4 |
5 | [![NPM Version][npm-img]][npm-url]
6 | [![Build Status][cli-img]][cli-url]
7 | [![Support Chat][git-img]][git-url]
8 |
9 | [PostCSS Trig] lets you use trigonometry functions in CSS.
10 |
11 | These functions include `acos`, `asin`, `atan`, `atan2`, `cos`, `hypot`, `pow`,
12 | `sin`, `sqrt`, and `tan`.
13 |
14 | ```pcss
15 | :root {
16 | --acos: acos(0.8);
17 | --asin: asin(0.6);
18 | --atan: atan(0.8);
19 | --atan2: atan2(5, 5);
20 | --cos: cos(20);
21 | --cos-deg: cos(20deg);
22 | --hypot: hypot(3, 4);
23 | --pow: pow(4, 4);
24 | --pow-rem: pow(4rem, 4);
25 | --sin: sin(20);
26 | --sin-deg: sin(20deg);
27 | --sqrt: sqrt(81);
28 | --sqrt-rem: sqrt(81rem);
29 | --tan: tan(20);
30 | --tan-deg: tan(20deg);
31 | }
32 |
33 |
34 | /* becomes */
35 |
36 | :root {
37 | --acos: 0.6435;
38 | --asin: 0.6435;
39 | --atan: 0.9273;
40 | --atan2: 0.7854;
41 | --cos: 0.40808;
42 | --cos-deg: 0.93969;
43 | --hypot: 5;
44 | --pow: 256;
45 | --pow-rem: 256rem;
46 | --sin: 0.91295;
47 | --sin-deg: 0.34202;
48 | --sqrt: 9;
49 | --sqrt-rem: 9rem;
50 | --tan: 2.23716;
51 | --tan-deg: 0.36397;
52 | }
53 | ```
54 |
55 | When necessary, more complex fallbacks are used to support real-time values.
56 |
57 | ```pcss
58 | :root {
59 | --cos-calc: cos(calc(20 * 2));
60 | --cos-var: cos(var(--angle));
61 | --pow-calc: pow(calc(4 * 2), 4);
62 | --pow-var: pow(var(--number), 4);
63 | --sin-calc: sin(calc(20 * 2));
64 | --sin-var: sin(var(--angle));
65 | --sqrt-calc: sqrt(calc(81 * 4));
66 | --sqrt-var: sqrt(var(--number));
67 | --tan-calc: tan(calc(20 * 2));
68 | --tan-var: tan(var(--angle));
69 | }
70 |
71 | /* becomes */
72 |
73 | :root {
74 | --cos-calc: calc(1 - ((20 * 2) * (20 * 2) / 2 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 24 ) - ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 720 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 40320 ));
75 | --cos-var: calc(1 - (var(--angle) * var(--angle) / 2 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) / 24 ) - (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 720 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 40320 ));
76 | --pow-calc: pow(calc(4 * 2), 4);
77 | --pow-var: pow(var(--number), 4);
78 | --sin-calc: calc((20 * 2) - ((20 * 2) * (20 * 2) * (20 * 2) / 6 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 120 ) - ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 5040 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 362880 ));
79 | --sin-var: calc(var(--angle) - (var(--angle) * var(--angle) * var(--angle) / 6 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 120 ) - (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 5040 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 362880 ));
80 | --sqrt-calc: calc(((((((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2) + (81 * 4) / (((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2)) / 2) + (81 * 4) / (((((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2) + (81 * 4) / (((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2)) / 2)) / 2);
81 | --sqrt-var: calc((((((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2) + var(--number) / ((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2)) / 2) + var(--number) / ((((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2) + var(--number) / ((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2)) / 2)) / 2);
82 | --tan-calc: calc((20 * 2) + ((1 / 3) * ((20 * 2) * (20 * 2) * (20 * 2))) + ((2 / 15) * ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2))) + ((17 / 315) * ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2))));
83 | --tan-var: calc(var(--angle) + ((1 / 3) * (var(--angle) * var(--angle) * var(--angle))) + ((2 / 15) * (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle))) + ((17 / 315) * (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle))));
84 | }
85 | ```
86 |
87 | ## Usage
88 |
89 | Add [PostCSS Trig] to your project:
90 |
91 | ```bash
92 | npm install postcss-trig --save-dev
93 | ```
94 |
95 | Use [PostCSS Trig] to process your CSS:
96 |
97 | ```js
98 | const postcssTrig = require('postcss-trig');
99 |
100 | postcssTrig.process(YOUR_CSS /*, processOptions, pluginOptions */);
101 | ```
102 |
103 | Or use it as a [PostCSS] plugin:
104 |
105 | ```js
106 | const postcss = require('postcss');
107 | const postcssTrig = require('postcss-trig');
108 |
109 | postcss([
110 | postcssTrig(/* pluginOptions */)
111 | ]).process(YOUR_CSS /*, processOptions */);
112 | ```
113 |
114 | [PostCSS Trig] runs in all Node environments, with special instructions for:
115 |
116 | | [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) |
117 | | --- | --- | --- | --- | --- | --- |
118 |
119 | ## Options
120 |
121 | ### precision
122 |
123 | The `precision` option determines how many decimal places of precision will be
124 | preserved after transformations. By default, this precision is up to `5` places.
125 |
126 | [cli-img]: https://img.shields.io/travis/csstools/postcss-trig.svg
127 | [cli-url]: https://travis-ci.org/csstools/postcss-trig
128 | [git-img]: https://img.shields.io/badge/support-chat-blue.svg
129 | [git-url]: https://gitter.im/postcss/postcss
130 | [npm-img]: https://img.shields.io/npm/v/postcss-trig.svg
131 | [npm-url]: https://www.npmjs.com/package/postcss-trig
132 |
133 | [PostCSS]: https://github.com/postcss/postcss
134 | [PostCSS Trig]: https://github.com/csstools/postcss-trig
135 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postcss-trig",
3 | "version": "1.0.0",
4 | "description": "Use trigonometry functions in CSS",
5 | "author": "Jonathan Neal ",
6 | "license": "CC0-1.0",
7 | "repository": "csstools/postcss-trig",
8 | "homepage": "https://github.com/csstools/postcss-trig#readme",
9 | "bugs": "https://github.com/csstools/postcss-trig/issues",
10 | "main": "index.js",
11 | "module": "index.mjs",
12 | "files": [
13 | "index.js",
14 | "index.js.map",
15 | "index.mjs",
16 | "index.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 src/lib/*.js --cache --ignore-path .gitignore --quiet",
24 | "test:tape": "postcss-tape"
25 | },
26 | "engines": {
27 | "node": ">=6.0.0"
28 | },
29 | "dependencies": {
30 | "postcss": "^7.0.14",
31 | "postcss-values-parser": "^2.0.1"
32 | },
33 | "devDependencies": {
34 | "@babel/core": "^7.2.2",
35 | "@babel/preset-env": "^7.3.1",
36 | "babel-eslint": "^10.0.1",
37 | "eslint": "^5.12.1",
38 | "eslint-config-dev": "^2.0.0",
39 | "postcss-tape": "^4.0.0",
40 | "pre-commit": "^1.2.2",
41 | "rollup": "^1.1.2",
42 | "rollup-plugin-babel": "^4.3.2"
43 | },
44 | "eslintConfig": {
45 | "extends": "dev",
46 | "parser": "babel-eslint"
47 | },
48 | "keywords": [
49 | "postcss",
50 | "css",
51 | "postcss-plugin",
52 | "trigonometry",
53 | "math",
54 | "calc"
55 | ]
56 | }
57 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import postcss from 'postcss';
2 | import valuesParser from 'postcss-values-parser';
3 | import {
4 | transformAcosFunction,
5 | transformAsinFunction,
6 | transformAtanFunction,
7 | transformAtan2Function,
8 | transformCosFunction,
9 | transformHypotFunction,
10 | transformPowFunction,
11 | transformSinFunction,
12 | transformSqrtFunction,
13 | transformTanFunction
14 | } from './lib/transforms';
15 |
16 | export default postcss.plugin('postcss-trig', opts => {
17 | const precision = 'precision' in Object(opts) ? Number(opts.precision) || 0 : 5;
18 |
19 | return root => {
20 | root.walkDecls(decl => {
21 | if (anyTrigFunctionRegExp.test(decl.value)) {
22 | const originalValue = decl.value;
23 |
24 | const valueAST = valuesParser(originalValue).parse();
25 |
26 | valueAST.walkFunctionNodes(functionNode => {
27 | if (trigFunctionNameRegExp.test(functionNode.value)) {
28 | const name = functionNode.value.toLowerCase();
29 | const transform = transformsByName[name];
30 |
31 | transform(functionNode, precision);
32 | }
33 | });
34 |
35 | const modifiedValue = String(valueAST);
36 |
37 | if (originalValue !== modifiedValue) {
38 | decl.value = modifiedValue;
39 | }
40 | }
41 | });
42 | };
43 | });
44 |
45 | const transformsByName = {
46 | acos: transformAcosFunction,
47 | asin: transformAsinFunction,
48 | atan: transformAtanFunction,
49 | atan2: transformAtan2Function,
50 | cos: transformCosFunction,
51 | hypot: transformHypotFunction,
52 | pow: transformPowFunction,
53 | sin: transformSinFunction,
54 | sqrt: transformSqrtFunction,
55 | tan: transformTanFunction
56 | };
57 |
58 | const anyTrigFunctionRegExp = /\b(acos|asin|atan|atan2|cos|hypot|pow|sin|sqrt|tan)\(.*\)/i;
59 | const trigFunctionNameRegExp = /^(acos|asin|atan|atan2|cos|hypot|pow|sin|sqrt|tan)$/i
60 |
--------------------------------------------------------------------------------
/src/lib/is.js:
--------------------------------------------------------------------------------
1 | /* Numbers
2 | /* ========================================================================== */
3 |
4 | // return whether the length is valid
5 | export function isLength(node) {
6 | return Object(node).type === 'number';
7 | }
8 |
9 | // return whether the length is valid
10 | export function isAngle(node) {
11 | return isLength(node) && matchAngleUnit.test(node.unit);
12 | }
13 |
14 | // return whether the number is valid
15 | export function isNumber(node) {
16 | return isLength(node) && node.unit === '';
17 | }
18 |
19 | /* Delimiters
20 | /* ========================================================================== */
21 |
22 | // return whether the comma is valid
23 | export function isComma(node) {
24 | return Object(node).type === 'comma';
25 | }
26 |
27 | /* Functions
28 | /* ========================================================================== */
29 |
30 | export function isFunction(node) {
31 | return Object(node).type === 'func';
32 | }
33 |
34 | export function isCalc(node) {
35 | return isFunction(node) && matchCalcName.test(node.value);
36 | }
37 |
38 | /* Matchers
39 | /* ========================================================================== */
40 |
41 | export const matchAngleUnit = /^(deg|grad|rad|turn)$/i;
42 | export const matchCalcName = /^calc$/i;
43 |
--------------------------------------------------------------------------------
/src/lib/new.js:
--------------------------------------------------------------------------------
1 | import valuesParser from 'postcss-values-parser';
2 |
3 | export function newNumber(value) {
4 | return valuesParser.number({ value: String(value) });
5 | }
6 |
7 | export function newOperator(value) {
8 | const multiplierOpts = { value, raws: { before: ' ', after: ' ' } };
9 |
10 | return valuesParser.operator(multiplierOpts);
11 | }
12 |
13 | export function newFunction(name, ...nodes) {
14 | return valuesParser.func({
15 | value: name,
16 | nodes: [
17 | valuesParser.paren({ value: '(' }),
18 | ...nodes,
19 | valuesParser.paren({ value: ')' })
20 | ]
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/transforms.js:
--------------------------------------------------------------------------------
1 | import { isAngle, isCalc, isComma, isFunction, isLength, isNumber, matchCalcName } from './is';
2 | import { newNumber, newOperator, newFunction } from './new';
3 |
4 | /* Transforms
5 | /* ========================================================================== */
6 |
7 | // return the first set of transformed arguments allowable by the parameters
8 | export function transformArgsByParams(node, params) {
9 | const nodes = (Object(node).nodes || []).slice(1, -1);
10 |
11 | return params.map(param => nodes.map(
12 | (childNode, index) => typeof param[index] === 'function' ? param[index](childNode) : null
13 | ).filter(child => typeof child !== 'boolean')).filter(param => param.every(
14 | result => result !== null
15 | ))[0] || [];
16 | }
17 |
18 | // return a transformed angle
19 | export function transformAngleOrNumberNodeIntoNumberNode(node) {
20 | if (isAngle(node) || isNumber(node)) {
21 | const unit = node.unit.toLowerCase();
22 |
23 | if (unit in angleMultipliersByUnit) {
24 | node.value = String(Number(node.value) * angleMultipliersByUnit[unit]);
25 |
26 | node.unit = '';
27 | }
28 |
29 | return node;
30 | }
31 |
32 | return null;
33 | }
34 |
35 | function transformCalcAddDivideBy(node, number) {
36 | if (isCalc(node)) {
37 | node.nodes.splice(-1, 0, newOperator('/'), newOperator(number));
38 | }
39 |
40 | return node;
41 | }
42 |
43 | export function getFunctionNode(node) {
44 | return isFunction(node) ? node : null;
45 | }
46 |
47 | export function getLengthNode(node) {
48 | return isLength(node) ? node : null;
49 | }
50 |
51 | export function getNumber(node) {
52 | return isNumber(node) ? Number(node.value) : null;
53 | }
54 |
55 | export function getNumberNode(node) {
56 | return isNumber(node) ? node : null;
57 | }
58 |
59 | export function uncalcNode(node) {
60 | if (isCalc(node)) {
61 | node.value = node.value.replace(matchCalcName, '');
62 | }
63 |
64 | return node;
65 | }
66 |
67 | /* Transform acos()
68 | /* ========================================================================== */
69 |
70 | export function transformAcosFunction(functionNode, precision) {
71 | const [radianNode] = transformArgsByParams(functionNode, [
72 | // |
73 | [transformAngleOrNumberNodeIntoNumberNode]
74 | ]);
75 |
76 | if (isNumber(radianNode)) {
77 | const numberNode = getAcosNumberNodeFromNumberNode(radianNode, precision);
78 |
79 | if (numberNode.value !== 'NaN') {
80 | functionNode.replaceWith(numberNode);
81 | }
82 | }
83 | }
84 |
85 | export function getAcosNumberNodeFromNumberNode(numberNode, precision) {
86 | const acos = usePrecision(Math.acos(numberNode.value), precision);
87 |
88 | return clone(numberNode, { value: String(acos) });
89 | }
90 |
91 | /* Transform asin()
92 | /* ========================================================================== */
93 |
94 | export function transformAsinFunction(functionNode, precision) {
95 | const [radianNode] = transformArgsByParams(functionNode, [
96 | // |
97 | [transformAngleOrNumberNodeIntoNumberNode]
98 | ]);
99 |
100 | if (isNumber(radianNode)) {
101 | const numberNode = getAsinNumberNodeFromNumberNode(radianNode, precision);
102 |
103 | if (numberNode.value !== 'NaN') {
104 | functionNode.replaceWith(numberNode);
105 | }
106 | }
107 | }
108 |
109 | export function getAsinNumberNodeFromNumberNode(numberNode, precision) {
110 | const asin = usePrecision(Math.asin(numberNode.value), precision);
111 |
112 | return clone(numberNode, { value: String(asin) });
113 | }
114 |
115 | /* Transform asin()
116 | /* ========================================================================== */
117 |
118 | export function transformAtanFunction(functionNode, precision) {
119 | const [radianNode] = transformArgsByParams(functionNode, [
120 | // |
121 | [transformAngleOrNumberNodeIntoNumberNode]
122 | ]);
123 |
124 | if (isNumber(radianNode)) {
125 | const numberNode = getAtanNumberNodeFromNumberNode(radianNode, precision);
126 |
127 | if (numberNode.value !== 'NaN') {
128 | functionNode.replaceWith(numberNode);
129 | }
130 | }
131 | }
132 |
133 | export function getAtanNumberNodeFromNumberNode(numberNode, precision) {
134 | const atan = usePrecision(Math.asin(numberNode.value), precision);
135 |
136 | return clone(numberNode, { value: String(atan) });
137 | }
138 |
139 | /* Transform atan2()
140 | /* ========================================================================== */
141 |
142 | export function transformAtan2Function(functionNode, precision) {
143 | const [coordinateY, coordinateX] = transformArgsByParams(functionNode, [
144 | // ,
145 | [getNumber, isComma, getNumber]
146 | ]);
147 |
148 | if (typeof coordinateY === 'number' && typeof coordinateX === 'number') {
149 | const numberNode = getAtan2NumberNodeFromCoordinates(coordinateY, coordinateX, precision);
150 |
151 | if (numberNode.value !== 'NaN') {
152 | functionNode.replaceWith(numberNode);
153 | }
154 | }
155 | }
156 |
157 | export function getAtan2NumberNodeFromCoordinates(coordinateY, coordinateX, precision) {
158 | const atan2 = usePrecision(Math.atan2(coordinateY, coordinateX), precision);
159 |
160 | return newNumber(atan2);
161 | }
162 |
163 | /* Transform cos()
164 | /* ========================================================================== */
165 |
166 | export function transformCosFunction(cosFunctionNode, precision) {
167 | const [radianNode] = transformArgsByParams(cosFunctionNode, [
168 | // |
169 | [transformAngleOrNumberNodeIntoNumberNode],
170 | //
171 | [getFunctionNode]
172 | ]);
173 |
174 | if (isNumber(radianNode)) {
175 | const numberNode = getCosNumberNodeFromNumberNode(radianNode, precision);
176 |
177 | if (numberNode.value !== 'NaN') {
178 | cosFunctionNode.replaceWith(numberNode);
179 | }
180 | } else if (isFunction(radianNode)) {
181 | cosFunctionNode.replaceWith(getCosFunctionNodeFromFunctionNode(radianNode));
182 | }
183 | }
184 |
185 | export function getCosNumberNodeFromNumberNode(numberNode, precision) {
186 | const cos = usePrecision(Math.cos(numberNode.value), precision);
187 |
188 | return clone(numberNode, { value: String(cos) });
189 | }
190 |
191 | export function getCosFunctionNodeFromFunctionNode(functionNode) {
192 | const cosTermNode1 = newNumber(1);
193 | const cosTermNode2 = transformCalcAddDivideBy(getPowCalcFunctionNodeFromFunctionNode(functionNode, 2), 2);
194 | const cosTermNode3 = transformCalcAddDivideBy(getPowCalcFunctionNodeFromFunctionNode(functionNode, 4), 24);
195 | const cosTermNode4 = transformCalcAddDivideBy(getPowCalcFunctionNodeFromFunctionNode(functionNode, 6), 720);
196 | const cosTermNode5 = transformCalcAddDivideBy(getPowCalcFunctionNodeFromFunctionNode(functionNode, 8), 40320);
197 | const calcCosNode = newFunction('calc', ...[
198 | uncalcNode(cosTermNode1),
199 | newOperator('-'),
200 | uncalcNode(cosTermNode2),
201 | newOperator('+'),
202 | uncalcNode(cosTermNode3),
203 | newOperator('-'),
204 | uncalcNode(cosTermNode4),
205 | newOperator('+'),
206 | uncalcNode(cosTermNode5)
207 | ]);
208 |
209 | return calcCosNode;
210 | }
211 |
212 | /* Transform hypot()
213 | /* ========================================================================== */
214 |
215 | export function transformHypotFunction(hypotFunctionNode, precision) {
216 | const hypotNodes = hypotFunctionNode.nodes.slice(1, -1);
217 |
218 | const isValidHypotArgs = hypotNodes.every((hypotNode, index) => index % 2 ? isComma(hypotNode) : isNumber(hypotNode));
219 |
220 | if (isValidHypotArgs) {
221 | const numberNode = getHypotNumberNodeFromHypotNodes(hypotNodes, precision);
222 |
223 | if (numberNode.value !== 'NaN') {
224 | hypotFunctionNode.replaceWith(numberNode);
225 | }
226 | }
227 | }
228 |
229 | export function getHypotNumberNodeFromHypotNodes(hypotNodes, precision) {
230 | const hypotNodesValues = hypotNodes.filter((hypotNode, index) => !(index % 2)).map(hypotNode => hypotNode.value);
231 | const hypot = usePrecision(Math.hypot.apply(Math, hypotNodesValues), precision);
232 | const hypotNode = newNumber(hypot);
233 |
234 | return hypotNode;
235 | }
236 |
237 | /* Transform pow()
238 | /* ========================================================================== */
239 |
240 | export function transformPowFunction(powFunctionNode, precision) {
241 | const [baseNode, exponent] = transformArgsByParams(powFunctionNode, [
242 | // ,
243 | [getLengthNode, isComma, getNumber],
244 | // ,
245 | [getFunctionNode, isComma, getNumber]
246 | ]);
247 |
248 | if (isLength(baseNode) && typeof exponent === 'number') {
249 | const lengthNode = getPowLengthNodeFromLengthNode(baseNode, exponent, precision);
250 |
251 | if (lengthNode.value !== 'NaN') {
252 | powFunctionNode.replaceWith(lengthNode);
253 | }
254 | } else if (isFunction(baseNode) && typeof exponentNumber === 'number') {
255 | powFunctionNode.replaceWith(getPowCalcFunctionNodeFromFunctionNode(baseNode, exponent));
256 | }
257 | }
258 |
259 | export function getPowLengthNodeFromLengthNode(lengthNode, exponent, precision) {
260 | const base = Number(lengthNode.value);
261 | const pow = usePrecision(Math.pow(base, exponent), precision);
262 |
263 | return clone(lengthNode, { value: String(pow) });
264 | }
265 |
266 | export function getPowCalcFunctionNodeFromFunctionNode(functionNode, exponent) {
267 | const functionCloneNode = uncalcNode(clone(functionNode));
268 | const calcSumNodes = [];
269 | let i = -1;
270 |
271 | while (++i < exponent) {
272 | calcSumNodes.push(clone(functionCloneNode));
273 |
274 | if (i + 1 < exponent) {
275 | calcSumNodes.push(newOperator('*'));
276 | }
277 | }
278 |
279 | return newFunction('calc', ...calcSumNodes);
280 | }
281 |
282 | /* Transform sin()
283 | /* ========================================================================== */
284 |
285 | export function transformSinFunction(sinFunctionNode, precision) {
286 | const [radianNode] = transformArgsByParams(sinFunctionNode, [
287 | // |
288 | [transformAngleOrNumberNodeIntoNumberNode],
289 | //
290 | [getFunctionNode]
291 | ]);
292 |
293 | if (isNumber(radianNode)) {
294 | const numberNode = getSinNumberNodeFromNumberNode(radianNode, precision);
295 |
296 | if (numberNode.value !== 'NaN') {
297 | sinFunctionNode.replaceWith(numberNode);
298 | }
299 | } else if (isFunction(radianNode)) {
300 | sinFunctionNode.replaceWith(getSinCalcFunctionNodeFromFunctionNode(radianNode));
301 | }
302 | }
303 |
304 | export function getSinNumberNodeFromNumberNode(numberNode, precision) {
305 | const sin = usePrecision(Math.sin(numberNode.value), precision);
306 |
307 | return clone(numberNode, { value: String(sin) });
308 | }
309 |
310 | export function getSinCalcFunctionNodeFromFunctionNode(functionNode) {
311 | const sinTermNode1 = clone(functionNode);
312 | const sinTermNode2 = transformCalcAddDivideBy(getPowCalcFunctionNodeFromFunctionNode(functionNode, 3), 6);
313 | const sinTermNode3 = transformCalcAddDivideBy(getPowCalcFunctionNodeFromFunctionNode(functionNode, 5), 120);
314 | const sinTermNode4 = transformCalcAddDivideBy(getPowCalcFunctionNodeFromFunctionNode(functionNode, 7), 5040);
315 | const sinTermNode5 = transformCalcAddDivideBy(getPowCalcFunctionNodeFromFunctionNode(functionNode, 9), 362880);
316 | const calcSinNode = newFunction('calc', ...[
317 | uncalcNode(sinTermNode1),
318 | newOperator('-'),
319 | uncalcNode(sinTermNode2),
320 | newOperator('+'),
321 | uncalcNode(sinTermNode3),
322 | newOperator('-'),
323 | uncalcNode(sinTermNode4),
324 | newOperator('+'),
325 | uncalcNode(sinTermNode5)
326 | ]);
327 |
328 | return calcSinNode;
329 | }
330 |
331 | /* Transform sqrt()
332 | /* ========================================================================== */
333 |
334 | export function transformSqrtFunction(sqrtFunctionNode, precision) {
335 | const [baseNode] = transformArgsByParams(sqrtFunctionNode, [
336 | // ,
337 | [getLengthNode],
338 | // ,
339 | [getFunctionNode]
340 | ]);
341 |
342 | if (isLength(baseNode)) {
343 | const sqrtNumberNode = getSqrtLengthNodeFromLengthNode(baseNode, precision);
344 |
345 | if (sqrtNumberNode.value !== 'NaN') {
346 | sqrtFunctionNode.replaceWith(sqrtNumberNode);
347 | }
348 | } else if (isFunction(baseNode)) {
349 | sqrtFunctionNode.replaceWith(getSqrtCalcFunctionNodeFromFunctionNode(baseNode));
350 | }
351 | }
352 |
353 | export function getSqrtLengthNodeFromLengthNode(lengthNode, precision) {
354 | const sqrt = usePrecision(Math.sqrt(lengthNode.value), precision);
355 |
356 | return clone(lengthNode, { value: String(sqrt) });
357 | }
358 |
359 | export function getSqrtCalcFunctionNodeFromFunctionNode(functionNode) {
360 | const sqrtGuess1 = getSqrtGuessCalcFunctionNodeFromFunctionNode(functionNode, functionNode);
361 | const sqrtGuess2 = getSqrtGuessCalcFunctionNodeFromFunctionNode(sqrtGuess1, functionNode);
362 | const sqrtGuess3 = getSqrtGuessCalcFunctionNodeFromFunctionNode(sqrtGuess2, functionNode);
363 | const sqrtGuess4 = getSqrtGuessCalcFunctionNodeFromFunctionNode(sqrtGuess3, functionNode);
364 | const sqrtGuess5 = getSqrtGuessCalcFunctionNodeFromFunctionNode(sqrtGuess4, functionNode);
365 |
366 | return sqrtGuess5;
367 | }
368 |
369 | export function getSqrtGuessCalcFunctionNodeFromFunctionNode(guessFunctionNode, originalFunctionNode) {
370 | return newFunction('calc', ...[
371 | newFunction('', ...[
372 | ...[
373 | uncalcNode(clone(guessFunctionNode)),
374 | newOperator('+'),
375 | uncalcNode(clone(originalFunctionNode)),
376 | newOperator('/'),
377 | uncalcNode(clone(guessFunctionNode))
378 | ]
379 | ]),
380 | newOperator('/'),
381 | newNumber(2)
382 | ]);
383 | }
384 |
385 | /* Transform tan()
386 | /* ========================================================================== */
387 |
388 | export function transformTanFunction(tanFunctionNode, precision) {
389 | const [radianNode] = transformArgsByParams(tanFunctionNode, [
390 | // |
391 | [transformAngleOrNumberNodeIntoNumberNode],
392 | //
393 | [getFunctionNode]
394 | ]);
395 |
396 | if (isNumber(radianNode)) {
397 | const numberNode = getTanNumberNodeFromNumberNode(radianNode, precision);
398 |
399 | if (numberNode.value !== 'NaN') {
400 | tanFunctionNode.replaceWith(numberNode);
401 | }
402 | } else if (isFunction(radianNode)) {
403 | tanFunctionNode.replaceWith(getTanCalcFunctionNodeFromFunctionNode(radianNode));
404 | }
405 | }
406 |
407 | export function getTanNumberNodeFromNumberNode(numberNode, precision) {
408 | const tan = usePrecision(Math.tan(numberNode.value), precision);
409 |
410 | return clone(numberNode, { value: String(tan) });
411 | }
412 |
413 | export function getTanCalcFunctionNodeFromFunctionNode(functionNode) {
414 | const tanTermNode1 = clone(functionNode);
415 | const tanTermNode2 = newFunction('calc', ...[
416 | newFunction('', ...[
417 | newNumber(1), newOperator('/'), newNumber(3)
418 | ]),
419 | newOperator('*'),
420 | ...getPowCalcFunctionNodeFromFunctionNode(functionNode, 3).nodes
421 | ]);
422 | const tanTermNode3 = newFunction('calc', ...[
423 | newFunction('', ...[
424 | newNumber(2), newOperator('/'), newNumber(15)
425 | ]),
426 | newOperator('*'),
427 | ...getPowCalcFunctionNodeFromFunctionNode(functionNode, 5).nodes
428 | ]);
429 | const tanTermNode4 = newFunction('calc', ...[
430 | newFunction('', ...[
431 | newNumber(17), newOperator('/'), newNumber(315)
432 | ]),
433 | newOperator('*'),
434 | ...getPowCalcFunctionNodeFromFunctionNode(functionNode, 7).nodes
435 | ]);
436 | const calcTanNode = newFunction('calc', ...[
437 | uncalcNode(tanTermNode1),
438 | newOperator('+'),
439 | uncalcNode(tanTermNode2),
440 | newOperator('+'),
441 | uncalcNode(tanTermNode3),
442 | newOperator('+'),
443 | uncalcNode(tanTermNode4)
444 | ]);
445 |
446 | return calcTanNode;
447 | }
448 |
449 | /* Conversions
450 | /* ========================================================================== */
451 |
452 | const angleMultipliersByUnit = {
453 | '': 1,
454 | deg: Math.PI / 180,
455 | grad: Math.PI / 200,
456 | rad: 1,
457 | turn: 2 * Math.PI
458 | };
459 |
460 | /* Clone
461 | /* ========================================================================== */
462 |
463 | function clone(node, overrides) {
464 | return normalize(node, node.clone(overrides));
465 | }
466 |
467 | function normalize(node, cloneNode) {
468 | if (node.raws) {
469 | for (const raw in node.raws) {
470 | cloneNode.raws[raw] = node.raws[raw];
471 | }
472 | }
473 |
474 | if (node.nodes) {
475 | for (const index in node.nodes) {
476 | normalize(node.nodes[index], cloneNode.nodes[index]);
477 | }
478 | }
479 |
480 | return cloneNode;
481 | }
482 |
483 | function usePrecision(number, precision) {
484 | return Number(`${Math.round(`${number}e${precision}`)}e-${precision}`);
485 | }
486 |
--------------------------------------------------------------------------------
/test/basic.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --acos: acos(0.8);
3 | --asin: asin(0.6);
4 | --atan: atan(0.8);
5 | --atan2: atan2(5, 5);
6 | --cos: cos(20);
7 | --cos-deg: cos(20deg);
8 | --hypot: hypot(3, 4);
9 | --pow: pow(4, 4);
10 | --pow-rem: pow(4rem, 4);
11 | --sin: sin(20);
12 | --sin-deg: sin(20deg);
13 | --sqrt: sqrt(81);
14 | --sqrt-rem: sqrt(81rem);
15 | --tan: tan(20);
16 | --tan-deg: tan(20deg);
17 | }
18 |
19 | :root {
20 | --cos-calc: cos(calc(20 * 2));
21 | --cos-var: cos(var(--angle));
22 | --pow-calc: pow(calc(4 * 2), 4);
23 | --pow-var: pow(var(--number), 4);
24 | --sin-calc: sin(calc(20 * 2));
25 | --sin-var: sin(var(--angle));
26 | --sqrt-calc: sqrt(calc(81 * 4));
27 | --sqrt-var: sqrt(var(--number));
28 | --tan-calc: tan(calc(20 * 2));
29 | --tan-var: tan(var(--angle));
30 | }
31 |
--------------------------------------------------------------------------------
/test/basic.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --acos: 0.6435;
3 | --asin: 0.6435;
4 | --atan: 0.9273;
5 | --atan2: 0.7854;
6 | --cos: 0.40808;
7 | --cos-deg: 0.93969;
8 | --hypot: 5;
9 | --pow: 256;
10 | --pow-rem: 256rem;
11 | --sin: 0.91295;
12 | --sin-deg: 0.34202;
13 | --sqrt: 9;
14 | --sqrt-rem: 9rem;
15 | --tan: 2.23716;
16 | --tan-deg: 0.36397;
17 | }
18 |
19 | :root {
20 | --cos-calc: calc(1 - ((20 * 2) * (20 * 2) / 2 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 24 ) - ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 720 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 40320 ));
21 | --cos-var: calc(1 - (var(--angle) * var(--angle) / 2 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) / 24 ) - (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 720 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 40320 ));
22 | --pow-calc: pow(calc(4 * 2), 4);
23 | --pow-var: pow(var(--number), 4);
24 | --sin-calc: calc((20 * 2) - ((20 * 2) * (20 * 2) * (20 * 2) / 6 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 120 ) - ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 5040 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 362880 ));
25 | --sin-var: calc(var(--angle) - (var(--angle) * var(--angle) * var(--angle) / 6 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 120 ) - (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 5040 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 362880 ));
26 | --sqrt-calc: calc(((((((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2) + (81 * 4) / (((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2)) / 2) + (81 * 4) / (((((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2) + (81 * 4) / (((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2)) / 2)) / 2);
27 | --sqrt-var: calc((((((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2) + var(--number) / ((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2)) / 2) + var(--number) / ((((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2) + var(--number) / ((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2)) / 2)) / 2);
28 | --tan-calc: calc((20 * 2) + ((1 / 3) * ((20 * 2) * (20 * 2) * (20 * 2))) + ((2 / 15) * ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2))) + ((17 / 315) * ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2))));
29 | --tan-var: calc(var(--angle) + ((1 / 3) * (var(--angle) * var(--angle) * var(--angle))) + ((2 / 15) * (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle))) + ((17 / 315) * (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle))));
30 | }
31 |
--------------------------------------------------------------------------------
/test/basic.precision.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --acos: 0.644;
3 | --asin: 0.644;
4 | --atan: 0.927;
5 | --atan2: 0.785;
6 | --cos: 0.408;
7 | --cos-deg: 0.94;
8 | --hypot: 5;
9 | --pow: 256;
10 | --pow-rem: 256rem;
11 | --sin: 0.913;
12 | --sin-deg: 0.342;
13 | --sqrt: 9;
14 | --sqrt-rem: 9rem;
15 | --tan: 2.237;
16 | --tan-deg: 0.364;
17 | }
18 |
19 | :root {
20 | --cos-calc: calc(1 - ((20 * 2) * (20 * 2) / 2 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 24 ) - ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 720 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 40320 ));
21 | --cos-var: calc(1 - (var(--angle) * var(--angle) / 2 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) / 24 ) - (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 720 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 40320 ));
22 | --pow-calc: pow(calc(4 * 2), 4);
23 | --pow-var: pow(var(--number), 4);
24 | --sin-calc: calc((20 * 2) - ((20 * 2) * (20 * 2) * (20 * 2) / 6 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 120 ) - ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 5040 ) + ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) / 362880 ));
25 | --sin-var: calc(var(--angle) - (var(--angle) * var(--angle) * var(--angle) / 6 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 120 ) - (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 5040 ) + (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) / 362880 ));
26 | --sqrt-calc: calc(((((((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2) + (81 * 4) / (((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2)) / 2) + (81 * 4) / (((((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2) + (81 * 4) / (((((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2) + (81 * 4) / (((((81 * 4) + (81 * 4) / (81 * 4)) / 2) + (81 * 4) / (((81 * 4) + (81 * 4) / (81 * 4)) / 2)) / 2)) / 2)) / 2)) / 2);
27 | --sqrt-var: calc((((((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2) + var(--number) / ((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2)) / 2) + var(--number) / ((((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2) + var(--number) / ((((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2) + var(--number) / ((((var(--number) + var(--number) / var(--number)) / 2) + var(--number) / ((var(--number) + var(--number) / var(--number)) / 2)) / 2)) / 2)) / 2)) / 2);
28 | --tan-calc: calc((20 * 2) + ((1 / 3) * ((20 * 2) * (20 * 2) * (20 * 2))) + ((2 / 15) * ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2))) + ((17 / 315) * ((20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2) * (20 * 2))));
29 | --tan-var: calc(var(--angle) + ((1 / 3) * (var(--angle) * var(--angle) * var(--angle))) + ((2 / 15) * (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle))) + ((17 / 315) * (var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle))));
30 | }
31 |
--------------------------------------------------------------------------------