@spark-ui/cli-utils 2.2.1 → 2.2.2

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 CHANGED
@@ -3,6 +3,10 @@
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.2.2](https://github.com/adevinta/spark/compare/@spark-ui/cli-utils@2.2.1...@spark-ui/cli-utils@2.2.2) (2023-02-27)
7
+
8
+ **Note:** Version bump only for package @spark-ui/cli-utils
9
+
6
10
  ## [2.2.1](https://github.com/adevinta/spark/compare/@spark-ui/cli-utils@2.2.0...@spark-ui/cli-utils@2.2.1) (2023-02-24)
7
11
 
8
12
  **Note:** Version bump only for package @spark-ui/cli-utils
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spark-ui/cli-utils",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
4
4
  "description": "Spark CLI utils",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -29,5 +29,5 @@
29
29
  "url": "git@github.com:adevinta/spark.git",
30
30
  "directory": "packages/utils/cli"
31
31
  },
32
- "gitHead": "ce879d963dfb960b7ab442cdf4fbba587176c846"
32
+ "gitHead": "f60c8e55186499585ce7dd3b76318ad8245bfd41"
33
33
  }
@@ -3,18 +3,15 @@ import { join } from 'node:path'
3
3
 
4
4
  import hexRgb from 'hex-rgb'
5
5
 
6
- import { isHex, isStringOrNumber, toKebabCase } from '../../utils.js'
6
+ import { doubleHyphensRegex, isHex, isObject, isStringOrNumber, toKebabCase } from './utils.js'
7
7
 
