@spark-ui/cli-utils 2.7.3 → 2.8.0
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/CHANGELOG.md +6 -0
- package/package.json +3 -7
- package/src/index.doc.mdx +0 -12
- package/bin/spark-setup-themes.mjs +0 -80
- package/src/setup-themes/utils/constants.js +0 -13
- package/src/setup-themes/utils/createCSSTokenfile.js +0 -109
- package/src/setup-themes/utils/createTailwindThemeConfigFile.js +0 -136
- package/src/setup-themes/utils/index.js +0 -2
- package/src/setup-themes/utils/utils.js +0 -54
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [2.8.0](https://github.com/adevinta/spark/compare/@spark-ui/cli-utils@2.7.3...@spark-ui/cli-utils@2.8.0) (2023-03-23)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- **cli-utils:** remove deprecated spark-setup-themes cli package ([a2efa9c](https://github.com/adevinta/spark/commit/a2efa9c15b3ece4285043fd25858435f455f257d))
|
|
11
|
+
|
|
6
12
|
## [2.7.3](https://github.com/adevinta/spark/compare/@spark-ui/cli-utils@2.7.2...@spark-ui/cli-utils@2.7.3) (2023-03-22)
|
|
7
13
|
|
|
8
14
|
**Note:** Version bump only for package @spark-ui/cli-utils
|
package/package.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spark-ui/cli-utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Spark CLI utils",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"bin": {
|
|
9
9
|
"spark": "./bin/spark.mjs",
|
|
10
|
-
"spark-generate": "./bin/spark-generate.mjs"
|
|
11
|
-
"spark-setup-themes": "./bin/spark-setup-themes.mjs"
|
|
10
|
+
"spark-generate": "./bin/spark-generate.mjs"
|
|
12
11
|
},
|
|
13
12
|
"type": "module",
|
|
14
13
|
"repository": {
|
|
@@ -18,19 +17,16 @@
|
|
|
18
17
|
},
|
|
19
18
|
"dependencies": {
|
|
20
19
|
"@clack/prompts": "0.6.2",
|
|
21
|
-
"@spark-ui/theme-utils": "^2.10.1",
|
|
22
20
|
"camel-case": "4.1.2",
|
|
23
21
|
"chalk": "5.2.0",
|
|
24
22
|
"commander": "10.0.0",
|
|
25
|
-
"deepmerge": "4.3.0",
|
|
26
23
|
"esbuild": "0.17.11",
|
|
27
24
|
"fs-extra": "11.1.0",
|
|
28
25
|
"glob": "8.1.0",
|
|
29
|
-
"hex-rgb": "5.0.0",
|
|
30
26
|
"pascal-case": "3.1.2"
|
|
31
27
|
},
|
|
32
28
|
"devDependencies": {
|
|
33
29
|
"@types/fs-extra": "11.0.1"
|
|
34
30
|
},
|
|
35
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "9b2398b8c58cf0359169bdde07e8e33ede075e16"
|
|
36
32
|
}
|
package/src/index.doc.mdx
CHANGED
|
@@ -9,7 +9,6 @@ import { Alert } from '@docs/helpers/Alert'
|
|
|
9
9
|
This package provides some CLI commands to improve the development experience when building the Spark design system. Right now there are some different commands available:
|
|
10
10
|
|
|
11
11
|
- A command for generating new components: `$ spark generate`.
|
|
12
|
-
- A command for doing the initial setup for one or more themes: `$ spark setup-themes`.
|
|
13
12
|
|
|
14
13
|
## Contents
|
|
15
14
|
|
|
@@ -44,14 +43,3 @@ Then, a command prompt will guide you through the process by asking you for:
|
|
|
44
43
|
- the package name (required),
|
|
45
44
|
- the template used (required, only `Component` template available right now)
|
|
46
45
|
- and the package description (optional).
|
|
47
|
-
|
|
48
|
-
<StoryHeading label="Setting up your themes" as="h2" />
|
|
49
|
-
|
|
50
|
-
<Alert kind="info">
|
|
51
|
-
[Step-by-step guide to integrating Spark into your current
|
|
52
|
-
project](?path=/docs/getting-started--docs#getting-started)
|
|
53
|
-
</Alert>
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
$ spark setup-themes
|
|
57
|
-
```
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { spawn } from 'child_process'
|
|
4
|
-
import { join, extname } from 'node:path'
|
|
5
|
-
import { readFileSync, readdirSync, writeFileSync, unlinkSync } from 'node:fs'
|
|
6
|
-
import { transformSync } from 'esbuild'
|
|
7
|
-
import { createRequire } from 'node:module'
|
|
8
|
-
import { Logger, System } from '../src/core/index.mjs'
|
|
9
|
-
import {
|
|
10
|
-
createCSSTokensFile,
|
|
11
|
-
createTailwindThemeConfigFile,
|
|
12
|
-
} from '../src/setup-themes/utils/index.js'
|
|
13
|
-
|
|
14
|
-
const logger = new Logger()
|
|
15
|
-
const system = new System({ logger })
|
|
16
|
-
|
|
17
|
-
const require = createRequire(import.meta.url)
|
|
18
|
-
const configFile = readdirSync(process.cwd()).find(fileName =>
|
|
19
|
-
/^(spark\.theme\.config)\.(js|ts|mjs|mts|cjs|cts)$/.test(fileName)
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
if (!configFile) {
|
|
23
|
-
system.exit(
|
|
24
|
-
"We couldn't find a `spark.theme.config` file in this folder. Please make sure that the file is located in the root folder of your project"
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const configFilePath = join(process.cwd(), configFile)
|
|
29
|
-
const configFileIsMJS = /spark\.theme\.config\.(mjs)$/.test(configFile)
|
|
30
|
-
|
|
31
|
-
const allowedExtensions = ['.ts', '.mts', '.cts', '.js', '.cjs', '.mjs']
|
|
32
|
-
const jsFileExtension = '.mjs'
|
|
33
|
-
const configFileExtension = extname(configFilePath)
|
|
34
|
-
if (!allowedExtensions.includes(configFileExtension)) {
|
|
35
|
-
system.exit(`Your spark.theme.config file extension (${configFileExtension}) is not supported.`)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const configFileContent = readFileSync(configFilePath, 'utf-8')
|
|
39
|
-
const jsCode = transformSync(configFileContent, { loader: 'ts' }).code
|
|
40
|
-
|
|
41
|
-
const jsFilePath = configFilePath.replace(/\.ts$|\.mts$|\.cts$|\.js|\.cjs$/, jsFileExtension)
|
|
42
|
-
const jsFileContents = jsCode
|
|
43
|
-
|
|
44
|
-
if (!configFileIsMJS) writeFileSync(jsFilePath, jsFileContents)
|
|
45
|
-
|
|
46
|
-
import(jsFilePath)
|
|
47
|
-
.then(module => {
|
|
48
|
-
const { tailwindThemeConfigPath, tailwindCSSPath, themes, htmlFontSize = 16 } = module.default
|
|
49
|
-
|
|
50
|
-
createTailwindThemeConfigFile(tailwindThemeConfigPath)
|
|
51
|
-
createCSSTokensFile(tailwindCSSPath, themes, htmlFontSize)
|
|
52
|
-
|
|
53
|
-
const child = spawn(process.execPath, [jsFilePath], {
|
|
54
|
-
stdio: 'inherit',
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
child.on('exit', code => {
|
|
58
|
-
if (!configFileIsMJS) unlinkSync(jsFilePath)
|
|
59
|
-
logger.success(
|
|
60
|
-
`✨ Your Spark Tailwind theme config file has been successfully created: ${join(
|
|
61
|
-
process.cwd(),
|
|
62
|
-
tailwindThemeConfigPath
|
|
63
|
-
)}`
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
logger.success(
|
|
67
|
-
`✨ Your Spark Tailwind CSS Tokens file file has been successfully created: ${join(
|
|
68
|
-
process.cwd(),
|
|
69
|
-
tailwindCSSPath
|
|
70
|
-
)}`
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
process.exit(code)
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
.catch(err => {
|
|
77
|
-
unlinkSync(jsFilePath)
|
|
78
|
-
system.exit(`
|
|
79
|
-
Something went wrong while running ${configFilePath}: ${err}`)
|
|
80
|
-
})
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export const tailwindKeys = {
|
|
2
|
-
colors: 'colors',
|
|
3
|
-
fontSize: 'fontSize',
|
|
4
|
-
screens: 'screens',
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export const DEFAULT_KEY = 'DEFAULT'
|
|
8
|
-
|
|
9
|
-
export const defaultColors = {
|
|
10
|
-
inherit: 'inherit',
|
|
11
|
-
current: 'currentColor',
|
|
12
|
-
transparent: 'transparent',
|
|
13
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { appendFileSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
|
|
4
|
-
import hexRgb from 'hex-rgb'
|
|
5
|
-
|
|
6
|
-
import { DEFAULT_KEY } from './constants.js'
|
|
7
|
-
import {
|
|
8
|
-
doubleHyphensRegex,
|
|
9
|
-
getRemEquivalentValue,
|
|
10
|
-
isHex,
|
|
11
|
-
isObject,
|
|
12
|
-
isStringOrNumber,
|
|
13
|
-
toKebabCase,
|
|
14
|
-
} from './utils.js'
|
|
15
|
-
|
|
16
|
-
function toCSSVars(_theme, className, htmlFontSize) {
|
|
17
|
-
const flattenedTheme = {}
|
|
18
|
-
|
|
19
|
-
function flatten(theme, paths = []) {
|
|
20
|
-
Object.entries(theme).forEach(([key, value]) => {
|
|
21
|
-
if (isObject(value)) {
|
|
22
|
-
return flatten(value, paths.concat(key))
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (isStringOrNumber(value)) {
|
|
26
|
-
const getFormattedValue = () => {
|
|
27
|
-
if (isHex(value)) {
|
|
28
|
-
const { red, green, blue } = hexRgb(value)
|
|
29
|
-
|
|
30
|
-
return `${red} ${green} ${blue}`
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (/rem$/gi.test(value)) {
|
|
34
|
-
return getRemEquivalentValue(value, htmlFontSize)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return value
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
flattenedTheme[
|
|
41
|
-
`--${[...paths, key === DEFAULT_KEY ? key.toLowerCase() : key]
|
|
42
|
-
.map(toKebabCase)
|
|
43
|
-
.join('-')
|
|
44
|
-
.replace(doubleHyphensRegex, '-')}`
|
|
45
|
-
] = getFormattedValue()
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
flatten(_theme)
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
...flattenedTheme,
|
|
54
|
-
className,
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const toStringifiedTheme = theme =>
|
|
59
|
-
Object.entries(theme)
|
|
60
|
-
.map(([k, v]) => `${k}:${v}`)
|
|
61
|
-
.join(';')
|
|
62
|
-
|
|
63
|
-
const getStringifiedThemes = (themeRecord, htmlFontSize) =>
|
|
64
|
-
Object.keys(themeRecord).map(key => {
|
|
65
|
-
const { className, ...rest } = toCSSVars(themeRecord[key], key, htmlFontSize)
|
|
66
|
-
|
|
67
|
-
return key === 'default'
|
|
68
|
-
? `:root{${toStringifiedTheme(rest)}}`
|
|
69
|
-
: `.${className}{${toStringifiedTheme(rest)}}`
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Creates a CSS file containing theme tokens represented as CSS custom properties
|
|
74
|
-
*
|
|
75
|
-
* @param {string} path - The file path where the CSS file will be created.
|
|
76
|
-
* @param {Record<string, Theme>} themeRecord - A record (with a required key of "default") of themes that will be included in the CSS Tokens file.
|
|
77
|
-
*
|
|
78
|
-
* @example
|
|
79
|
-
*
|
|
80
|
-
* const defaultTheme: Theme = { ... }
|
|
81
|
-
* const darkTheme: Theme = { ... }
|
|
82
|
-
* const otherTheme: Theme = { ... }
|
|
83
|
-
*
|
|
84
|
-
* const themes = {
|
|
85
|
-
* default: defaultTheme,
|
|
86
|
-
* dark: darkTheme
|
|
87
|
-
* other: otherTheme
|
|
88
|
-
* }
|
|
89
|
-
*
|
|
90
|
-
* createCSSTokensFile('somePath.css', themes) // will generate a "somePath.css" file in the relative location from which it was called
|
|
91
|
-
*/
|
|
92
|
-
export function createCSSTokensFile(path, themeRecord, htmlFontSize) {
|
|
93
|
-
try {
|
|
94
|
-
appendFileSync(
|
|
95
|
-
join(process.cwd(), path),
|
|
96
|
-
`
|
|
97
|
-
@tailwind base;
|
|
98
|
-
@tailwind components;
|
|
99
|
-
@tailwind utilities;
|
|
100
|
-
@layer base {${getStringifiedThemes(themeRecord, htmlFontSize).join('')}}
|
|
101
|
-
`,
|
|
102
|
-
{
|
|
103
|
-
flag: 'w',
|
|
104
|
-
}
|
|
105
|
-
)
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.error('Failed to create the CSS token file', error)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { writeFileSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
|
|
4
|
-
import { defaultTheme } from '@spark-ui/theme-utils'
|
|
5
|
-
|
|
6
|
-
import { DEFAULT_KEY, defaultColors, tailwindKeys } from './constants.js'
|
|
7
|
-
import {
|
|
8
|
-
doubleHyphensRegex,
|
|
9
|
-
hasNumber,
|
|
10
|
-
isAlphanumericWithLeadingLetter,
|
|
11
|
-
isCamelCase,
|
|
12
|
-
isHex,
|
|
13
|
-
isObject,
|
|
14
|
-
isStringOrNumber,
|
|
15
|
-
toKebabCase,
|
|
16
|
-
} from './utils.js'
|
|
17
|
-
|
|
18
|
-
function toTailwindConfig(_theme) {
|
|
19
|
-
const themeCpy = JSON.parse(JSON.stringify(_theme))
|
|
20
|
-
|
|
21
|
-
const { fontSize, colors, screens } = tailwindKeys
|
|
22
|
-
|
|
23
|
-
/* eslint-disable complexity */
|
|
24
|
-
function traverse(theme, paths = []) {
|
|
25
|
-
Object.entries(theme).forEach(([key, value]) => {
|
|
26
|
-
// 👀 see: https://tailwindcss.com/docs/font-size#providing-a-default-line-height
|
|
27
|
-
if (isObject(value) && !paths.length && key === fontSize) {
|
|
28
|
-
Object.keys(value).forEach(k => {
|
|
29
|
-
const prefix = toKebabCase(fontSize)
|
|
30
|
-
if (isStringOrNumber(value[k])) {
|
|
31
|
-
theme[key][k] = `var(--${prefix}-${k})`
|
|
32
|
-
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const kebabedKey = isCamelCase(k) || hasNumber(k) ? toKebabCase(k) : k
|
|
37
|
-
|
|
38
|
-
if (kebabedKey !== k) {
|
|
39
|
-
const tmp = theme[key][k]
|
|
40
|
-
delete theme[key][k]
|
|
41
|
-
theme[key][kebabedKey] = tmp
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
theme[key][kebabedKey] = [
|
|
45
|
-
`var(--${prefix}-${kebabedKey}-font-size)`,
|
|
46
|
-
{
|
|
47
|
-
...(value[kebabedKey].lineHeight && {
|
|
48
|
-
lineHeight: `var(--${prefix}-${kebabedKey}-line-height)`,
|
|
49
|
-
}),
|
|
50
|
-
...(value[kebabedKey].letterSpacing && {
|
|
51
|
-
letterSpacing: `var(--${prefix}-${kebabedKey}-letter-spacing)`,
|
|
52
|
-
}),
|
|
53
|
-
...(value[kebabedKey].fontWeight && {
|
|
54
|
-
fontWeight: `var(--${prefix}-${kebabedKey}-font-weight)`,
|
|
55
|
-
}),
|
|
56
|
-
},
|
|
57
|
-
]
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
return
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (isObject(value)) {
|
|
64
|
-
Object.keys(value).forEach(k => {
|
|
65
|
-
if (k === DEFAULT_KEY) {
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!isObject(value[k]) && !isCamelCase(k)) {
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const tmp = value[k]
|
|
74
|
-
delete value[k]
|
|
75
|
-
value[toKebabCase(k)] = tmp
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
return traverse(value, paths.concat(key))
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (isStringOrNumber(value)) {
|
|
82
|
-
const rootPath = paths.at(0) ?? ''
|
|
83
|
-
const isScreenValue = rootPath.includes(screens)
|
|
84
|
-
const isColorValue = rootPath.includes(colors)
|
|
85
|
-
|
|
86
|
-
const formattedValue = (() => {
|
|
87
|
-
if (isColorValue && isHex(value)) {
|
|
88
|
-
return `rgb(var(--${paths.join('-')}-${key}) / <alpha-value>)`
|
|
89
|
-
}
|
|
90
|
-
if (isScreenValue) {
|
|
91
|
-
return String(value).toLowerCase()
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return `var(--${paths.join('-')}-${key.toLowerCase()})`
|
|
95
|
-
})()
|
|
96
|
-
|
|
97
|
-
const formattedKey = isAlphanumericWithLeadingLetter(key) ? toKebabCase(key) : key
|
|
98
|
-
|
|
99
|
-
if (formattedKey !== key) {
|
|
100
|
-
delete theme[key]
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
theme[formattedKey] = isScreenValue
|
|
104
|
-
? formattedValue
|
|
105
|
-
: toKebabCase(formattedValue).replace(doubleHyphensRegex, '-')
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
traverse(themeCpy)
|
|
111
|
-
|
|
112
|
-
return { ...themeCpy, colors: { ...themeCpy.colors, ...defaultColors } }
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Creates a Tailwind config file that links the [theme options](https://tailwindcss.com/docs/theme#configuration-reference) provided by Tailwind with the CSS custom property values generated using the "createCSSTokensFile" function
|
|
117
|
-
*
|
|
118
|
-
* @param {string} path - The file path where the Tailwind config file will be created.
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
*
|
|
122
|
-
* createTailwindThemeConfigFile('./tailwind.theme.js') // will generate a "tailwind.theme.js" in the relative location from which it was called
|
|
123
|
-
*/
|
|
124
|
-
export function createTailwindThemeConfigFile(path) {
|
|
125
|
-
try {
|
|
126
|
-
writeFileSync(
|
|
127
|
-
join(process.cwd(), path),
|
|
128
|
-
`module.exports = ${JSON.stringify(toTailwindConfig(defaultTheme))}`,
|
|
129
|
-
{
|
|
130
|
-
flag: 'w',
|
|
131
|
-
}
|
|
132
|
-
)
|
|
133
|
-
} catch (error) {
|
|
134
|
-
console.error('Failed to create the Tailwind theme config file', error)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
function toKebabCase(v) {
|
|
2
|
-
return v.replace(/[A-Z]+(?=[a-z0-9])|\d+/g, match => '-' + match.toLowerCase())
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
function isAlphanumericWithLeadingLetter(v) {
|
|
6
|
-
return /^[a-zA-Z](?=.*\d)[a-zA-Z\d]*$/.test(v)
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function isHex(value) {
|
|
10
|
-
if (typeof value === 'number') {
|
|
11
|
-
return false
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const regexp = /^#[0-9a-fA-F]+$/
|
|
15
|
-
|
|
16
|
-
return regexp.test(value)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function isStringOrNumber(value) {
|
|
20
|
-
return typeof value === 'string' || typeof value === 'number'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function isObject(x) {
|
|
24
|
-
return !!x && x.constructor === Object
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function isCamelCase(value) {
|
|
28
|
-
return /[A-Z]/.test(value.slice(1))
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function hasNumber(value) {
|
|
32
|
-
return /\d/.test(value)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function getRemEquivalentValue(remValue, htmlFontSize) {
|
|
36
|
-
const defaultBrowserBase = 16
|
|
37
|
-
const pxValue = parseFloat(remValue) * defaultBrowserBase
|
|
38
|
-
|
|
39
|
-
return `${pxValue / htmlFontSize}rem`
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const doubleHyphensRegex = /(?<!var\()--+/g
|
|
43
|
-
|
|
44
|
-
export {
|
|
45
|
-
toKebabCase,
|
|
46
|
-
isHex,
|
|
47
|
-
isStringOrNumber,
|
|
48
|
-
isObject,
|
|
49
|
-
isCamelCase,
|
|
50
|
-
isAlphanumericWithLeadingLetter,
|
|
51
|
-
hasNumber,
|
|
52
|
-
getRemEquivalentValue,
|
|
53
|
-
doubleHyphensRegex,
|
|
54
|
-
}
|