Skip to content

Refactor: extract reusable core for consumer libraries #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@
"code",
"test"
]
},
{
"login": "TxHawks",
"name": "Jonathan Pollak",
"avatar_url": "https://avatars2.githubusercontent.com/u/5658514?v=4",
"profile": "https://github.com/TxHawks",
"contributions": [
"code",
"test"
]
}
]
}
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RTL conversion for CSS in JS objects
[![downloads][downloads-badge]][npm-stat]
[![MIT License][license-badge]][LICENSE]

[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome][prs-badge]][prs]
[![Donate][donate-badge]][donate]
[![Code of Conduct][coc-badge]][coc]
Expand Down Expand Up @@ -59,7 +59,7 @@ console.log(styles) // logs {paddingRight: 23}
You can also just include a script tag in your browser and use the `rtlCSSJS` variable:

```html
<script src="https://unpkg.com/rtl-css-js@1.0.0-beta.1"></script>
<script src="https://unpkg.com/rtl-css-js"></script>
<script>
const styles = rtlCSSJS({paddingRight: 23})
console.log(styles) // logs {paddingLeft: 23}
Expand All @@ -74,6 +74,17 @@ const styles = rtlCSSJS({paddingLeft: '20px /* @noflip */'})
console.log(styles) // logs {paddingLeft: '20px /* @noflip */' }
```

### core