8
- function flattenTheme(theme, className) {
8
+ function toCSSVars(_theme, className) {
9
9
  const flattenedTheme = {}
10
10
 
11
- function flatten(obj, path) {
12
- Object.entries(obj).forEach(([key, value]) => {
13
- if (value !== null && typeof value === 'object') {
14
- const formattedPath = path ? `--${path}-${key}` : `--${key}`
15
- flatten(value, toKebabCase(formattedPath.replace(/-{3,}/, '--')))
16
-
17
- return
11
+ function flatten(theme, paths = []) {
12
+ Object.entries(theme).forEach(([key, value]) => {
13
+ if (isObject(value)) {
14
+ return flatten(value, paths.concat(key))
18
15
  }
19
16
 
20
17
  if (isStringOrNumber(value)) {
@@ -28,12 +25,14 @@ function flattenTheme(theme, className) {
28
25
  return value
29
26
  }
30
27
 
31
- flattenedTheme[`${path}-${toKebabCase(key)}`] = getFormattedValue()
28
+ flattenedTheme[
29
+ `--${[...paths, key].map(toKebabCase).join('-').replace(doubleHyphensRegex, '-')}`
30
+ ] = getFormattedValue()
32
31
  }
33
32
  })
34
33
  }
35
34
 
36
- flatten(theme)
35
+ flatten(_theme)
37
36
 
38
37
  return {
39
38
  ...flattenedTheme,
@@ -48,7 +47,7 @@ const toStringifiedTheme = theme =>
48
47
 
49
48
  const getStringifiedThemes = themeRecord =>
50
49
  Object.keys(themeRecord).map(key => {
51
- const { className, ...rest } = flattenTheme(themeRecord[key], key)
50
+ const { className, ...rest } = toCSSVars(themeRecord[key], key)
52
51
 
53
52
  return key === 'default'
54
53
  ? `:root{${toStringifiedTheme(rest)}}`
@@ -3,33 +3,53 @@ import { join } from 'node:path'
3
3
 
4
4
  import { defaultTheme } from '@spark-ui/theme-utils'
5
5
 
6
- import { isHex, isStringOrNumber, toKebabCase, toKebabCaseKeys } from '../../utils.js'
6
+ import { tailwindKeys } from './constants.js'
7
+ import {
8
+ doubleHyphensRegex,
9
+ hasNumber,
10
+ isCamelCase,
11
+ isHex,
12
+ isObject,
13
+ isStringOrNumber,
14
+ toKebabCase,
15
+ } from './utils.js'
7
16
 
8
- function toTailwindConfig(theme) {
9
- const themeCpy = JSON.parse(JSON.stringify(theme))
17
+ function toTailwindConfig(_theme) {
18
+ const themeCpy = JSON.parse(JSON.stringify(_theme))
10
19
 
11
- /* eslint-disable complexity */
12
- function flatten(obj, path) {
13
- Object.entries(obj).forEach(([key, value]) => {
14
- if (value !== null && typeof value === 'object' && !path && key === 'fontSize') {
20
+ const { fontSize, colors, screens } = tailwindKeys
21
+
22
+ function traverse(theme, paths = []) {
23
+ Object.entries(theme).forEach(([key, value]) => {
24
+ // 👀 see: https://tailwindcss.com/docs/font-size#providing-a-default-line-height
25
+ if (isObject(value) && !paths.length && key === fontSize) {
15
26
  Object.keys(value).forEach(k => {
27
+ const prefix = toKebabCase(fontSize)
16
28
  if (isStringOrNumber(value[k])) {
17
- obj[key][k] = `var(--${toKebabCase(key)}-${k})`
29
+ theme[key][k] = `var(--${prefix}-${k})`
18
30
 
19
31
  return
20
32
  }
21
33
 
22
- obj[key][k] = [
23
- `var(--${toKebabCase(key)}-${k}-font-size`,
34
+ const kebabedKey = isCamelCase(k) || hasNumber(k) ? toKebabCase(k) : k
35
+
36
+ if (kebabedKey !== k) {
37
+ const tmp = theme[key][k]
38
+ delete theme[key][k]
39
+ theme[key][kebabedKey] = tmp
40
+ }
41
+
42
+ theme[key][kebabedKey] = [
43
+ `var(--${prefix}-${kebabedKey}-font-size)`,
24
44
  {
25
- ...(value[k].lineHeight && {
26
- lineHeight: `var(--${toKebabCase(key)}-${k}-line-height`,
45
+ ...(value[kebabedKey].lineHeight && {
46
+ lineHeight: `var(--${prefix}-${kebabedKey}-line-height)`,
27
47
  }),
28
- ...(value[k].letterSpacing && {
29
- letterSpacing: `var(--${toKebabCase(key)}-${k}-letter-spacing`,
48
+ ...(value[kebabedKey].letterSpacing && {
49
+ letterSpacing: `var(--${prefix}-${kebabedKey}-letter-spacing)`,
30
50
  }),
31
- ...(value[k].fontWeight && {
32
- fontWeight: `var(--${toKebabCase(key)}-${k}-font-weight`,
51
+ ...(value[kebabedKey].fontWeight && {
52
+ fontWeight: `var(--${prefix}-${kebabedKey}-font-weight)`,
33
53
  }),
34
54
  },
35
55
  ]
@@ -38,31 +58,46 @@ function toTailwindConfig(theme) {
38
58
  return
39
59
  }
40
60
 
41
- if (value !== null && typeof value === 'object') {
42
- const formattedPath = path ? `--${path}-${key}` : `--${key}`
43
- flatten(value, toKebabCase(formattedPath.replace(/-{3,}/, '--')))
61
+ if (isObject(value)) {
62
+ Object.keys(value).forEach(k => {
63
+ if (!isObject(value[k]) && !isCamelCase(k)) {
64
+ return
65
+ }
66
+
67
+ const tmp = value[k]
68
+ delete value[k]
69
+ value[toKebabCase(k)] = tmp
70
+ })
44
71
 
45
- return
72
+ return traverse(value, paths.concat(key))
46
73
  }
47
74
 
48
- /* eslint-disable */
49
75
  if (isStringOrNumber(value)) {
76
+ const rootPath = paths.at(0) ?? ''
77
+ const isScreenValue = rootPath.includes(screens)
78
+ const isColorValue = rootPath.includes(colors)
79
+
50
80
  const formattedValue = (() => {
51
- if (/--colors/.test(path || '') && isHex(value))
52
- return `rgb(var(${path}-${toKebabCase(key)}) / <alpha-value>)`
53
- if (/--screens/.test(path || '')) return value
54
- return `var(${path}-${toKebabCase(key)})`
81
+ if (isColorValue && isHex(value)) {
82
+ return `rgb(var(--${paths.join('-')}-${key}) / <alpha-value>)`
83
+ }
84
+ if (isScreenValue) {
85
+ return String(value).toLowerCase()
86
+ }
87
+
88
+ return `var(--${paths.join('-')}-${key})`
55
89
  })()
56
90
 
57
- obj[key] = formattedValue
58
- /* eslint-enable */
91
+ theme[key] = isScreenValue
92
+ ? formattedValue
93
+ : toKebabCase(formattedValue).replace(doubleHyphensRegex, '-')
59
94
  }
60
95
  })
61
96
  }
62
97
 
63
- flatten(themeCpy)
98
+ traverse(themeCpy)
64
99
 
65
- return toKebabCaseKeys(themeCpy)
100
+ return themeCpy
66
101
  }
67
102
 
68
103
  /**
@@ -0,0 +1,41 @@
1
+ function toKebabCase(v) {
2
+ return v.replace(/[A-Z0-9]/g, e => `-${e.toLocaleLowerCase()}`)
3
+ }
4
+
5
+ function isHex(value) {
6
+ if (typeof value === 'number') {
7
+ return false
8
+ }
9
+
10
+ const regexp = /^#[0-9a-fA-F]+$/
11
+
12
+ return regexp.test(value)
13
+ }
14
+
15
+ function isStringOrNumber(value) {
16
+ return typeof value === 'string' || typeof value === 'number'
17
+ }
18
+
19
+ function isObject(x) {
20
+ return !!x && x.constructor === Object
21
+ }
22
+
23
+ function isCamelCase(value) {
24
+ return /[A-Z]/.test(value.slice(1))
25
+ }
26
+
27
+ function hasNumber(value) {
28
+ return /\d/.test(value)
29
+ }
30
+
31
+ const doubleHyphensRegex = /(?<!var\()--+/g
32
+
33
+ export {
34
+ toKebabCase,
35
+ isHex,
36
+ isStringOrNumber,
37
+ isObject,
38
+ isCamelCase,
39
+ hasNumber,
40
+ doubleHyphensRegex,
41
+ }
package/src/utils.js DELETED
@@ -1,39 +0,0 @@
1
- function toKebabCase(v) {
2
- return v.replace(/[A-Z]/g, e => `-${e.toLocaleLowerCase()}`)
3
- }
4
-
5
- function isHex(value) {
6
- if (typeof value === 'number') {
7
- return false
8
- }
9
-
10
- const regexp = /^#[0-9a-fA-F]+$/
11
-
12
- return regexp.test(value)
13
- }
14
-
15
- function isStringOrNumber(value) {
16
- return typeof value === 'string' || typeof value === 'number'
17
- }
18
-
19
- function toKebabCaseKeys(obj, level = 1) {
20
- const result = {}
21
- for (const [key, value] of Object.entries(obj)) {
22
- const transformedKey =
23
- level > 1 ? key.replace(/([a-z])([A-Z0-9])/g, '$1-$2').toLowerCase() : key
24
-
25
- if (Array.isArray(value)) {
26
- result[transformedKey] = value.map(v =>
27
- typeof v === 'object' ? toKebabCaseKeys(v, level + 1) : v
28
- )
29
- } else if (typeof value === 'object') {
30
- result[transformedKey] = toKebabCaseKeys(value, level + 1)
31
- } else {
32
- result[transformedKey] = value
33
- }
34
- }
35
-
36
- return result
37
- }
38
-
39
- export { toKebabCase, isHex, toKebabCaseKeys, isStringOrNumber }