Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: naive组件库 主题适配报错,需将hsl转换为rgb格式 #4041

Merged
merged 11 commits into from
Aug 7, 2024
3 changes: 2 additions & 1 deletion apps/web-naive/src/locales/langs/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"page": {
"demos": {
"title": "Demos",
"naive": "Naive UI"
"naive": "Naive UI",
"table": "Table"
}
}
}
3 changes: 2 additions & 1 deletion apps/web-naive/src/locales/langs/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"page": {
"demos": {
"title": "演示",
"naive": "Naive UI"
"naive": "Naive UI",
"table": "Table"
}
}
}
9 changes: 9 additions & 0 deletions apps/web-naive/src/router/routes/modules/demos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ const routes: RouteRecordRaw[] = [
path: '/demos/naive',
component: () => import('#/views/demos/naive/index.vue'),
},
{
meta: {
icon: 'mdi:shield-key-outline',
title: $t('page.demos.table'),
},
name: 'Table',
path: '/demos/table',
component: () => import('#/views/demos/table/index.vue'),
},
],
},
];
Expand Down
31 changes: 31 additions & 0 deletions apps/web-naive/src/views/demos/table/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import { ref } from 'vue';

import { NDataTable } from 'naive-ui';

const columns = ref([
{
key: 'no',
title: 'No',
},
{
key: 'title',
title: 'Title',
},
{
key: 'length',
title: 'Length',
},
]);
const data = [
{ length: '4:18', no: 3, title: 'Wonderwall' },
{ length: '4:48', no: 4, title: "Don't Look Back in Anger" },
{ length: '7:27', no: 12, title: 'Champagne Supernova' },
];
</script>

<template>
<NDataTable :columns="columns" :data="data" />
</template>

<style scoped></style>
148 changes: 147 additions & 1 deletion packages/@core/base/shared/src/colorful/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,150 @@
return new TinyColor(color).isValid;
}

export { convertToHsl, convertToHslCssVar, isValidColor, TinyColor };
interface RGBColor {
b: number;
g: number;
r: number;
}

interface RGBAColor extends RGBColor {
a: number;
}

interface HSLObjectStringColor {
h: string;
l: string;
s: string;
}
interface HSLAObjectStringColor extends HSLObjectStringColor {
a?: string;
}

const MATCHER =
/hsla?\(\s*(\+?-?\d+(?:\.\d+)?(?:e\d+)?[dgrt])\s*,\s*(\+?-?\d+(?:\.\d+)?%)\s*,\s*(\+?-?\d+(?:\.\d+)?%)(?:\s*,\s*(\+?-?\d+(?:\.\d+)?(?:e-\d+)?%?))?\s*\)/i;
// const MATCHER =
// /hsla?\(\s*(\+?-?\d*(?:\.\d*)?(?:e\+)?\d*(?:deg|rad|grad|turn)?)\s*,\s*(\+?-?\d*(?:\.\d*)?(?:e\+)?\d*%)\s*,\s*(\+?-?\d*(?:\.\d*)?(?:e\+)?\d*%)\s*(?:(,\s*\+?-?\s*(?:\d*(?:\.\d*)?(?:e-\d*)?%?)?)\s*)?\)/i;
// const MATCHER_SPACE =
// /hsla?\(\s*(\+?-?\d*(?:\.\d*)?(?:e\+)?\d*(?:deg|rad|grad|turn)?)\s*(\+?-?\d*(?:\.\d*)?(?:e\+)?\d*%)\s*(\+?-?\d*(?:\.\d*)?(?:e\+)?\d*%)\s*(?:(\/\s*\+?-?\s*(?:\d*(?:\.\d*)?(?:e-\d*)?%?)?)\s*)?\)/i;
const MATCHER_SPACE =
// eslint-disable-next-line regexp/no-super-linear-backtracking
/hsla?\(\s*(\+?-?\d{1,5}(?:\.\d{1,5})?(?:e[+-]?\d+)?(?:deg|rad|grad|turn)?)\s*(?:(\+?-?\d{1,5}(?:\.\d{1,5})?(?:e[+-]?\d+)?%?)\s*)?(\+?-?\d{1,5}(?:\.\d{1,5})?(?:e[+-]?\d+)?%?)?\s*(?:\/\s*(\+?-?\d{1,5}(?:\.\d{1,5})?(?:e[+-]?\d+)?%?)\s*)?\)/i;
vince292007 marked this conversation as resolved.
Show resolved Hide resolved