`rtl-css-js` also exposes its internal helpers and utilities so you can deal
with [certain scenarios](https://github.com/kentcdodds/rtl-css-js/pull/22)
yourself. To use these you can use the `rtlCSSJSCore` global with the UMD build,
`require('rtl-css-js/core')`, or use
`import {propertyValueConverters, arrayToObject} from 'rtl-css-js/core.esm'`.

You can import anything that's exported from `src/core`. Please see the code
comments for documentation on how to use these.

## Caveats

### `background`
Expand All @@ -96,8 +107,8 @@ I'm not aware of any, if you are please [make a pull request](http://makeapullre
Thanks goes to these people ([emoji key][emojis]):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
| [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub>Kent C. Dodds</sub>](https://kentcdodds.com)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=kentcdodds "Code") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=kentcdodds "Tests") [🚇](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars.githubusercontent.com/u/63876?v=3" width="100px;"/><br /><sub>Ahmed El Gabri</sub>](https://gabri.me)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=ahmedelgabri "Code") [📖](https://github.com/kentcdodds/rtl-css-js/commits?author=ahmedelgabri "Documentation") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=ahmedelgabri "Tests") | [<img src="https://avatars1.githubusercontent.com/u/1383861?v=4" width="100px;"/><br /><sub>Maja Wichrowska</sub>](https://github.com/majapw)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=majapw "Code") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=majapw "Tests") | [<img src="https://avatars2.githubusercontent.com/u/6600720?v=4" width="100px;"/><br /><sub>Yaniv</sub>](https://github.com/yzimet)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=yzimet "Code") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=yzimet "Tests") |
| :---: | :---: | :---: | :---: |
| [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub>Kent C. Dodds</sub>](https://kentcdodds.com)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=kentcdodds "Code") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=kentcdodds "Tests") [🚇](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars.githubusercontent.com/u/63876?v=3" width="100px;"/><br /><sub>Ahmed El Gabri</sub>](https://gabri.me)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=ahmedelgabri "Code") [📖](https://github.com/kentcdodds/rtl-css-js/commits?author=ahmedelgabri "Documentation") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=ahmedelgabri "Tests") | [<img src="https://avatars1.githubusercontent.com/u/1383861?v=4" width="100px;"/><br /><sub>Maja Wichrowska</sub>](https://github.com/majapw)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=majapw "Code") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=majapw "Tests") | [<img src="https://avatars2.githubusercontent.com/u/6600720?v=4" width="100px;"/><br /><sub>Yaniv</sub>](https://github.com/yzimet)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=yzimet "Code") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=yzimet "Tests") | [<img src="https://avatars2.githubusercontent.com/u/5658514?v=4" width="100px;"/><br /><sub>Jonathan Pollak</sub>](https://github.com/TxHawks)<br />[💻](https://github.com/kentcdodds/rtl-css-js/commits?author=TxHawks "Code") [⚠️](https://github.com/kentcdodds/rtl-css-js/commits?author=TxHawks "Tests") |
| :---: | :---: | :---: | :---: | :---: |
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors][all-contributors] specification. Contributions of any kind welcome!
Expand Down
3 changes: 3 additions & 0 deletions core.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint import/no-unresolved:0 */
// this file just makes it easier to import dist/core
export * from './dist/rtl-css-js.core.esm'
3 changes: 3 additions & 0 deletions core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint import/no-unresolved:0 */
// this file just makes it easier to require dist/core
module.exports = require('./dist/rtl-css-js.core.cjs')
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@
"module": "dist/rtl-css-js.es.js",
"scripts": {
"add-contributor": "kcd-scripts contributors add",
"build": "kcd-scripts build --browser --environment BUILD_NAME:rtlCSSJS",
"build": "rimraf dist && npm-run-all build:*",
"build:main":
"kcd-scripts build --bundle --environment BUILD_NAME:rtlCSSJS --no-clean",
"build:core":
"kcd-scripts build --bundle --environment BUILD_NAME:rtlCSSJSCore,BUILD_FILENAME_SUFFIX:\".core\",BUILD_INPUT:src/core/index.js --no-clean",
"lint": "kcd-scripts lint",
"test": "kcd-scripts test",
"test:update": "npm run test -s -- --coverage --updateSnapshot",
"validate": "kcd-scripts validate",
"precommit": "kcd-scripts precommit"
},
"files": ["dist"],
"files": ["dist", "core", "core.esm"],
"keywords": ["css-in-js", "ltr", "rtl", "cssjanus"],
"author": "Kent C. Dodds <kent@doddsfamily.us> (http://kentcdodds.com/)",
"license": "MIT",
"devDependencies": {
"kcd-scripts": "^0.6.0"
"kcd-scripts": "^0.16.0",
"npm-run-all": "^4.1.1",
"rimraf": "^2.6.2"
},
"eslintConfig": {
"extends": "./node_modules/kcd-scripts/eslint.js"
Expand Down
14 changes: 11 additions & 3 deletions src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import convert from '../'

// use this object for bigger tests
// the key the test title
// the key is the test title
// the objects each have an input (array that's spread on a call to convert) and an output which is the resulting object
// if you want to run `.only` or `.skip` for one of the tests
// specify `modifier: 'only'` or `modifier: 'skip'` 👍
Expand Down Expand Up @@ -189,8 +189,16 @@ const shortTests = [
{backgroundImage: 'repeating-linear-gradient(to left top, blue, red)'},
],
[
[{backgroundImage: 'repeating-linear-gradient(to left, #00ff00 0%, #ff0000 100%)'}],
{backgroundImage: 'repeating-linear-gradient(to right, #00ff00 0%, #ff0000 100%)'},
[
{
backgroundImage:
'repeating-linear-gradient(to left, #00ff00 0%, #ff0000 100%)',
},
],
{
backgroundImage:
'repeating-linear-gradient(to right, #00ff00 0%, #ff0000 100%)',
},
],
[
[{background: '#000 linear-gradient(to left top, blue, red)'}],
Expand Down
22 changes: 22 additions & 0 deletions src/core/__tests__/property-value-converters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* These are tests for core functionality that isn't used by the canonical
* implementation and therefore cannot be tested in the main test file.
*/

import {propertyValueConverters} from '../'

describe('Extended core functionality', () => {
describe('propertyValueConverters', () => {
it('should not calculate new background position when "isRtl" is "false"', () => {
const value = '77% 40%'
const newValue = propertyValueConverters.backgroundPosition({
value,
valuesToConvet: {left: 'right', right: 'left'},
isRtl: false,
bgPosDirectionRegex: new RegExp('(left)|(right)'),
})

expect(value).toEqual(newValue)
})
})
})
4 changes: 4 additions & 0 deletions src/core/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import propertyValueConverters from './property-value-converters'

export * from './utils'
export {propertyValueConverters}
162 changes: 162 additions & 0 deletions src/core/property-value-converters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import {
includes,
isNumber,
calculateNewBackgroundPosition,
calculateNewTranslate,
handleQuartetValues,
getValuesAsList,
} from './utils'

// some values require a little fudging, that fudging goes here.
const propertyValueConverters = {
padding({value}) {
if (isNumber(value)) {
return value
}
return handleQuartetValues(value)
},
textShadow({value}) {
// intentionally leaving off the `g` flag here because we only want to change the first number (which is the offset-x)
return value.replace(/(-*)([.|\d]+)/, (match, negative, number) => {
if (number === '0') {
return match
}
const doubleNegative = negative === '' ? '-' : ''
return `${doubleNegative}${number}`
})
},
borderColor({value}) {
return handleQuartetValues(value)
},
borderRadius({value}) {
if (isNumber(value)) {
return value
}
if (includes(value, '/')) {
const [radius1, radius2] = value.split('/')
const convertedRadius1 = propertyValueConverters.borderRadius({
value: radius1.trim(),
})
const convertedRadius2 = propertyValueConverters.borderRadius({
value: radius2.trim(),
})
return `${convertedRadius1} / ${convertedRadius2}`
}
const splitValues = getValuesAsList(value)
switch (splitValues.length) {
case 2: {
return splitValues.reverse().join(' ')
}
case 4: {
const [topLeft, topRight, bottomRight, bottomLeft] = splitValues
return [topRight, topLeft, bottomLeft, bottomRight].join(' ')
}
default: {
return value
}
}
},
background({
value,
valuesToConvert,
isRtl,
bgImgDirectionRegex,
bgPosDirectionRegex,
}) {
// Yeah, this is in need of a refactor 🙃...
// but this property is a tough cookie 🍪
// get the backgroundPosition out of the string by removing everything that couldn't be the backgroundPosition value
const backgroundPositionValue = value
.replace(
/(url\(.*?\))|(rgba?\(.*?\))|(hsl\(.*?\))|(#[a-fA-F0-9]+)|((^| )(\D)+( |$))/g,
'',
)
.trim()
// replace that backgroundPosition value with the converted version
value = value.replace(
backgroundPositionValue,
propertyValueConverters.backgroundPosition({
value: backgroundPositionValue,
valuesToConvert,
isRtl,
bgPosDirectionRegex,
}),
)
// do the backgroundImage value replacing on the whole value (because why not?)
return propertyValueConverters.backgroundImage({
value,
valuesToConvert,
bgImgDirectionRegex,
})
},
backgroundImage({value, valuesToConvert, bgImgDirectionRegex}) {
if (!includes(value, 'url(') && !includes(value, 'linear-gradient(')) {
return value
}
return value.replace(bgImgDirectionRegex, (match, g1, group2) => {
return match.replace(group2, valuesToConvert[group2])
})
},
backgroundPosition({value, valuesToConvert, isRtl, bgPosDirectionRegex}) {
return (
value
// intentionally only grabbing the first instance of this because that represents `left`
.replace(isRtl ? /^((-|\d|\.)+%)/ : null, (match, group) =>
calculateNewBackgroundPosition(group),
)
.replace(bgPosDirectionRegex, match => valuesToConvert[match])
)
},
backgroundPositionX({value, valuesToConvert, isRtl, bgPosDirectionRegex}) {
if (isNumber(value)) {
return value
}
return propertyValueConverters.backgroundPosition({
value,
valuesToConvert,
isRtl,
bgPosDirectionRegex,
})
},
transform({value}) {
// This was copied and modified from CSSJanus:
// https://github.com/cssjanus/cssjanus/blob/4a40f001b1ba35567112d8b8e1d9d95eda4234c3/src/cssjanus.js#L152-L153
const nonAsciiPattern = '[^\\u0020-\\u007e]'
const unicodePattern = '(?:(?:\\[0-9a-f]{1,6})(?:\\r\\n|\\s)?)'
const numPattern = '(?:[0-9]*\\.[0-9]+|[0-9]+)'
const unitPattern = '(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)'
const escapePattern = `(?:${unicodePattern}|\\\\[^\\r\\n\\f0-9a-f])`
const nmstartPattern = `(?:[_a-z]|${nonAsciiPattern}|${escapePattern})`
const nmcharPattern = `(?:[_a-z0-9-]|${nonAsciiPattern}|${escapePattern})`
const identPattern = `-?${nmstartPattern}${nmcharPattern}*`
const quantPattern = `${numPattern}(?:\\s*${unitPattern}|${identPattern})?`
const signedQuantPattern = `((?:-?${quantPattern})|(?:inherit|auto))`
const translateXRegExp = new RegExp(
`(translateX\\s*\\(\\s*)${signedQuantPattern}(\\s*\\))`,
'gi',
)
const translateRegExp = new RegExp(
`(translate\\s*\\(\\s*)${signedQuantPattern}((?:\\s*,\\s*${signedQuantPattern}){0,1}\\s*\\))`,
'gi',
)
const translate3dRegExp = new RegExp(
`(translate3d\\s*\\(\\s*)${signedQuantPattern}((?:\\s*,\\s*${signedQuantPattern}){0,2}\\s*\\))`,
'gi',
)
return value
.replace(translateXRegExp, calculateNewTranslate)
.replace(translateRegExp, calculateNewTranslate)
.replace(translate3dRegExp, calculateNewTranslate)
},
}

propertyValueConverters.margin = propertyValueConverters.padding
propertyValueConverters.borderWidth = propertyValueConverters.padding
propertyValueConverters.boxShadow = propertyValueConverters.textShadow
propertyValueConverters.webkitBoxShadow = propertyValueConverters.textShadow
propertyValueConverters.mozBoxShadow = propertyValueConverters.textShadow
propertyValueConverters.borderStyle = propertyValueConverters.borderColor
propertyValueConverters.webkitTransform = propertyValueConverters.transform
propertyValueConverters.mozTransform = propertyValueConverters.transform

export default propertyValueConverters
Loading