Skip to content

Commit

Permalink
Feat/va config colors (#3388)
Browse files Browse the repository at this point in the history
* feat(va-config): colors prop

* feat(va-config): i18n config

* chore(docs): remove unused code

Co-authored-by: Vitaly <[email protected]>

---------

Co-authored-by: Vitaly <[email protected]>
  • Loading branch information
m0ksem and RVitaly1978 committed May 23, 2023
1 parent f5d3d6b commit 06db00e
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 23 deletions.
14 changes: 8 additions & 6 deletions packages/docs/layouts/landing.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<template>
<NuxtPage />
<VaConfig :colors="{ currentPresetName: 'landing' }">
<div class="landing">
<NuxtPage />
</div>
</VaConfig>
</template>

<script lang="ts" setup>
import { useColors } from 'vuestic-ui'
const { applyPreset } = useColors()
applyPreset('landing')
useHead({
title: 'Vuestic UI — Vue 3 UI framework',
Expand All @@ -17,11 +18,12 @@ useHead({
})
</script>

<style lang="scss">
<style lang="scss" scoped>
// Need to import tailwind in layout, because otherwise Vuestic component's css will has a higher priority
// @import '~/assets/css/tailwind.css';
body {
.landing {
background: var(--va-background-secondary);
color: var(--va-on-background-secondary)
}
</style>
22 changes: 22 additions & 0 deletions packages/ui/src/components/va-config/VaConfig.demo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@
</va-button>
</va-config>
</VbCard>

<VbCard title="Colors">
<va-config :colors="{ variables: {
primary: '#f0f',
} }">
<va-button>
Button inside va-config
</va-button>

<div style="background-color: var(--va-primary); color: var(--va-on-primary);">CSS variables</div>
</va-config>
</VbCard>

<VbCard title="i18n">
<va-config :i18n="{
dropzone: 'Завантажити файл',
}">
<va-file-upload dropzone />
</va-config>
</VbCard>
</VbDemo>
</template>

Expand All @@ -82,6 +102,7 @@ import { VaRating } from '../va-rating/'
import { VaChip } from '../va-chip'
import { VaConfig } from './'
import { VaColorInput } from '../va-color-input/'
import { VaFileUpload } from '../va-file-upload'
export default {
components: {
Expand All @@ -90,6 +111,7 @@ export default {
VaConfig,
VaChip,
VaColorInput,
VaFileUpload,
},
data () {
return {
Expand Down
43 changes: 40 additions & 3 deletions packages/ui/src/components/va-config/VaConfig.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,65 @@
<template>
<slot />
<CssVarsRenderer v-bind="$attrs">
<slot />
</CssVarsRenderer>
</template>

<script lang="ts">
import { computed, defineComponent, PropType } from 'vue'
import { computed, defineComponent, PropType, h, Fragment } from 'vue'
import { useComponentPresetProp } from '../../composables/useComponentPreset'
import { ComponentConfig } from '../../services/component-config'
import { provideLocalConfig, useLocalConfig } from '../../composables/useLocalConfig'
import { useGlobalConfigProvider } from './hooks/useGlobalConfigProvider'
import { PartialGlobalConfig } from '../../services/global-config'
import { renderSlotNodes } from '../../utils/headless'
import { useColors } from '../../composables'
const CssVarsRenderer = defineComponent({
name: 'VaCssVarsRenderer',
inheritAttrs: false,
setup (props, { slots, attrs }) {
const { colorsToCSSVariable, colors } = useColors()
const style = computed(() => {
return colorsToCSSVariable(colors)
})
return () => h(Fragment, attrs, renderSlotNodes(slots.default, {}, {
style: style.value,
}) || undefined)
},
})
export default defineComponent({
name: 'VaConfig',
components: { CssVarsRenderer },
props: {
...useComponentPresetProp,
components: { type: Object as PropType<ComponentConfig>, default: () => ({}) },
colors: { type: Object as PropType<PartialGlobalConfig['colors']>, default: () => ({}) },
i18n: { type: Object as PropType<PartialGlobalConfig['i18n']>, default: () => ({}) },
},
inheritAttrs: false,
setup (props) {
const prevChain = useLocalConfig()
// We want it to be an array and not a merged object for optimization purposes
const nextChain = computed(() => [...prevChain.value, props.components])
provideLocalConfig(nextChain)
return {}
const newConfig = useGlobalConfigProvider(computed(() => {
return {
colors: props.colors,
i18n: props.i18n,
}
}))
return {
newConfig,
}
},
})
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { mergeDeep } from './../../../utils/merge-deep'
import cloneDeep from 'lodash/cloneDeep'
import { provide, computed, Ref } from 'vue'
import { useGlobalConfig } from '../../../composables'
import { GLOBAL_CONFIG, GlobalConfig, GlobalConfigUpdater, PartialGlobalConfig } from '../../../services/global-config'
import { makeColorsConfig } from '../../../services/color/config/make-config'

export const useGlobalConfigProvider = (next: Ref<PartialGlobalConfig>) => {
const { globalConfig, mergeGlobalConfig, setGlobalConfig, getGlobalConfig } = useGlobalConfig()

const nextChain = computed(() => {
const gcCopy = cloneDeep(globalConfig.value)
const compiledCopy: GlobalConfig = {
...gcCopy,
colors: makeColorsConfig(gcCopy.colors),
}

return mergeDeep(compiledCopy, next.value) as GlobalConfig
})

provide(GLOBAL_CONFIG, {
mergeGlobalConfig,
setGlobalConfig,
getGlobalConfig,
globalConfig: nextChain,
})

return nextChain
}
4 changes: 3 additions & 1 deletion packages/ui/src/composables/useColors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
type ColorInput,
} from '../services/color/utils'
import { isDev } from '../utils/env'
import kebabCase from 'lodash/kebabCase'

/**
* You can add these props to any component by destructuring them inside props option.
Expand Down Expand Up @@ -111,7 +112,8 @@ export const useColors = () => {
.keys(colors)
.filter((key) => colors[key] !== undefined)
.reduce((acc: Record<string, any>, colorName: string) => {
acc[`--${prefix}-${colorName}`] = getColor(colors[colorName], undefined, true)
acc[`--${prefix}-${kebabCase(colorName)}`] = getColor(colors[colorName], undefined, true)
acc[`--${prefix}-on-${kebabCase(colorName)}`] = getColor(getTextColor(getColor(colors[colorName]!)), undefined, true)
return acc
}, {})
}
Expand Down
9 changes: 2 additions & 7 deletions packages/ui/src/services/color/config/default.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import type { ColorConfig } from '../types'
import { presets } from '../presets'
import { makeColorsConfig } from './make-config'

export const getColorDefaultConfig = (): ColorConfig => ({
get variables () {
return this.presets[this.currentPresetName]
},
set variables (value) {
this.presets[this.currentPresetName] = value
},
export const getColorDefaultConfig = (): ColorConfig => makeColorsConfig({
threshold: 150,
presets: {
light: presets.light,
Expand Down
11 changes: 11 additions & 0 deletions packages/ui/src/services/color/config/make-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ColorConfig } from '../types'

export const makeColorsConfig = (values: Omit<ColorConfig, 'variables'>): ColorConfig => ({
get variables () {
return this.presets[this.currentPresetName]
},
set variables (value) {
this.presets[this.currentPresetName] = value
},
...values,
})
8 changes: 4 additions & 4 deletions packages/ui/src/services/color/tests/color-config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ describe('useColors', () => {
)

it.each([
[[{ color: '#000000' }, 'va-test'], { '--va-test-color': '#000000' }],
[[{ color: 'secondary' }, 'va-test'], { '--va-test-color': 'var(--va-secondary)' }],
[[{ color: 'var(--va-primary)' }, 'va-test'], { '--va-test-color': 'var(--va-primary)' }], // TODO call Oleg
[[{ color: 'bad-color' }, 'va-test'], { '--va-test-color': '#154EC1' }],
[[{ color: '#000000' }, 'va-test'], { '--va-test-color': '#000000', '--va-test-on-color': 'var(--va-text-inverted)' }],
[[{ color: 'secondary' }, 'va-test'], { '--va-test-color': 'var(--va-secondary)', '--va-test-on-color': 'var(--va-text-inverted)' }],
[[{ color: 'var(--va-primary)' }, 'va-test'], { '--va-test-color': 'var(--va-primary)', '--va-test-on-color': 'var(--va-text-inverted)' }],
[[{ color: 'bad-color' }, 'va-test'], { '--va-test-color': '#154EC1', '--va-test-on-color': 'var(--va-text-inverted)' }],
[[{}, 'va-test'], {}],
])(
'colorToCssVariableArgs %s should be %s',
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/utils/headless.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const toNode = (v: any, attrs: NodeAttributes): VNode | null => {

if (v.type === Fragment) {
if (v.children === null) { return v }
return toNode(v.children[0], attrs)
return h(Fragment, v.props, v.children.map((v: any) => toNode(v, attrs)))
}

return h(v, attrs)
Expand Down
5 changes: 4 additions & 1 deletion packages/ui/src/utils/merge-deep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ export const mergeDeep = (target: any, source: any): any => {
const sourceValue = source[key]

if (isObject(targetValue) && isObject(sourceValue)) {
target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue)
target[key] = mergeDeep(Object.create(
Object.getPrototypeOf(targetValue),
Object.getOwnPropertyDescriptors(targetValue),
), sourceValue)
} else {
target[key] = sourceValue
}
Expand Down

0 comments on commit 06db00e

Please sign in to comment.