const aStr = (a?: string) => (a ? a.replace(/^([,/])\s*/, '').trim() : a);
export default function hslMatcher(
hsl: string = '',
): HSLAObjectStringColor | undefined {
const match = MATCHER.exec(hsl) || MATCHER_SPACE.exec(hsl);
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
if (match) {
const [_, h, s, l, a] = match;
if (a && /^:?[,/]\s*-?\+?$/.test(a.trim())) return;
return {
a: aStr(a),
h,
l,
s,
};
}
}
function hlsStringToRGB(hls: string): RGBAColor | RGBColor | undefined {
const obj = hslMatcher(hls);
if (!obj) return;
const { a: alphaStr, h: hueStr, l: lStr, s: sStr } = obj;
let h = 0;
let l = 0;
let s = 0;

if (/\s*\d*turn\s*$/.test(hueStr)) {
Fixed Show fixed Hide fixed
h = Number(hueStr.replace(/turn\s*$/i, '')) * 360;
} else if (/\s*\d*grad\s*$/.test(hueStr)) {
Fixed Show fixed Hide fixed
h = gradsToDegrees(hueStr.replace(/grad\s*$/i, ''));
} else if (/\s*\d*rad\s*$/.test(hueStr)) {
Fixed Show fixed Hide fixed
h = radiansToDegrees(Number(hueStr.replace(/rad\s*$/i, '')));
}

if (/^[+-]?\d*(?:\.\d*)?(?:e[+-]?\d+)?$/i.test(hueStr.replace(/deg$/i, ''))) {
h = Number(hueStr.replace(/deg$/i, ''));
}
if (h > 360) h = 360;
if (h < 0) h = 0;
if (/^[+-]?\d*(?:\.\d*)?(?:e[+-]?\d+)?%$/i.test(sStr)) {
s = Number(sStr.replace(/%$/, ''));
}
if (s > 100) s = 100;
if (s < 0) s = 0;
if (
/^(?:[+-]?\d*|[+-]?(?:[^\d\n\r\u2028\u2029]\d*|\d+(?:[^\d\n\r\u2028\u2029]\d*)?)(?:e\+\d*)?)%$/.test(
lStr,
)
) {
l = Number(lStr.replace(/%$/, ''));
}
if (l > 100) l = 100;
if (l < 0) l = 0;

s /= 100;
l /= 100;
const k = (n: number) => (n + h / 30) % 12;
const a = s * Math.min(l, 1 - l);
const f = (n: number) =>
l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));

// rounding
const toFixed = (n: number) => Number(n.toFixed(0));

/**
* https://drafts.csswg.org/css-color/#typedef-alpha-value
* Opacity in CSS is typically represented using the <alpha-value> syntax,
* for example in the opacity property or as the alpha component in a color function.
* Represented as a <number>, the useful range of the value is 0 (representing full transparency) to 1 (representing full opacity).
* It can also be written as a <percentage>, which computes to the equivalent <number> (0% to 0, 100% to 1).
* Unless otherwise specified, an <alpha-value> component defaults to 100% when omitted.
* Values outside the range [0,1] are not invalid, but are clamped to that range when computed.
*/
if (alphaStr && /^\+?-?\d*(?:\.\d*)?(?:e[+-]?\d+|%)?$/i.test(alphaStr)) {
const alpha = /%/.test(alphaStr)
? Number(alphaStr.replaceAll('%', '')) / 100
: Number(alphaStr);
return {
a: alpha,
b: toFixed(255 * f(4)),
g: toFixed(255 * f(8)),
r: toFixed(255 * f(0)),
};
}
return {
b: toFixed(255 * f(4)),
g: toFixed(255 * f(8)),
r: toFixed(255 * f(0)),
};
vince292007 marked this conversation as resolved.
Show resolved Hide resolved
}
/** Convert `grad` to `deg` */
function gradsToDegrees(input: number | string) {
let grads = Number(input);

grads = grads % 400;
if (grads < 0) {
grads += 400;
}
// or grads = grads < 0 ? 400 + grads : grads;
const degrees = (grads / 400) * 360; // or let degrees = grads*0.9
return degrees;
}

/** Convert `rad` to `deg` */
function radiansToDegrees(radians: number) {
return Number((radians * (180 / Math.PI)).toFixed(0));
}

function hlsStringToRGBSting(color: string): string {
return new TinyColor(hlsStringToRGB(`hsl(${color})`)).toRgbString();
}
vince292007 marked this conversation as resolved.
Show resolved Hide resolved

export {
convertToHsl,
convertToHslCssVar,
hlsStringToRGB,
hlsStringToRGBSting,
isValidColor,
TinyColor,
};
5 changes: 2 additions & 3 deletions packages/effects/hooks/src/use-design-tokens.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { reactive, watch } from 'vue';

import { preferences } from '@vben/preferences';
import { updateCSSVariables } from '@vben/utils';
import { hlsStringToRGBSting, updateCSSVariables } from '@vben/utils';

/**
* 用于适配各个框架的设计系统
Expand Down Expand Up @@ -102,7 +102,7 @@ export function useNaiveDesignTokens() {

const getCssVariableValue = (variable: string, isColor: boolean = true) => {
const value = rootStyles.getPropertyValue(variable);
return isColor ? `hsl(${value})` : value;
return isColor ? hlsStringToRGBSting(value) : value;
};

watch(
Expand Down Expand Up @@ -150,7 +150,6 @@ export function useNaiveDesignTokens() {
},
{ immediate: true },
);

return {
commonTokens,
};
Expand Down
Loading