@magic/css 0.7.40 → 0.7.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -1
- package/package.json +11 -7
- package/src/bin/index.js +96 -0
- package/src/parse/index.mjs +28 -15
- package/src/stringify/fontFaces.mjs +150 -0
- package/src/stringify/index.mjs +24 -1
- package/src/stringify/props.mjs +11 -1
- package/src/stringify/recurseStringify.mjs +15 -90
package/README.md
CHANGED
|
@@ -29,8 +29,44 @@ parse/stringify/write css in js
|
|
|
29
29
|
npm install --save-exact @magic/css
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
|
|
32
33
|
#### usage:
|
|
33
34
|
|
|
35
|
+
##### cli:
|
|
36
|
+
|
|
37
|
+
@magic/css includes a cli script that can handle most usecases the internal javascript api allows.
|
|
38
|
+
|
|
39
|
+
to use this cli from any directory,
|
|
40
|
+
`npm install -g @magic.css` is a useful shortcut.
|
|
41
|
+
after the global install, you can just call `mcss` from anywhere in your terminal.
|
|
42
|
+
|
|
43
|
+
after installation, add:
|
|
44
|
+
`"mcss": "mcss"`
|
|
45
|
+
to your package.json "scripts" section and then
|
|
46
|
+
`npm run mcss`
|
|
47
|
+
to see the help output below.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
@magic/css
|
|
51
|
+
commands:
|
|
52
|
+
stringify - convert css in js to css
|
|
53
|
+
parse - convert css in js to an array of key value pairs
|
|
54
|
+
full - get a full result object.
|
|
55
|
+
|
|
56
|
+
flags:
|
|
57
|
+
--minified - output minified css - alias: ["--m", "-m"]
|
|
58
|
+
--help - alias: ["-h"]
|
|
59
|
+
--out - directory to write output files to. omit to print to stdout - alias: ["--o", "-o"]
|
|
60
|
+
--in - directory with source files, needs index.js to exist - alias: ["--i", "-i"]
|
|
61
|
+
|
|
62
|
+
examples:
|
|
63
|
+
mcss parse --in ./styles --out ./css
|
|
64
|
+
mcss stringify --in ./styles --out ./css
|
|
65
|
+
mcss full --in ./styles --out ./css
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### library:
|
|
69
|
+
|
|
34
70
|
##### init
|
|
35
71
|
```javascript
|
|
36
72
|
import css from '@magic/css'
|
|
@@ -490,6 +526,23 @@ update dependencies
|
|
|
490
526
|
#### 0.7.40
|
|
491
527
|
update dependencies
|
|
492
528
|
|
|
493
|
-
#### 0.7.41
|
|
529
|
+
#### 0.7.41
|
|
530
|
+
update dependencies
|
|
531
|
+
|
|
532
|
+
#### 0.7.42
|
|
533
|
+
update dependencies
|
|
534
|
+
|
|
535
|
+
#### 0.7.43
|
|
536
|
+
* update dependencies
|
|
537
|
+
* added font v2 to allow handling of local() fonts (see https://magic.github.io/css/#styles-webfonts)
|
|
538
|
+
* woff2 files are placed before woff files
|
|
539
|
+
* use single quotes in output css
|
|
540
|
+
* add cli
|
|
541
|
+
|
|
542
|
+
#### 0.7.44
|
|
543
|
+
* css props can be arrays to provide css overloads `{ color: ['green', 'red'] }` turns into `color: green; color: red;`
|
|
544
|
+
* update dependencies
|
|
545
|
+
|
|
546
|
+
#### 0.7.45 - unreleased
|
|
494
547
|
...
|
|
495
548
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magic/css",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.44",
|
|
4
4
|
"author": "Wizards & Witches",
|
|
5
5
|
"description": "css in js",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"test": "t --exclude docs example config.js",
|
|
18
18
|
"calls": "calls"
|
|
19
19
|
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"mcss": "src/bin/index.js",
|
|
22
|
+
"magic-css": "src/bin/index.js"
|
|
23
|
+
},
|
|
20
24
|
"engines": {
|
|
21
25
|
"node": ">=14.15.4"
|
|
22
26
|
},
|
|
@@ -35,11 +39,11 @@
|
|
|
35
39
|
"dependencies": {
|
|
36
40
|
"@magic/cases": "0.0.5",
|
|
37
41
|
"@magic/deep": "0.1.7",
|
|
38
|
-
"@magic/fs": "0.0.
|
|
42
|
+
"@magic/fs": "0.0.18",
|
|
39
43
|
"@magic/log": "0.1.10",
|
|
40
44
|
"@magic/types": "0.1.16",
|
|
41
|
-
"autoprefixer": "10.
|
|
42
|
-
"postcss": "8.
|
|
45
|
+
"autoprefixer": "10.4.0",
|
|
46
|
+
"postcss": "8.4.5"
|
|
43
47
|
},
|
|
44
48
|
"devDependencies": {
|
|
45
49
|
"@magic-modules/git-badges": "0.0.11",
|
|
@@ -47,9 +51,9 @@
|
|
|
47
51
|
"@magic-modules/no-spy": "0.0.6",
|
|
48
52
|
"@magic-modules/pre": "0.0.11",
|
|
49
53
|
"@magic-themes/docs": "0.0.14",
|
|
50
|
-
"@magic/core": "0.0.
|
|
51
|
-
"@magic/format": "0.0.
|
|
52
|
-
"@magic/test": "0.1.
|
|
54
|
+
"@magic/core": "0.0.133",
|
|
55
|
+
"@magic/format": "0.0.33",
|
|
56
|
+
"@magic/test": "0.1.77"
|
|
53
57
|
},
|
|
54
58
|
"keywords": [
|
|
55
59
|
"css-in-js",
|
package/src/bin/index.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
import cli from '@magic/cli'
|
|
6
|
+
import fs from '@magic/fs'
|
|
7
|
+
import log from '@magic/log'
|
|
8
|
+
|
|
9
|
+
import css from '../index.mjs'
|
|
10
|
+
|
|
11
|
+
const cwd = process.cwd()
|
|
12
|
+
|
|
13
|
+
const { args, commands } = cli({
|
|
14
|
+
commands: ['full', 'parse', 'stringify'],
|
|
15
|
+
options: [
|
|
16
|
+
['--in', '--i', '-i'],
|
|
17
|
+
['--out', '--o', '-o'],
|
|
18
|
+
['--minified', '--m', '-m'],
|
|
19
|
+
],
|
|
20
|
+
single: ['--in', '--out', '--minified'],
|
|
21
|
+
help: {
|
|
22
|
+
name: '@magic/css',
|
|
23
|
+
header: 'css in js pipeline.',
|
|
24
|
+
commands: {
|
|
25
|
+
full: 'get a full result object.',
|
|
26
|
+
parse: 'convert css in js to an array of key value pairs',
|
|
27
|
+
stringify: 'convert css in js to css',
|
|
28
|
+
},
|
|
29
|
+
options: {
|
|
30
|
+
'--in': 'directory with index.js that has a css in js object as default export',
|
|
31
|
+
'--out': 'directory to write output files to. omit to print to stdout',
|
|
32
|
+
'--minified': 'output minified css',
|
|
33
|
+
},
|
|
34
|
+
example: `
|
|
35
|
+
mcss parse --in ./css --out ./css
|
|
36
|
+
mcss stringify --in ./styles --out ./css
|
|
37
|
+
`.trim(),
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const logResult = style => log.success('mcss output', `\n\n${style}\n`)
|
|
42
|
+
|
|
43
|
+
const maybeWrite = async ({ args, commands, style }) => {
|
|
44
|
+
const outFile = commands.stringify ? 'main.css' : 'theme.js'
|
|
45
|
+
|
|
46
|
+
if (args.out) {
|
|
47
|
+
if (!path.isAbsolute(args.out)) {
|
|
48
|
+
args.out = path.join(cwd, args.out)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!args.out.endsWith('.css') && !args.out.endsWith('.js')) {
|
|
52
|
+
args.out = path.join(args.out, outFile)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const dirname = path.dirname(args.out)
|
|
56
|
+
await fs.mkdirp(dirname)
|
|
57
|
+
|
|
58
|
+
await fs.writeFile(args.out, style)
|
|
59
|
+
} else {
|
|
60
|
+
logResult(style)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
log.success('mcss is done.')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const run = async () => {
|
|
67
|
+
if (!args.in) {
|
|
68
|
+
args.in = cwd
|
|
69
|
+
log.info('--in not specified, using process.cwd()', args.in)
|
|
70
|
+
} else if (!path.isAbsolute(args.in)) {
|
|
71
|
+
args.in = path.join(cwd, args.in)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!args.in.endsWith('index.js')) {
|
|
75
|
+
args.in = path.join(args.in, 'index.js')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const { default: theme } = await import(args.in)
|
|
79
|
+
|
|
80
|
+
const result = await css(theme)
|
|
81
|
+
|
|
82
|
+
if (commands.full) {
|
|
83
|
+
const style = JSON.stringify(result, null, 2)
|
|
84
|
+
maybeWrite({ args, commands, style })
|
|
85
|
+
} else if (commands.stringify) {
|
|
86
|
+
const style = args.hasOwnProperty('minified') ? result.minified : result.css
|
|
87
|
+
maybeWrite({ args, commands, style })
|
|
88
|
+
} else if (commands.parse) {
|
|
89
|
+
const style = JSON.stringify(result.parsed, null, 2)
|
|
90
|
+
maybeWrite({ args, commands, style })
|
|
91
|
+
} else {
|
|
92
|
+
log.error('MISSING_COMMAND', 'Either parse, stringify or full are required.')
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
run()
|
package/src/parse/index.mjs
CHANGED
|
@@ -29,14 +29,12 @@ const recurseParse = (mod, opts) => {
|
|
|
29
29
|
let children = []
|
|
30
30
|
const props = {}
|
|
31
31
|
|
|
32
|
-
// media and keyframes are special, they provide a full body of css rules
|
|
33
32
|
if (parent.startsWith('@keyframes') || parent.startsWith('@media')) {
|
|
33
|
+
// media and keyframes are special, they provide a full body of css rules
|
|
34
34
|
const i = parse(items)
|
|
35
35
|
return [parent, i]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// handle font face declarations that are expected to expand
|
|
39
|
-
if (parent.startsWith('@font-face')) {
|
|
36
|
+
} else if (parent.startsWith('@font-face')) {
|
|
37
|
+
// handle font face declarations that are expected to expand
|
|
40
38
|
let i = items
|
|
41
39
|
if (is.string(items.url)) {
|
|
42
40
|
i = [items]
|
|
@@ -47,14 +45,18 @@ const recurseParse = (mod, opts) => {
|
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
if (is.objectNative(items)) {
|
|
49
|
+
Object.entries(items).forEach(([name, item]) => {
|
|
50
|
+
if (is.array(item)) {
|
|
51
|
+
props[name] = item
|
|
52
|
+
} else if (is.objectNative(item)) {
|
|
53
|
+
name = getSelector(parent, name)
|
|
54
|
+
children = deep.merge(children, recurseParse([name, item], opts))
|
|
55
|
+
} else {
|
|
56
|
+
props[name] = item
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
58
60
|
|
|
59
61
|
if (is.empty(props)) {
|
|
60
62
|
if (!is.empty(children)) {
|
|
@@ -67,6 +69,11 @@ const recurseParse = (mod, opts) => {
|
|
|
67
69
|
|
|
68
70
|
const isStyle = style => style && style.length === 2 && is.string(style[0]) && is.object(style[1])
|
|
69
71
|
|
|
72
|
+
/*
|
|
73
|
+
* we can not use deep.flatten here, the flattened array has a specific structure:
|
|
74
|
+
* [[key, styles], [key, styles]],
|
|
75
|
+
* deep.flatten would return [key, styles, key, styles]
|
|
76
|
+
*/
|
|
70
77
|
const flat = a => {
|
|
71
78
|
if (isStyle(a)) {
|
|
72
79
|
const [k, v] = a
|
|
@@ -83,22 +90,28 @@ const flat = a => {
|
|
|
83
90
|
}
|
|
84
91
|
}
|
|
85
92
|
})
|
|
93
|
+
|
|
86
94
|
return flattened
|
|
87
95
|
}
|
|
88
96
|
}
|
|
89
97
|
|
|
98
|
+
/*
|
|
99
|
+
* parse the styles css object into an array of key-value pairs.
|
|
100
|
+
*/
|
|
90
101
|
const parse = (styles, opts = {}) => {
|
|
91
102
|
// first check if the user sent us a function that resolves to a css object
|
|
92
103
|
if (is.function(styles)) {
|
|
93
104
|
styles = styles(opts)
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
// this might trigger additionally to the is.function if statement above
|
|
97
107
|
if (is.array(styles)) {
|
|
108
|
+
// if styles are an array, map over the items
|
|
98
109
|
styles = styles.map(s => recurseParse(s, opts))
|
|
99
|
-
} else if (
|
|
110
|
+
} else if (is.objectNative(styles)) {
|
|
111
|
+
// styles are an object
|
|
100
112
|
styles = Object.entries(styles).map(s => recurseParse(s, opts))
|
|
101
113
|
} else {
|
|
114
|
+
// unknown styles
|
|
102
115
|
log.error('invalid styles received', styles)
|
|
103
116
|
}
|
|
104
117
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import is from '@magic/types'
|
|
2
|
+
import deep from '@magic/deep'
|
|
3
|
+
import log from '@magic/log'
|
|
4
|
+
|
|
5
|
+
import { recurseStringify } from './recurseStringify.mjs'
|
|
6
|
+
|
|
7
|
+
export const fontFileTypes = {
|
|
8
|
+
eot: url => `src: url('${url}.eot'); src: url('${url}.eot#iefix') format('embedded-opentype')`,
|
|
9
|
+
woff2: url => `url('${url}.woff2') format('woff2')`,
|
|
10
|
+
woff: url => `url('${url}.woff') format('woff')`,
|
|
11
|
+
ttf: url => `url('${url}.ttf') format('truetype')`,
|
|
12
|
+
svg: (url, family) => `url('${url}.svg#${family}') format('svg')`,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const fontV1 = (name, font) => {
|
|
16
|
+
log.warn('W_DEPRECATED', 'font name', font.family, 'is declared in a deprecated way.')
|
|
17
|
+
log('See: https://magic.github.io/css/#styles-webfonts for more information.')
|
|
18
|
+
|
|
19
|
+
let { family, url, types = 'woff2', weights = 400, styles = 'normal', ...rest } = font
|
|
20
|
+
|
|
21
|
+
if (!url.endsWith('/')) {
|
|
22
|
+
url += '/'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!is.array(weights)) {
|
|
26
|
+
weights = [weights]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!is.array(types)) {
|
|
30
|
+
types = [types]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!is.array(styles)) {
|
|
34
|
+
styles = [styles]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return weights.map(fontWeight => {
|
|
38
|
+
return styles.map(fontStyle => {
|
|
39
|
+
const weightStyleUrl = `${url}${family}-${fontWeight}-${fontStyle}`
|
|
40
|
+
|
|
41
|
+
let fontString = `${name} ${recurseStringify({
|
|
42
|
+
fontFamily: `'${family}'`,
|
|
43
|
+
fontStyle,
|
|
44
|
+
fontWeight,
|
|
45
|
+
...rest,
|
|
46
|
+
})}`
|
|
47
|
+
|
|
48
|
+
let fontFileString = 'src:'
|
|
49
|
+
if (types.includes('eot')) {
|
|
50
|
+
fontFileString = ''
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const fontFileStrings = []
|
|
54
|
+
Object.entries(fontFileTypes).map(([name, fn]) => {
|
|
55
|
+
if (types.includes(name)) {
|
|
56
|
+
const str = fn(weightStyleUrl, family)
|
|
57
|
+
fontFileStrings.push(str)
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
fontFileString += fontFileStrings.join(',') + ';'
|
|
62
|
+
|
|
63
|
+
fontString = fontString.replace('}\n', `${fontFileString} }\n`)
|
|
64
|
+
return fontString
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const fontV2 = (name, font) => {
|
|
70
|
+
let { family, url, types = 'woff2', styles, ...rest } = font
|
|
71
|
+
|
|
72
|
+
if (!url.endsWith('/')) {
|
|
73
|
+
url += '/'
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!is.array(types)) {
|
|
77
|
+
types = [types]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const fontStrings = Object.entries(styles).map(entry => {
|
|
81
|
+
const [fontStyle, weights] = entry
|
|
82
|
+
|
|
83
|
+
return Object.entries(weights).map(([fontWeight, local]) => {
|
|
84
|
+
const weightStyleUrl = `${url}${family}-${fontWeight}-${fontStyle}`
|
|
85
|
+
|
|
86
|
+
const fontFileStrings = []
|
|
87
|
+
|
|
88
|
+
let fontFileString = ''
|
|
89
|
+
if (types.includes('eot')) {
|
|
90
|
+
fontFileString = ''
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
local.forEach(l => {
|
|
94
|
+
fontFileStrings.push(`local('${l}')`)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
Object.entries(fontFileTypes).map(([name, fn]) => {
|
|
98
|
+
if (types.includes(name)) {
|
|
99
|
+
const str = fn(weightStyleUrl, family)
|
|
100
|
+
fontFileStrings.push(str)
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
fontFileString += fontFileStrings.join(',')
|
|
105
|
+
|
|
106
|
+
const props = recurseStringify({
|
|
107
|
+
fontFamily: `'${family}'`,
|
|
108
|
+
fontStyle,
|
|
109
|
+
fontWeight,
|
|
110
|
+
src: fontFileString,
|
|
111
|
+
...rest,
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const fontString = `${name} ${props}`
|
|
115
|
+
|
|
116
|
+
return fontString
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
return deep.flatten(fontStrings).join('\n')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const fontFaces = ({ res, name, items }) => {
|
|
124
|
+
if (is.array(items)) {
|
|
125
|
+
const fontStrings = items.map(font => {
|
|
126
|
+
if (is.objectNative(font.styles)) {
|
|
127
|
+
return fontV2(name, font)
|
|
128
|
+
} else {
|
|
129
|
+
return fontV1(name, font)
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
return deep.flatten(fontStrings).join('\n')
|
|
134
|
+
} else {
|
|
135
|
+
const { fontFamily, fontDir = '', fontRoot, ...rest } = items
|
|
136
|
+
res = `${name} ${recurseStringify({ fontFamily: `'${fontFamily}'`, ...rest })}`
|
|
137
|
+
|
|
138
|
+
const eotString = `src: url('${fontDir}${fontFamily}.eot');`
|
|
139
|
+
|
|
140
|
+
const srcString = `${eotString} src: ${[
|
|
141
|
+
`url('${fontDir}${fontFamily}.eot#iefix') format('embedded-opentype')`,
|
|
142
|
+
`url('${fontDir}${fontFamily}.ttf') format('truetype')`,
|
|
143
|
+
`url('${fontDir}${fontFamily}.woff2') format('woff2')`,
|
|
144
|
+
`url('${fontDir}${fontFamily}.woff') format('woff')`,
|
|
145
|
+
`url('${fontDir}${fontFamily}.svg#${fontFamily}') format('svg');`,
|
|
146
|
+
].join(', ')}`
|
|
147
|
+
|
|
148
|
+
return res.replace('}\n', `${srcString} }\n`)
|
|
149
|
+
}
|
|
150
|
+
}
|
package/src/stringify/index.mjs
CHANGED
|
@@ -4,11 +4,34 @@ import autoprefixer from 'autoprefixer'
|
|
|
4
4
|
import parse from '../parse/index.mjs'
|
|
5
5
|
import recurseStringify from './recurseStringify.mjs'
|
|
6
6
|
|
|
7
|
+
import { fontFaces } from './fontFaces.mjs'
|
|
8
|
+
|
|
9
|
+
const keyframes = ({ name, items, plugins }) => `${name} { ${recurseStringify(items, plugins)} }\n`
|
|
10
|
+
const mediaqueries = ({ name, items, plugins }) =>
|
|
11
|
+
`${name} { ${recurseStringify(items, plugins)} }\n`
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* stringify the styles css object into a valid css string.
|
|
15
|
+
*/
|
|
7
16
|
const stringify = async (styles, opts = {}) => {
|
|
17
|
+
const { plugins = {} } = opts
|
|
18
|
+
|
|
19
|
+
plugins.stringify = {
|
|
20
|
+
'@font-face': fontFaces,
|
|
21
|
+
'@keyframes': keyframes,
|
|
22
|
+
'@media': mediaqueries,
|
|
23
|
+
...plugins.stringify,
|
|
24
|
+
}
|
|
25
|
+
|
|
8
26
|
const parsed = parse(styles, opts)
|
|
9
27
|
|
|
10
|
-
const stringified = recurseStringify(parsed)
|
|
28
|
+
const stringified = recurseStringify(parsed, plugins.stringify, opts)
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* test the resulting css using postcss and autoprefix vendors where needed.
|
|
32
|
+
*/
|
|
11
33
|
const result = await postcss([autoprefixer]).process(stringified, { from: undefined })
|
|
34
|
+
|
|
12
35
|
result.warnings().forEach(warn => {
|
|
13
36
|
console.warn(warn.toString())
|
|
14
37
|
})
|
package/src/stringify/props.mjs
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import cases from '@magic/cases'
|
|
2
|
+
import is from '@magic/types'
|
|
2
3
|
|
|
3
4
|
export const stringifyProps = props =>
|
|
4
5
|
Object.entries(props)
|
|
5
|
-
.map(([k, v]) =>
|
|
6
|
+
.map(([k, v]) => {
|
|
7
|
+
const kebab = cases.kebab(k)
|
|
8
|
+
|
|
9
|
+
// handle css overloads (color: ['green', 'red'] turns into "color: green; color: red;")
|
|
10
|
+
if (is.array(v)) {
|
|
11
|
+
return v.map(o => `${kebab}: ${o};`).join(' ')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return `${kebab}: ${v};`
|
|
15
|
+
})
|
|
6
16
|
.join(' ')
|
|
7
17
|
|
|
8
18
|
export default stringifyProps
|
|
@@ -2,102 +2,27 @@ import is from '@magic/types'
|
|
|
2
2
|
|
|
3
3
|
import stringifyProps from './props.mjs'
|
|
4
4
|
|
|
5
|
-
export const
|
|
6
|
-
if (is.array(
|
|
7
|
-
const
|
|
5
|
+
export const recurseStringify = (res, plugins = [], opts = {}) => {
|
|
6
|
+
if (is.array(res)) {
|
|
7
|
+
const [name, items] = res
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
let
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (!is.array(weights)) {
|
|
16
|
-
weights = [weights]
|
|
17
|
-
}
|
|
18
|
-
if (!is.array(styles)) {
|
|
19
|
-
styles = [styles]
|
|
20
|
-
}
|
|
21
|
-
if (!is.array(types)) {
|
|
22
|
-
types = [types]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
weights.forEach(fontWeight => {
|
|
26
|
-
styles.forEach(fontStyle => {
|
|
27
|
-
const weightStyleUrl = `${url}${family}-${fontWeight}-${fontStyle}`
|
|
28
|
-
|
|
29
|
-
let fontString = `${name} ${recurseStringify({
|
|
30
|
-
fontFamily: `"${family}"`,
|
|
31
|
-
fontStyle,
|
|
32
|
-
fontWeight,
|
|
33
|
-
...rest,
|
|
34
|
-
})}`
|
|
35
|
-
|
|
36
|
-
const fontFileTypes = {
|
|
37
|
-
eot: url =>
|
|
38
|
-
`src: url('${url}.eot'); src: url('${url}.eot#iefix') format('embedded-opentype')`,
|
|
39
|
-
ttf: url => `url('${url}.ttf') format('truetype')`,
|
|
40
|
-
woff: url => `url('${url}.woff') format('woff')`,
|
|
41
|
-
woff2: url => `url('${url}.woff2') format('woff2')`,
|
|
42
|
-
svg: url => `url('${url}.svg#${family}') format('svg')`,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let fontFileString = 'src:'
|
|
46
|
-
if (types.includes('eot')) {
|
|
47
|
-
fontFileString = ''
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const fontFileStrings = []
|
|
51
|
-
Object.entries(fontFileTypes).map(([name, fn]) => {
|
|
52
|
-
if (types.includes(name)) {
|
|
53
|
-
const str = fn(weightStyleUrl)
|
|
54
|
-
fontFileStrings.push(str)
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
fontFileString += fontFileStrings.join(',') + ';'
|
|
59
|
-
|
|
60
|
-
fontString = fontString.replace('}\n', `${fontFileString} }\n`)
|
|
61
|
-
fontStrings.push(fontString)
|
|
62
|
-
})
|
|
9
|
+
if (is.string(name)) {
|
|
10
|
+
let result = ''
|
|
11
|
+
Object.entries(plugins).forEach(([lookup, fn]) => {
|
|
12
|
+
if (name.startsWith(lookup)) {
|
|
13
|
+
result = fn({ name, items, plugins })
|
|
14
|
+
}
|
|
63
15
|
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
return fontStrings.join('\n')
|
|
67
|
-
} else {
|
|
68
|
-
const { fontFamily, fontDir = '', fontRoot, ...rest } = items
|
|
69
|
-
res = `${name} ${recurseStringify({ fontFamily: `"${fontFamily}"`, ...rest })}`
|
|
70
|
-
|
|
71
|
-
const eotString = `src: url('${fontDir}${fontFamily}.eot');`
|
|
72
|
-
|
|
73
|
-
const srcString = `${eotString} src: ${[
|
|
74
|
-
`url('${fontDir}${fontFamily}.eot#iefix') format('embedded-opentype')`,
|
|
75
|
-
`url('${fontDir}${fontFamily}.ttf') format('truetype')`,
|
|
76
|
-
`url('${fontDir}${fontFamily}.woff') format('woff')`,
|
|
77
|
-
`url('${fontDir}${fontFamily}.woff2') format('woff2')`,
|
|
78
|
-
`url('${fontDir}${fontFamily}.svg#${fontFamily}') format('svg');`,
|
|
79
|
-
].join(', ')}`
|
|
80
16
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export const recurseStringify = mod => {
|
|
86
|
-
let res = mod
|
|
87
|
-
|
|
88
|
-
if (is.array(mod)) {
|
|
89
|
-
const [name, items] = mod
|
|
90
|
-
if (is.string(name)) {
|
|
91
|
-
if (name.startsWith('@keyframes') || name.startsWith('@media')) {
|
|
92
|
-
return `${name} { ${recurseStringify(items)} }\n`
|
|
93
|
-
} else if (name.startsWith('@font-face')) {
|
|
94
|
-
return fontFaces({ res, name, items })
|
|
17
|
+
if (result) {
|
|
18
|
+
return result
|
|
95
19
|
}
|
|
96
20
|
}
|
|
97
21
|
|
|
98
|
-
return
|
|
99
|
-
} else if (is.object(
|
|
100
|
-
|
|
22
|
+
return res.map(r => recurseStringify(r, plugins, opts)).join(' ')
|
|
23
|
+
} else if (is.object(res)) {
|
|
24
|
+
const stringified = stringifyProps(res)
|
|
25
|
+
return `{ ${stringified} }\n`
|
|
101
26
|
}
|
|
102
27
|
|
|
103
28
|
return res
|