refactor: Migrate ColorCircles to composition api (no-changelog) (#9747)

This commit is contained in:
Tomi Turtiainen 2024-06-14 14:30:29 +03:00 committed by GitHub
parent db1cc24414
commit e293683234
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 92 additions and 100 deletions

View file

@ -0,0 +1,44 @@
/**
* Convert an HSL color to a Hex color
*/
export function hslToHex(h: number, s: number, l: number): string {
l /= 100;
const a = (s * Math.min(l, 1 - l)) / 100;
const f = (n: number) => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color)
.toString(16)
.padStart(2, '0');
};
return `#${f(0)}${f(8)}${f(4)}`;
}
/**
* Resolve calc() expressions in HSL strings
*/
export function resolveHSLCalc(hslString: string): string {
const calcRegex = /calc\(([^)]+)\)/;
const matchCalc = hslString.match(calcRegex);
if (!matchCalc) {
return hslString;
}
const expression = matchCalc[1].replace(/%/g, '');
const evaluation: number = eval(expression);
const finalPercentage = `${evaluation}%`;
return hslString.replace(calcRegex, finalPercentage);
}
/**
* Get the Hex color from an HSL color string
*/
export function getHex(hsl: string): string {
hsl = resolveHSLCalc(hsl);
const colors = hsl
.replace('hsl(', '')
.replace(')', '')
.replace(/%/g, '')
.split(',')
.map(parseFloat);
return hslToHex(colors[0], colors[1], colors[2]);
}

View file

@ -1,3 +1,51 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive } from 'vue';
import type { PropType } from 'vue';
import { getHex, resolveHSLCalc } from './ColorCircles.utils';
const props = defineProps({
colors: {
type: Array as PropType<string[]>,
required: true,
},
});
const hsl = reactive<{ [color: string]: string }>({});
const observer = ref<MutationObserver | null>(null);
const setColors = () => {
for (const color of props.colors) {
const style = getComputedStyle(document.body);
hsl[color] = style.getPropertyValue(color);
}
};
onMounted(() => {
setColors();
observer.value = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'attributes') {
setColors();
}
}
});
const body = document.querySelector('body');
if (body) {
observer.value.observe(body, { attributes: true });
}
});
onUnmounted(() => {
observer.value?.disconnect();
});
// Expose functions for template usage
const getHexValue = (color: string) => getHex(hsl[color]);
const getHSLValue = (color: string) => resolveHSLCalc(hsl[color]);
</script>
<template>
<div :class="$style.section">
<div v-for="color in colors" :key="color" :class="$style.container">
@ -9,106 +57,6 @@
</div>
</template>
<script lang="ts">
import type { PropType } from 'vue';
import { defineComponent } from 'vue';
function hslToHex(h: number, s: number, l: number): string {
l /= 100;
const a = (s * Math.min(l, 1 - l)) / 100;
const f = (n: number) => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color)
.toString(16)
.padStart(2, '0'); // convert to Hex and prefix "0" if needed
};
return `#${f(0)}${f(8)}${f(4)}`;
}
function resolveHSLCalc(hslString: string): string {
const calcRegex = /calc\(([^)]+)\)/;
const matchCalc = hslString.match(calcRegex);
if (!matchCalc) {
return hslString;
}
const expression = matchCalc[1];
const noPercentageExpression = expression.replace(/%/g, '');
const evaluation: number = eval(noPercentageExpression);
const finalPercentage = evaluation.toString() + '%';
const resolvedHslString = hslString.replace(calcRegex, finalPercentage);
return resolvedHslString;
}
function getHex(hsl: string): string {
hsl = resolveHSLCalc(hsl);
const colors = hsl
.replace('hsl(', '')
.replace(')', '')
.replace(/%/g, '')
.split(',')
.map((n: string) => parseFloat(n));
return hslToHex(colors[0], colors[1], colors[2]);
}
export default defineComponent({
name: 'ColorCircles',
props: {
colors: {
type: Array as PropType<string[]>,
required: true,
},
},
data() {
return {
observer: null as null | MutationObserver,
hsl: {} as { [color: string]: string },
};
},
created() {
const setColors = () => {
this.colors.forEach((color) => {
const style = getComputedStyle(document.body);
this.hsl = {
...this.hsl,
[color]: style.getPropertyValue(color),
};
});
};
setColors();
// when theme class is added or removed, reset color values
this.observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'attributes') {
setColors();
}
}
});
const body = document.querySelector('body');
if (body) {
this.observer.observe(body, { attributes: true });
}
},
unmounted() {
if (this.observer) {
this.observer.disconnect();
}
},
methods: {
getHexValue(color: string) {
return getHex(this.hsl[color]);
},
getHSLValue(color: string) {
return resolveHSLCalc(this.hsl[color]);
},
},
});
</script>
<style lang="scss" module>
.section {
display: flex;