@startupjs-ui/core 0.1.1 → 0.1.3
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/helpers/colorToRGBA.js +13 -0
- package/helpers/index.js +3 -0
- package/helpers/path.js +3 -0
- package/helpers/u.js +3 -0
- package/hooks/index.js +4 -0
- package/hooks/useColors.js +16 -0
- package/hooks/useCssVariables.js +5 -0
- package/hooks/useMedia.en.mdx +28 -0
- package/hooks/useMedia.js +37 -0
- package/hooks/useMedia.ru.mdx +28 -0
- package/hooks/useMedia.styl +2 -0
- package/hooks/useTransformCssVariables.js +37 -0
- package/index.d.ts +79 -0
- package/index.js +15 -0
- package/package.json +17 -2
- package/styles/colors.styl +74 -0
- package/styles/helpers.styl +82 -0
- package/styles/index.styl +8 -0
- package/styles/palette.styl +14 -0
- package/styles/shadows.styl +34 -0
- package/styles/typography.styl +99 -0
- package/styles/variables.styl +83 -0
- package/theming/Colors.js +109 -0
- package/theming/CssVariables.js +59 -0
- package/theming/Palette.js +20 -0
- package/theming/StyleContext.js +9 -0
- package/theming/TheColor.js +76 -0
- package/theming/ThemeContext.js +5 -0
- package/theming/ThemeProvider.js +3 -0
- package/theming/defaultPalette.js +3 -0
- package/theming/defaultUiVariables.js +9 -0
- package/theming/generateColors.js +12 -0
- package/theming/getCssVariable.js +10 -0
- package/theming/helpers.js +265 -0
- package/theming/palette.json +10 -0
- package/theming/themed.js +66 -0
- package/theming/transformColors.js +15 -0
- package/theming/useCssVariablesMeta.js +44 -0
- package/CHANGELOG.md +0 -9
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
$UI.media = {
|
|
2
|
+
mobile: 480px,
|
|
3
|
+
tablet: 768px,
|
|
4
|
+
desktop: 1024px,
|
|
5
|
+
wide: 1280px
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
$UI.gutters = {
|
|
9
|
+
xs: 0.5u,
|
|
10
|
+
s: 1u,
|
|
11
|
+
m: 2u,
|
|
12
|
+
l: 3u,
|
|
13
|
+
xl: 4u,
|
|
14
|
+
xxl: 5u
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
$UI.defaultFontSize = 'body2'
|
|
18
|
+
|
|
19
|
+
$UI.fontFamilies = {
|
|
20
|
+
web: {
|
|
21
|
+
normal: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue', sans-serif",
|
|
22
|
+
heading: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue', sans-serif"
|
|
23
|
+
},
|
|
24
|
+
android: {
|
|
25
|
+
normal: 'System',
|
|
26
|
+
heading: 'System'
|
|
27
|
+
},
|
|
28
|
+
ios: {
|
|
29
|
+
normal: 'System',
|
|
30
|
+
heading: 'System'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
$UI.fontWeights = {
|
|
35
|
+
normal: 400,
|
|
36
|
+
normalBold: 600,
|
|
37
|
+
heading: 400,
|
|
38
|
+
headingBold: 600
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
$UI.fontSizes = {
|
|
42
|
+
xs: 1.25u, // DEPRECATED
|
|
43
|
+
s: 1.5u, // DEPRECATED
|
|
44
|
+
m: 1.75u, // DEPRECATED
|
|
45
|
+
l: 2u, // DEPRECATED
|
|
46
|
+
xl: 2.5u, // DEPRECATED
|
|
47
|
+
xxl: 3u, // DEPRECATED
|
|
48
|
+
xxxl: 4.5u, // DEPRECATED
|
|
49
|
+
xxxxl: 6u, // DEPRECATED
|
|
50
|
+
xxxxxl: 9u, // DEPRECATED
|
|
51
|
+
h1: 9u,
|
|
52
|
+
h2: 6u,
|
|
53
|
+
h3: 4.5u,
|
|
54
|
+
h4: 3u,
|
|
55
|
+
h5: 2.5u,
|
|
56
|
+
h6: 2u,
|
|
57
|
+
description: 1.75u, // DEPRECATED
|
|
58
|
+
body1: 2u,
|
|
59
|
+
body2: 1.75u,
|
|
60
|
+
caption: 1.5u
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
$UI.lineHeights = {
|
|
64
|
+
xs: 1.75u, // DEPRECATED
|
|
65
|
+
s: 2u, // DEPRECATED
|
|
66
|
+
m: 2.5u, // DEPRECATED
|
|
67
|
+
l: 3u, // DEPRECATED
|
|
68
|
+
xl: 3.5u, // DEPRECATED
|
|
69
|
+
xxl: 4u, // DEPRECATED
|
|
70
|
+
xxxl: 6u, // DEPRECATED
|
|
71
|
+
xxxxl: 8u, // DEPRECATED
|
|
72
|
+
xxxxxl: 12u, // DEPRECATED
|
|
73
|
+
h1: 12u,
|
|
74
|
+
h2: 8u,
|
|
75
|
+
h3: 6u,
|
|
76
|
+
h4: 4u,
|
|
77
|
+
h5: 3.5u,
|
|
78
|
+
h6: 3u,
|
|
79
|
+
description: 2.5u, // DEPRECATED
|
|
80
|
+
body1: 3u,
|
|
81
|
+
body2: 2.5u,
|
|
82
|
+
caption: 2u
|
|
83
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export const BaseColors = {
|
|
2
|
+
main: 'main',
|
|
3
|
+
'bg-main': 'bg-main',
|
|
4
|
+
'text-main': 'text-main',
|
|
5
|
+
'border-main': 'border-main',
|
|
6
|
+
primary: 'primary',
|
|
7
|
+
secondary: 'secondary',
|
|
8
|
+
error: 'error',
|
|
9
|
+
success: 'success',
|
|
10
|
+
warning: 'warning',
|
|
11
|
+
info: 'info',
|
|
12
|
+
attention: 'attention'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const BgColors = {
|
|
16
|
+
'bg-main-subtle': 'bg-main-subtle',
|
|
17
|
+
'bg-main-subtle-alt': 'bg-main-subtle-alt',
|
|
18
|
+
'bg-main-strong': 'bg-main-strong',
|
|
19
|
+
'bg-primary': 'bg-primary',
|
|
20
|
+
'bg-secondary': 'bg-secondary',
|
|
21
|
+
'bg-error': 'bg-error',
|
|
22
|
+
'bg-success': 'bg-success',
|
|
23
|
+
'bg-warning': 'bg-warning',
|
|
24
|
+
'bg-info': 'bg-info',
|
|
25
|
+
'bg-attention': 'bg-attention',
|
|
26
|
+
'bg-primary-strong': 'bg-primary-strong',
|
|
27
|
+
'bg-primary-subtle': 'bg-primary-subtle',
|
|
28
|
+
'bg-primary-transparent': 'bg-primary-transparent',
|
|
29
|
+
'bg-secondary-subtle': 'bg-secondary-subtle',
|
|
30
|
+
'bg-error-transparent': 'bg-error-transparent',
|
|
31
|
+
'bg-success-transparent': 'bg-success-transparent',
|
|
32
|
+
'bg-warning-transparent': 'bg-warning-transparent'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const TextColors = {
|
|
36
|
+
'text-description': 'text-description',
|
|
37
|
+
'text-placeholder': 'text-placeholder',
|
|
38
|
+
'text-subtle': 'text-subtle',
|
|
39
|
+
'text-primary': 'text-primary',
|
|
40
|
+
'text-secondary': 'text-secondary',
|
|
41
|
+
'text-error': 'text-error',
|
|
42
|
+
'text-success': 'text-success',
|
|
43
|
+
'text-warning': 'text-warning',
|
|
44
|
+
'text-info': 'text-info',
|
|
45
|
+
'text-attention': 'text-attention',
|
|
46
|
+
'text-success-strong': 'text-success-strong',
|
|
47
|
+
'text-info-strong': 'text-info-strong'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const TextOnColors = {
|
|
51
|
+
'text-on-color': 'text-on-color',
|
|
52
|
+
'text-on-primary': 'text-on-primary',
|
|
53
|
+
'text-on-secondary': 'text-on-secondary',
|
|
54
|
+
'text-on-error': 'text-on-error',
|
|
55
|
+
'text-on-success': 'text-on-success',
|
|
56
|
+
'text-on-warning': 'text-on-warning',
|
|
57
|
+
'text-on-info': 'text-on-info',
|
|
58
|
+
'text-on-attention': 'text-on-attention'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const BorderColors = {
|
|
62
|
+
'border-main-strong': 'border-main-strong',
|
|
63
|
+
'border-main-strong-alt': 'border-main-strong-alt',
|
|
64
|
+
'border-main-subtle': 'border-main-subtle',
|
|
65
|
+
'border-primary': 'border-primary',
|
|
66
|
+
'border-secondary': 'border-secondary',
|
|
67
|
+
'border-error': 'border-error',
|
|
68
|
+
'border-success': 'border-success',
|
|
69
|
+
'border-warning': 'border-warning',
|
|
70
|
+
'border-info': 'border-info',
|
|
71
|
+
'border-attention': 'border-attention'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const ShadowColors = {
|
|
75
|
+
'shadow-main': 'shadow-main',
|
|
76
|
+
'shadow-main-strong': 'shadow-main-strong',
|
|
77
|
+
'shadow-main-subtle': 'shadow-main-subtle'
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const ComponentColors = {
|
|
81
|
+
'--AutoSuggest-itemBg': '--AutoSuggest-itemBg',
|
|
82
|
+
'--Carousel-arrowWrapperBg': '--Carousel-arrowWrapperBg',
|
|
83
|
+
'--Checkbox-switchBg': '--Checkbox-switchBg',
|
|
84
|
+
'--Checkbox-switchBulletBg': '--Checkbox-switchBulletBg',
|
|
85
|
+
'--Checkbox-switchBulletBg-checked': '--Checkbox-switchBulletBg-checked',
|
|
86
|
+
'--Div-hoverBg': '--Div-hoverBg',
|
|
87
|
+
'--Div-activeBg': '--Div-activeBg',
|
|
88
|
+
'--Div-tooltipBg': '--Div-tooltipBg',
|
|
89
|
+
'--Div-tooltipText': '--Div-tooltipText',
|
|
90
|
+
'--Modal-overlayBg': '--Modal-overlayBg',
|
|
91
|
+
'--InputWrapper-label-color': '--InputWrapper-label-color',
|
|
92
|
+
'--Range-labelBg': '--Range-labelBg',
|
|
93
|
+
'--Range-labelText': '--Range-labelText',
|
|
94
|
+
'--TextInput-text-color': '--TextInput-text-color'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const Colors = {
|
|
98
|
+
...BaseColors,
|
|
99
|
+
...BgColors,
|
|
100
|
+
...TextColors,
|
|
101
|
+
...TextOnColors,
|
|
102
|
+
...BorderColors,
|
|
103
|
+
...ShadowColors,
|
|
104
|
+
...ComponentColors
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default Colors
|
|
108
|
+
|
|
109
|
+
export const ColorValues = Object.values(Colors)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { $, variables as singletonVariables } from 'startupjs'
|
|
3
|
+
// TODO: Move CssVariables to basic startupjs and also move the singleton variables file to some generic lib
|
|
4
|
+
// so that it's not tightly coupled with our custom stylesheets implementation
|
|
5
|
+
import transformColors from './transformColors'
|
|
6
|
+
|
|
7
|
+
export default function CssVariables ({ meta, clear = true, children }) {
|
|
8
|
+
function setColorScheme (value = '') {
|
|
9
|
+
document.documentElement.style.colorScheme = value
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
useMemo(() => {
|
|
13
|
+
const isWeb = $.system.platform.get() === 'web'
|
|
14
|
+
const isDark = isWeb ? document.documentElement.style.colorScheme === 'dark' : false
|
|
15
|
+
|
|
16
|
+
if (!meta) {
|
|
17
|
+
// default color scheme is light so we reset it to default if there are no overrides
|
|
18
|
+
if (isDark) setColorScheme()
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const variables = transformColors(meta)
|
|
23
|
+
|
|
24
|
+
// set new variables
|
|
25
|
+
for (const variableName in variables) {
|
|
26
|
+
if (variables[variableName] !== singletonVariables[variableName]) {
|
|
27
|
+
singletonVariables[variableName] = variables[variableName]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// remove old variables
|
|
32
|
+
for (const variableName in singletonVariables) {
|
|
33
|
+
if (variables[variableName] == null) {
|
|
34
|
+
delete singletonVariables[variableName]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isWeb) {
|
|
39
|
+
if (singletonVariables['--color-bg-main']?.isDark?.()) {
|
|
40
|
+
if (!isDark) setColorScheme('dark')
|
|
41
|
+
} else {
|
|
42
|
+
setColorScheme()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// clear dynamic theme when destroyed
|
|
47
|
+
if (clear) {
|
|
48
|
+
return () => {
|
|
49
|
+
if (isWeb) setColorScheme()
|
|
50
|
+
|
|
51
|
+
for (const variableName in singletonVariables) {
|
|
52
|
+
delete singletonVariables[variableName]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}, [JSON.stringify(meta)])
|
|
57
|
+
|
|
58
|
+
return children || null
|
|
59
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TheColor } from './TheColor'
|
|
2
|
+
import { getPaletteMeta, prepareColorsObject } from './helpers'
|
|
3
|
+
import defaultPalette from './palette.json'
|
|
4
|
+
|
|
5
|
+
export default class Palette {
|
|
6
|
+
constructor (palette = defaultPalette) {
|
|
7
|
+
this.colors = palette
|
|
8
|
+
|
|
9
|
+
Object.assign(this, getPaletteMeta(palette))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
generateColors = (overrides, componentOverrides) => {
|
|
13
|
+
const { low, high, middle } = this
|
|
14
|
+
return prepareColorsObject(this.colors, this.Color, { overrides, componentOverrides, low, middle, high })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
Color = (name, level, { alpha } = {}) => {
|
|
18
|
+
return new TheColor(name, level, this.colors, { alpha })
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getPaletteMeta, rgba, getPaletteLength } from './helpers'
|
|
2
|
+
|
|
3
|
+
const BLACK = '#000000'
|
|
4
|
+
const WHITE = '#ffffff'
|
|
5
|
+
export class TheColor {
|
|
6
|
+
constructor (name, level, palette, { alpha } = {}) {
|
|
7
|
+
const isBlackOrWhite = this.isBlack(name, level, palette) || this.isWhite(name, level)
|
|
8
|
+
|
|
9
|
+
if (!isBlackOrWhite && !palette?.[name]?.[level]) {
|
|
10
|
+
throw Error(`Color ${name} level ${level} not found in palette ${JSON.stringify(palette, null, 2)}`)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const meta = {
|
|
14
|
+
name,
|
|
15
|
+
level,
|
|
16
|
+
palette,
|
|
17
|
+
...getPaletteMeta(palette)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (alpha != null) meta.alpha = alpha
|
|
21
|
+
|
|
22
|
+
Object.assign(this, meta)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
clone (name, level, palette, { alpha } = {}) {
|
|
26
|
+
return new TheColor(
|
|
27
|
+
name ?? this.name,
|
|
28
|
+
level ?? this.level,
|
|
29
|
+
palette ?? this.palette,
|
|
30
|
+
{ alpha: alpha ?? this.alpha }
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
toString () {
|
|
35
|
+
let stringColor
|
|
36
|
+
|
|
37
|
+
if (this.isBlack()) {
|
|
38
|
+
stringColor = BLACK
|
|
39
|
+
} else if (this.isWhite()) {
|
|
40
|
+
stringColor = WHITE
|
|
41
|
+
} else {
|
|
42
|
+
stringColor = this.palette[this.name][this.level]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return this.alpha != null ? rgba(stringColor, this.alpha) : stringColor
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
isEqual (other) {
|
|
49
|
+
return this.name === other.name && this.level === other.level && this.alpha === other.alpha
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
isBlack (name = this.name, level = this.level, palette = this.palette) {
|
|
53
|
+
return name === 'main' && level === getPaletteLength(palette)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
isWhite (name = this.name, level = this.level) {
|
|
57
|
+
return name === 'main' && level === -1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
setAlpha (alpha) {
|
|
61
|
+
const { name, level, palette, ...rest } = this
|
|
62
|
+
return this.clone(name, level, palette, { ...rest, alpha })
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
isDark () { return this.level > this.middle }
|
|
66
|
+
isLight () { return !this.isDark() }
|
|
67
|
+
highContrast () { return this.clone(this.name, this.isLight() ? this.high : this.low) }
|
|
68
|
+
stronger (offset = 1) { return this.subtler(-offset) }
|
|
69
|
+
|
|
70
|
+
subtler (offset = 1) {
|
|
71
|
+
if (this.isDark()) offset = -offset
|
|
72
|
+
let level = this.level + offset
|
|
73
|
+
level = Math.min(this.high + 1, Math.max(this.low - 1, level))
|
|
74
|
+
return this.clone(this.name, level)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// TODO: Figure out if we would want to transition default UI colors to be dynamic
|
|
2
|
+
import palette from './defaultPalette'
|
|
3
|
+
import transformColors from './transformColors'
|
|
4
|
+
|
|
5
|
+
export default { ...getColors() }
|
|
6
|
+
|
|
7
|
+
function getColors () {
|
|
8
|
+
return transformColors(palette.generateColors())
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { prepareColorsObject, getPaletteMeta } from './helpers'
|
|
2
|
+
import { TheColor } from './TheColor'
|
|
3
|
+
|
|
4
|
+
// generate meaningful colors from palette
|
|
5
|
+
export default function generateColors (palette, overrides = {}) {
|
|
6
|
+
if (!palette) throw Error('palette is required')
|
|
7
|
+
|
|
8
|
+
const Color = (name, level, { alpha } = {}) => new TheColor(name, level, palette, { alpha })
|
|
9
|
+
const { low, middle, high } = getPaletteMeta(palette)
|
|
10
|
+
|
|
11
|
+
return prepareColorsObject(palette, Color, { overrides, low, middle, high })
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { variables as singletonVariables, defaultVariables } from 'startupjs'
|
|
2
|
+
|
|
3
|
+
export default function getCssVariable (cssVarName, { convertToString = true } = {}) {
|
|
4
|
+
if (!/^--/.test(cssVarName)) throw Error('[getCssVariable]: Incorrect name format - must begin with --')
|
|
5
|
+
|
|
6
|
+
const colorInstance = singletonVariables[cssVarName] || defaultVariables[cssVarName]
|
|
7
|
+
if (!colorInstance) return
|
|
8
|
+
|
|
9
|
+
return convertToString ? colorInstance.toString() : colorInstance
|
|
10
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// refs:
|
|
2
|
+
// https://accessiblepalette.com/?lightness=98,93.3,88.6,79.9,71.2,60.5,49.8,38.4,27,15.6&e94c49=1,0&F1903C=1,-10&f3e203=1,-15&89BF1D=0,0&64c273=0,15&007DCC=0,0&808080=0,0&EAE8DE=0,0&768092=0,0
|
|
3
|
+
// https://www.ibm.com/design/language/color/
|
|
4
|
+
import Colors from './Colors'
|
|
5
|
+
import { TheColor } from './TheColor'
|
|
6
|
+
import getCssVariable from './getCssVariable'
|
|
7
|
+
|
|
8
|
+
export function getPaletteMeta (palette) {
|
|
9
|
+
const res = {}
|
|
10
|
+
const high = getPaletteLength(palette) - 1
|
|
11
|
+
res.low = 0 // lightest colorful color
|
|
12
|
+
res.high = high // darkest colorful color
|
|
13
|
+
res.middle = Math.floor(high / 2) // last light color
|
|
14
|
+
return res
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function rgbToHex (r, g, b) {
|
|
18
|
+
// Ensure that the input values are within the valid range
|
|
19
|
+
r = Math.max(0, Math.min(255, r))
|
|
20
|
+
g = Math.max(0, Math.min(255, g))
|
|
21
|
+
b = Math.max(0, Math.min(255, b))
|
|
22
|
+
|
|
23
|
+
// Convert the RGB values to hexadecimal
|
|
24
|
+
const hexR = r.toString(16).padStart(2, '0')
|
|
25
|
+
const hexG = g.toString(16).padStart(2, '0')
|
|
26
|
+
const hexB = b.toString(16).padStart(2, '0')
|
|
27
|
+
|
|
28
|
+
return `#${hexR}${hexG}${hexB}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Extract RGB values from RGB or RGBA string
|
|
32
|
+
export function extractRGB (str) {
|
|
33
|
+
const match = str.match(/(\d+\.?\d*|\.\d+)/g) // improved regex to match decimals
|
|
34
|
+
if (!match) return []
|
|
35
|
+
return match.map(Number)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function rgba (color, alpha) {
|
|
39
|
+
if (typeof alpha !== 'number' || alpha < 0 || alpha > 1) {
|
|
40
|
+
throw new Error('Invalid alpha value. It should be between 0 and 1.')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Convert hex to RGB
|
|
44
|
+
const hexToRgb = (hex) => {
|
|
45
|
+
if (hex.startsWith('#')) hex = hex.slice(1)
|
|
46
|
+
const bigint = parseInt(hex, 16)
|
|
47
|
+
const r = (bigint >> 16) & 255
|
|
48
|
+
const g = (bigint >> 8) & 255
|
|
49
|
+
const b = bigint & 255
|
|
50
|
+
return [r, g, b]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (color.startsWith('#')) {
|
|
54
|
+
const [r, g, b] = hexToRgb(color)
|
|
55
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`
|
|
56
|
+
} else if (color.startsWith('rgb')) {
|
|
57
|
+
const values = extractRGB(color)
|
|
58
|
+
if (values.length === 3 || values.length === 4) {
|
|
59
|
+
return `rgba(${values[0]}, ${values[1]}, ${values[2]}, ${alpha})`
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
throw new Error('Invalid color format. Supported formats are hex, rgb, and rgba.')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// find color in palette by the color value itself
|
|
67
|
+
// (note that hex/rgb/rgba matters -- it's considered to be different colors)
|
|
68
|
+
export function findColorInPalette (color, palette) {
|
|
69
|
+
let alpha
|
|
70
|
+
|
|
71
|
+
if (color.includes('rgb')) {
|
|
72
|
+
const rgbValues = extractRGB(color)
|
|
73
|
+
const [r, g, b, a] = rgbValues
|
|
74
|
+
if (a != null) alpha = a
|
|
75
|
+
color = rgbToHex(r, g, b)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let foundName
|
|
79
|
+
let foundLevel
|
|
80
|
+
for (const name in palette) {
|
|
81
|
+
const level = palette[name].indexOf(color)
|
|
82
|
+
if (level !== -1) {
|
|
83
|
+
foundName = name
|
|
84
|
+
foundLevel = level
|
|
85
|
+
break
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return [foundName, foundLevel, alpha]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function getPaletteLength (palette) {
|
|
93
|
+
return Object.values(palette)[0].length
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function transformOverrides (overrides, palette, Color) {
|
|
97
|
+
if (!overrides) return
|
|
98
|
+
|
|
99
|
+
const res = {}
|
|
100
|
+
|
|
101
|
+
for (const colorName in overrides) {
|
|
102
|
+
const color = overrides[colorName]
|
|
103
|
+
// Set color as it is if it's the instance
|
|
104
|
+
if (color instanceof TheColor) {
|
|
105
|
+
res[colorName] = color
|
|
106
|
+
// Get color value from existing (needed for static overrides).
|
|
107
|
+
// First check already overriden colors in local 'res' variable to allow reuse of overriden variables immediately
|
|
108
|
+
// e.g.,
|
|
109
|
+
// :root
|
|
110
|
+
// --palette-primary-4: #000099
|
|
111
|
+
// --color-primary: var(--palette-primary-4)
|
|
112
|
+
// --color-secondary: var(--palette-error-4)
|
|
113
|
+
// --color-bg-main: var(--color-primary-bg)
|
|
114
|
+
} else if (/^var\(--/.test(color)) {
|
|
115
|
+
const colorVar = color.replace(/var\(\s*(--[A-Za-z0-9_-]+)\s*\)/, (match, varName) => {
|
|
116
|
+
return varName
|
|
117
|
+
})
|
|
118
|
+
const colorValue = res[colorVar] || getCssVariable(colorVar, { convertToString: false })
|
|
119
|
+
if (!colorValue) throw Error(`'${colorName}' does not exist.`)
|
|
120
|
+
res[colorName] = colorValue.clone()
|
|
121
|
+
// Find color in a palette by hex or rgb(a) string
|
|
122
|
+
} else {
|
|
123
|
+
const [paletteColorName, level, alpha] = findColorInPalette(color, palette)
|
|
124
|
+
if (!paletteColorName) throw Error(`'${colorName}' does not exist in palette. You can only pass a color from palette.`)
|
|
125
|
+
res[colorName] = Color(paletteColorName, level, { alpha })
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return res
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* eslint-disable dot-notation, no-multi-spaces */
|
|
133
|
+
export function prepareColorsObject (
|
|
134
|
+
palette,
|
|
135
|
+
Color,
|
|
136
|
+
{
|
|
137
|
+
overrides = {},
|
|
138
|
+
componentOverrides,
|
|
139
|
+
high,
|
|
140
|
+
low,
|
|
141
|
+
middle
|
|
142
|
+
}
|
|
143
|
+
) {
|
|
144
|
+
const C = {}
|
|
145
|
+
const transformedOverrides = transformOverrides(overrides, palette, Color)
|
|
146
|
+
if (transformedOverrides) Object.assign(C, transformedOverrides)
|
|
147
|
+
|
|
148
|
+
// base colors
|
|
149
|
+
// we don't want shadow to change to a light color in a dark theme, that's why we are creating it as
|
|
150
|
+
// a separate color
|
|
151
|
+
C[Colors['shadow-main']] ??= Color('main', high + 1, { alpha: 0.2 })
|
|
152
|
+
C[Colors.main] ??= Color('main', low)
|
|
153
|
+
C[Colors.primary] ??= Color('primary', middle)
|
|
154
|
+
C[Colors.secondary] ??= Color('secondary', high - 2)
|
|
155
|
+
C[Colors.error] ??= Color('error', middle)
|
|
156
|
+
C[Colors.success] ??= Color('success', middle)
|
|
157
|
+
C[Colors.warning] ??= Color('warning', middle - 2)
|
|
158
|
+
C[Colors.info] ??= Color('info', middle - 1)
|
|
159
|
+
C[Colors.attention] ??= Color('attention', middle)
|
|
160
|
+
|
|
161
|
+
// all other colors are generated from the base colors
|
|
162
|
+
|
|
163
|
+
// shadow colors
|
|
164
|
+
C[Colors['shadow-main-strong']] ??= C[Colors['shadow-main']].setAlpha(0.15)
|
|
165
|
+
C[Colors['shadow-main-subtle']] ??= C[Colors['shadow-main']].setAlpha(0.25)
|
|
166
|
+
|
|
167
|
+
// main bg colors
|
|
168
|
+
C[Colors['bg-main']] ??= C[Colors.main]
|
|
169
|
+
C[Colors['bg-primary']] ??= C[Colors.primary]
|
|
170
|
+
C[Colors['bg-secondary']] ??= C[Colors.secondary]
|
|
171
|
+
C[Colors['bg-error']] ??= C[Colors.error]
|
|
172
|
+
C[Colors['bg-success']] ??= C[Colors.success]
|
|
173
|
+
C[Colors['bg-warning']] ??= C[Colors.warning]
|
|
174
|
+
C[Colors['bg-info']] ??= C[Colors.info]
|
|
175
|
+
C[Colors['bg-attention']] ??= C[Colors.attention]
|
|
176
|
+
|
|
177
|
+
// extra bg colors
|
|
178
|
+
C[Colors['bg-main-subtle']] ??= C[Colors['bg-main']].subtler(1)
|
|
179
|
+
C[Colors['bg-main-subtle-alt']] ??= C[Colors['bg-main']].subtler(2)
|
|
180
|
+
C[Colors['bg-main-strong']] ??= C[Colors['bg-main']].stronger(1)
|
|
181
|
+
C[Colors['bg-primary-strong']] ??= C[Colors.primary].stronger(4)
|
|
182
|
+
C[Colors['bg-primary-subtle']] ??= C[Colors.primary].subtler(3)
|
|
183
|
+
C[Colors['bg-primary-transparent']] ??= C[Colors.primary].setAlpha(0.05)
|
|
184
|
+
C[Colors['bg-secondary-subtle']] ??= C[Colors.secondary].highContrast()
|
|
185
|
+
C[Colors['bg-error-transparent']] ??= C[Colors.error].setAlpha(0.05)
|
|
186
|
+
C[Colors['bg-success-transparent']] ??= C[Colors.success].setAlpha(0.05)
|
|
187
|
+
C[Colors['bg-warning-transparent']] ??= C[Colors.warning].setAlpha(0.05)
|
|
188
|
+
|
|
189
|
+
// text
|
|
190
|
+
C[Colors['text-main']] ??= C[Colors.main].subtler(7)
|
|
191
|
+
C[Colors['text-description']] ??= C[Colors['text-main']].subtler(2)
|
|
192
|
+
C[Colors['text-placeholder']] ??= C[Colors['text-main']].subtler(4)
|
|
193
|
+
C[Colors['text-subtle']] ??= C[Colors['text-main']].subtler(4)
|
|
194
|
+
C[Colors['text-primary']] ??= C[Colors.primary]
|
|
195
|
+
C[Colors['text-secondary']] ??= C[Colors.secondary]
|
|
196
|
+
C[Colors['text-error']] ??= C[Colors.error]
|
|
197
|
+
C[Colors['text-success']] ??= C[Colors.success]
|
|
198
|
+
C[Colors['text-warning']] ??= C[Colors.warning]
|
|
199
|
+
C[Colors['text-info']] ??= C[Colors.info]
|
|
200
|
+
C[Colors['text-attention']] ??= C[Colors.attention]
|
|
201
|
+
|
|
202
|
+
// extra text colors
|
|
203
|
+
C[Colors['text-success-strong']] ??= C[Colors.success].stronger(2)
|
|
204
|
+
C[Colors['text-info-strong']] ??= C[Colors.info].stronger(2)
|
|
205
|
+
|
|
206
|
+
// text on different backgrounds
|
|
207
|
+
C[Colors['text-on-color']] ??= C[Colors.main]
|
|
208
|
+
C[Colors['text-on-primary']] ??= C[Colors.primary].stronger(4)
|
|
209
|
+
C[Colors['text-on-secondary']] ??= C[Colors.secondary].highContrast()
|
|
210
|
+
C[Colors['text-on-error']] ??= C[Colors.error].stronger(4)
|
|
211
|
+
C[Colors['text-on-success']] ??= C[Colors.success].stronger(4)
|
|
212
|
+
C[Colors['text-on-warning']] ??= C[Colors['text-on-color']]
|
|
213
|
+
C[Colors['text-on-info']] ??= C[Colors.info].stronger(3)
|
|
214
|
+
C[Colors['text-on-attention']] ??= C[Colors.attention].stronger(4)
|
|
215
|
+
|
|
216
|
+
// border
|
|
217
|
+
C[Colors['border-main']] ??= C[Colors.main].subtler(2)
|
|
218
|
+
C[Colors['border-main-strong']] ??= C[Colors['border-main']].stronger(3)
|
|
219
|
+
C[Colors['border-primary']] ??= C[Colors.primary]
|
|
220
|
+
C[Colors['border-secondary']] ??= C[Colors.secondary]
|
|
221
|
+
C[Colors['border-error']] ??= C[Colors.error]
|
|
222
|
+
C[Colors['border-success']] ??= C[Colors.success]
|
|
223
|
+
C[Colors['border-warning']] ??= C[Colors.warning]
|
|
224
|
+
C[Colors['border-info']] ??= C[Colors.info]
|
|
225
|
+
C[Colors['border-attention']] ??= C[Colors.attention]
|
|
226
|
+
|
|
227
|
+
// extra border colors
|
|
228
|
+
C[Colors['border-main-subtle']] ??= C[Colors['border-main']].subtler(1)
|
|
229
|
+
C[Colors['border-main-strong-alt']] ??= C[Colors['border-main']].stronger(1)
|
|
230
|
+
|
|
231
|
+
// generate component colors
|
|
232
|
+
const CC = {}
|
|
233
|
+
|
|
234
|
+
if (componentOverrides) {
|
|
235
|
+
const transformedOverrides = transformOverrides(componentOverrides, palette, Color)
|
|
236
|
+
if (transformedOverrides) Object.assign(CC, transformedOverrides)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
CC[Colors['--AutoSuggest-itemBg']] ??= C[Colors['bg-main']].highContrast().setAlpha(0.05)
|
|
240
|
+
CC[Colors['--Carousel-arrowWrapperBg']] ??= Color('main', high, { alpha: 0.1 })
|
|
241
|
+
CC[Colors['--Checkbox-switchBg']] ??= Color('main', middle)
|
|
242
|
+
CC[Colors['--Checkbox-switchBulletBg']] ??= Color('main', low)
|
|
243
|
+
CC[Colors['--Checkbox-switchBulletBg-checked']] ??= C[Colors['text-on-primary']]
|
|
244
|
+
CC[Colors['--Div-hoverBg']] ??= C[Colors['bg-main']].highContrast().setAlpha(0.05)
|
|
245
|
+
CC[Colors['--Div-activeBg']] ??= C[Colors['bg-main']].highContrast().setAlpha(0.2)
|
|
246
|
+
CC[Colors['--Div-tooltipBg']] ??= C[Colors['bg-main']].subtler(7)
|
|
247
|
+
CC[Colors['--Div-tooltipText']] ??= C[Colors['text-main']].subtler(7)
|
|
248
|
+
CC[Colors['--Modal-overlayBg']] ??= Color('main', high - 2, { alpha: 0.25 })
|
|
249
|
+
CC[Colors['--InputWrapper-label-color']] ??= C[Colors['text-secondary']]
|
|
250
|
+
CC[Colors['--Range-labelBg']] ??= C[Colors['bg-main']].subtler(7)
|
|
251
|
+
CC[Colors['--Range-labelText']] ??= C[Colors['text-main']].subtler(7)
|
|
252
|
+
CC[Colors['--TextInput-text-color']] ??= C[Colors['text-secondary']]
|
|
253
|
+
|
|
254
|
+
// add palette colors
|
|
255
|
+
const P = {}
|
|
256
|
+
for (const colorName in palette) {
|
|
257
|
+
const colors = palette[colorName]
|
|
258
|
+
for (let i = 0; i < colors.length; i++) {
|
|
259
|
+
P[`${colorName}-${i}`] = Color(colorName, i)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return { colors: C, palette: P, componentColors: CC }
|
|
264
|
+
}
|
|
265
|
+
/* eslint-enable dot-notation, no-multi-spaces */
|