vueless 0.0.325 → 0.0.326
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/composable.ui/index.js +17 -23
- package/constants/index.js +5 -1
- package/directive.tooltip/index.js +7 -8
- package/index.js +5 -1
- package/package.json +1 -1
- package/service.helper/index.js +32 -0
- package/service.theme/index.js +124 -0
- package/service.ui/index.js +63 -197
- package/ui.data-table/components/TableRow.vue +21 -5
- package/ui.data-table/index.vue +1 -1
- package/ui.loader/composables/attrs.composable.js +1 -1
- package/ui.text-notify/index.vue +2 -3
- package/ui.text-notify/services/index.js +2 -2
- package/web-types.json +1 -1
package/composable.ui/index.js
CHANGED
|
@@ -10,17 +10,15 @@ import {
|
|
|
10
10
|
Fragment,
|
|
11
11
|
} from "vue";
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
cx,
|
|
15
|
-
setColor,
|
|
16
|
-
getColor,
|
|
17
|
-
strategy,
|
|
18
|
-
nestedComponentRegEx,
|
|
19
|
-
globalComponentConfig,
|
|
20
|
-
} from "../service.ui";
|
|
13
|
+
import { cx, setColor, getColor, vuelessConfig } from "../service.ui/index.js";
|
|
21
14
|
|
|
22
|
-
import { cloneDeep } from "../service.helper";
|
|
23
|
-
import {
|
|
15
|
+
import { cloneDeep, isCSR } from "../service.helper/index.js";
|
|
16
|
+
import {
|
|
17
|
+
STRATEGY_TYPE,
|
|
18
|
+
CVA_CONFIG_KEY,
|
|
19
|
+
SYSTEM_CONFIG_KEY,
|
|
20
|
+
NESTED_COMPONENT_REG_EXP,
|
|
21
|
+
} from "../constants/index.js";
|
|
24
22
|
|
|
25
23
|
/**
|
|
26
24
|
Merging component configs in a given sequence (bigger number = bigger priority):
|
|
@@ -32,10 +30,11 @@ import { STRATEGY_TYPE, CVA_CONFIG_KEY, SYSTEM_CONFIG_KEY } from "../constants";
|
|
|
32
30
|
export default function useUI(defaultConfig = {}, propsConfigGetter = null, topLevelClassKey) {
|
|
33
31
|
const { type, props } = getCurrentInstance();
|
|
34
32
|
const componentName = type.name;
|
|
35
|
-
const globalConfig =
|
|
33
|
+
const globalConfig = vuelessConfig?.component ? vuelessConfig?.component[componentName] : {};
|
|
36
34
|
|
|
37
|
-
const isStrategyValid =
|
|
38
|
-
|
|
35
|
+
const isStrategyValid =
|
|
36
|
+
vuelessConfig.strategy && Object.values(STRATEGY_TYPE).includes(vuelessConfig.strategy);
|
|
37
|
+
const vuelessStrategy = isStrategyValid ? vuelessConfig.strategy : STRATEGY_TYPE.merge;
|
|
39
38
|
|
|
40
39
|
const [firstClassKey] = Object.keys(defaultConfig);
|
|
41
40
|
const config = ref({});
|
|
@@ -58,7 +57,7 @@ export default function useUI(defaultConfig = {}, propsConfigGetter = null, topL
|
|
|
58
57
|
const nestedComponent = getNestedComponent(defaultConfig[configKey]);
|
|
59
58
|
|
|
60
59
|
const attrs = useAttrs();
|
|
61
|
-
const isDev = import.meta.env
|
|
60
|
+
const isDev = isCSR && import.meta.env?.DEV;
|
|
62
61
|
const vuelessAttrs = ref({});
|
|
63
62
|
const isTopLevelKey = (topLevelClassKey || firstClassKey) === configKey;
|
|
64
63
|
|
|
@@ -199,7 +198,6 @@ function mergeConfigs({
|
|
|
199
198
|
safelistColors,
|
|
200
199
|
defaultVariants,
|
|
201
200
|
compoundVariants,
|
|
202
|
-
iconName,
|
|
203
201
|
} = SYSTEM_CONFIG_KEY;
|
|
204
202
|
|
|
205
203
|
for (let key in composedConfig) {
|
|
@@ -235,7 +233,6 @@ function mergeConfigs({
|
|
|
235
233
|
|
|
236
234
|
const isObject = isObjectComposedConfig || isObjectGlobalConfig || isObjectPropsConfig;
|
|
237
235
|
const isEmpty = composedConfig[key] === null;
|
|
238
|
-
const isIconName = key.toLowerCase().includes(iconName.toLowerCase());
|
|
239
236
|
const isI18n = key === i18n;
|
|
240
237
|
|
|
241
238
|
if (key === "variants" && !isVariants) {
|
|
@@ -252,7 +249,7 @@ function mergeConfigs({
|
|
|
252
249
|
isReplace,
|
|
253
250
|
isVariants,
|
|
254
251
|
})
|
|
255
|
-
: isReplace ||
|
|
252
|
+
: isReplace || isI18n
|
|
256
253
|
? propsConfig[key] || globalConfig[key] || defaultConfig[key]
|
|
257
254
|
: cx([defaultConfig[key], globalConfig[key], propsConfig[key]]);
|
|
258
255
|
}
|
|
@@ -388,7 +385,8 @@ function getBaseClasses(value) {
|
|
|
388
385
|
function getNestedComponent(value) {
|
|
389
386
|
const classes = getBaseClasses(value);
|
|
390
387
|
const component = value?.component || "";
|
|
391
|
-
const match =
|
|
388
|
+
const match =
|
|
389
|
+
classes.match(NESTED_COMPONENT_REG_EXP) || component.match(NESTED_COMPONENT_REG_EXP);
|
|
392
390
|
|
|
393
391
|
return match ? match[1] : "";
|
|
394
392
|
}
|
|
@@ -401,11 +399,7 @@ function getNestedComponent(value) {
|
|
|
401
399
|
function isSystemKey(key) {
|
|
402
400
|
const isExactKey = Object.values(SYSTEM_CONFIG_KEY).some((value) => value === key);
|
|
403
401
|
|
|
404
|
-
return (
|
|
405
|
-
isExactKey ||
|
|
406
|
-
key.toLowerCase().includes(SYSTEM_CONFIG_KEY.iconName.toLowerCase()) ||
|
|
407
|
-
key.toLowerCase().includes(SYSTEM_CONFIG_KEY.transition.toLowerCase())
|
|
408
|
-
);
|
|
402
|
+
return isExactKey || key.toLowerCase().includes(SYSTEM_CONFIG_KEY.transition.toLowerCase());
|
|
409
403
|
}
|
|
410
404
|
|
|
411
405
|
/**
|
package/constants/index.js
CHANGED
|
@@ -62,6 +62,10 @@ export const SYSTEM_CONFIG_KEY = {
|
|
|
62
62
|
component: "component",
|
|
63
63
|
transition: "transition",
|
|
64
64
|
safelistColors: "safelistColors",
|
|
65
|
-
iconName: "iconName",
|
|
66
65
|
...CVA_CONFIG_KEY,
|
|
67
66
|
};
|
|
67
|
+
|
|
68
|
+
/* Other */
|
|
69
|
+
export const PX_IN_REM = 16;
|
|
70
|
+
export const HYPHEN_SYMBOL = "-";
|
|
71
|
+
export const NESTED_COMPONENT_REG_EXP = /\{U[^}]*}/g;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import tippy from "tippy.js";
|
|
2
2
|
import { merge } from "lodash-es";
|
|
3
3
|
|
|
4
|
+
// Fix for SSR
|
|
4
5
|
import "tippy.js/dist/tippy.css";
|
|
5
6
|
import "tippy.js/themes/light.css";
|
|
6
7
|
import "tippy.js/animations/shift-away.css";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import.meta.glob("/vueless.config.js", { eager: true, import: "default" }),
|
|
11
|
-
);
|
|
9
|
+
import { vuelessConfig } from "../service.ui/index.js";
|
|
10
|
+
import { isCSR, isSSR } from "../service.helper/index.js";
|
|
12
11
|
|
|
13
12
|
const globalSettings = vuelessConfig?.directive?.tooltip || {};
|
|
14
13
|
const defaultSettings = {
|
|
@@ -19,21 +18,21 @@ const defaultSettings = {
|
|
|
19
18
|
|
|
20
19
|
const mergedSettings = merge(defaultSettings, globalSettings);
|
|
21
20
|
|
|
22
|
-
tippy.setDefaultProps(mergedSettings);
|
|
21
|
+
isCSR && tippy.setDefaultProps(mergedSettings);
|
|
23
22
|
|
|
24
23
|
export default {
|
|
25
24
|
mounted(el, bindings) {
|
|
26
|
-
tippy(el, merge(mergedSettings, bindings.value || {}));
|
|
25
|
+
isCSR && tippy(el, merge(mergedSettings, bindings.value || {}));
|
|
27
26
|
},
|
|
28
27
|
|
|
29
28
|
updated(el, bindings) {
|
|
30
|
-
if (!el._tippy) return;
|
|
29
|
+
if (!el._tippy || isSSR) return;
|
|
31
30
|
|
|
32
31
|
el._tippy.setProps(merge(mergedSettings, bindings.value || {}));
|
|
33
32
|
},
|
|
34
33
|
|
|
35
34
|
unmounted(el) {
|
|
36
|
-
if (!el._tippy) return;
|
|
35
|
+
if (!el._tippy || isSSR) return;
|
|
37
36
|
|
|
38
37
|
el._tippy.destroy();
|
|
39
38
|
},
|
package/index.js
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import { createLocale, LocaleSymbol } from "./composable.locale";
|
|
3
3
|
import { createLoaderRendering, LoaderRenderingSymbol } from "./ui.loader-rendering/composables/useLoaderRendering";
|
|
4
4
|
import { createLoaderTop, LoaderTopSymbol } from "./ui.loader-top/composables/useLoaderTop";
|
|
5
|
+
import { themeInit } from "./service.theme";
|
|
5
6
|
|
|
6
|
-
export {
|
|
7
|
+
export { setTitle } from "./service.helper";
|
|
8
|
+
export { setTheme } from "./service.theme";
|
|
7
9
|
export { default as createVueI18nAdapter } from "./adatper.locale/vue-i18n";
|
|
8
10
|
export { default as defaultEnLocale } from "./adatper.locale/locales/en";
|
|
9
11
|
export { useLocale } from "./composable.locale";
|
|
@@ -33,6 +35,8 @@ export function createVueless(options = {}) {
|
|
|
33
35
|
app.provide(LoaderTopSymbol, loaderTop);
|
|
34
36
|
};
|
|
35
37
|
|
|
38
|
+
themeInit();
|
|
39
|
+
|
|
36
40
|
return {
|
|
37
41
|
install,
|
|
38
42
|
};
|
package/package.json
CHANGED
package/service.helper/index.js
CHANGED
|
@@ -37,6 +37,13 @@ export function cloneDeep(entity, cache = new WeakMap()) {
|
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
Invoke function with delay (same as lodash.debounce).
|
|
42
|
+
@param {Function} func
|
|
43
|
+
@param {Number} wait
|
|
44
|
+
|
|
45
|
+
@returns {Function}
|
|
46
|
+
*/
|
|
40
47
|
export function debounce(func, wait) {
|
|
41
48
|
let timeout;
|
|
42
49
|
|
|
@@ -47,3 +54,28 @@ export function debounce(func, wait) {
|
|
|
47
54
|
timeout = setTimeout(() => func.apply(context, args), wait);
|
|
48
55
|
};
|
|
49
56
|
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
Change page title in runtime by provided config.
|
|
60
|
+
@param {Object} config
|
|
61
|
+
@param {string} config.title
|
|
62
|
+
@param {string} config.separator
|
|
63
|
+
@param {string} config.suffix
|
|
64
|
+
|
|
65
|
+
@returns {VoidFunction}
|
|
66
|
+
*/
|
|
67
|
+
export function setTitle({ title, separator = " / ", suffix = "" }) {
|
|
68
|
+
document.title = title ? title + separator + suffix : suffix;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
Check is code rendering on the server side.
|
|
73
|
+
@returns {boolean}
|
|
74
|
+
*/
|
|
75
|
+
export const isSSR = typeof window === "undefined";
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
Check is code rendering on the client side.
|
|
79
|
+
@returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
export const isCSR = typeof window !== "undefined";
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import colors from "tailwindcss/colors.js";
|
|
2
|
+
|
|
3
|
+
import { vuelessConfig } from "../service.ui";
|
|
4
|
+
import {
|
|
5
|
+
GRAY_COLOR,
|
|
6
|
+
COOL_COLOR,
|
|
7
|
+
BRAND_COLORS,
|
|
8
|
+
GRAYSCALE_COLOR,
|
|
9
|
+
DEFAULT_RING,
|
|
10
|
+
DEFAULT_RING_OFFSET,
|
|
11
|
+
DEFAULT_ROUNDING,
|
|
12
|
+
DEFAULT_BRAND_COLOR,
|
|
13
|
+
DEFAULT_GRAY_COLOR,
|
|
14
|
+
DARK_MODE_SELECTOR,
|
|
15
|
+
GRAY_COLORS,
|
|
16
|
+
PX_IN_REM,
|
|
17
|
+
} from "../constants/index.js";
|
|
18
|
+
|
|
19
|
+
export function themeInit() {
|
|
20
|
+
const prefersColorSchemeDark = window && window.matchMedia("(prefers-color-scheme: dark)");
|
|
21
|
+
|
|
22
|
+
setTheme({ systemDarkMode: prefersColorSchemeDark.matches });
|
|
23
|
+
|
|
24
|
+
prefersColorSchemeDark.addEventListener("change", (event) =>
|
|
25
|
+
setTheme({ systemDarkMode: event.matches }),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function setTheme(config = {}) {
|
|
30
|
+
const isDarkMode = setDarkMode(config);
|
|
31
|
+
const ring = config?.ring ?? vuelessConfig?.ring ?? DEFAULT_RING;
|
|
32
|
+
const ringOffset = config?.ringOffset ?? vuelessConfig?.ringOffset ?? DEFAULT_RING_OFFSET;
|
|
33
|
+
const rounding = config?.rounding ?? vuelessConfig?.rounding ?? DEFAULT_ROUNDING;
|
|
34
|
+
let brand = config?.brand ?? vuelessConfig?.brand ?? DEFAULT_BRAND_COLOR;
|
|
35
|
+
let gray = config?.gray ?? vuelessConfig?.gray ?? DEFAULT_GRAY_COLOR;
|
|
36
|
+
|
|
37
|
+
const isBrandColor = BRAND_COLORS.some((color) => color === brand);
|
|
38
|
+
const isGrayColor = GRAY_COLORS.some((color) => color === gray);
|
|
39
|
+
|
|
40
|
+
if (!isBrandColor) {
|
|
41
|
+
// eslint-disable-next-line no-console
|
|
42
|
+
console.warn(`Brand color '${brand}' is incorrect.`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!isGrayColor) {
|
|
46
|
+
// eslint-disable-next-line no-console
|
|
47
|
+
console.warn(`Gray color '${gray}' is incorrect.`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const defaultBrandShade = isDarkMode ? 400 : 600;
|
|
51
|
+
const defaultGrayShade = isDarkMode ? 400 : 600;
|
|
52
|
+
|
|
53
|
+
if (gray === COOL_COLOR) {
|
|
54
|
+
gray = GRAY_COLOR;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (brand === GRAYSCALE_COLOR) {
|
|
58
|
+
brand = gray;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const variables = {
|
|
62
|
+
"--vl-ring": `${ring}px`,
|
|
63
|
+
"--vl-ring-offset": `${ringOffset}px`,
|
|
64
|
+
"--vl-rounding": `${Number(rounding) / PX_IN_REM}rem`,
|
|
65
|
+
"--vl-color-gray-default": convertHexInRgb(colors[gray][defaultBrandShade]),
|
|
66
|
+
"--vl-color-brand-default": convertHexInRgb(colors[brand][defaultGrayShade]),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
for (const key in colors[gray]) {
|
|
70
|
+
variables[`--vl-color-gray-${key}`] = convertHexInRgb(colors[gray][key]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const key in colors[brand]) {
|
|
74
|
+
variables[`--vl-color-brand-${key}`] = convertHexInRgb(colors[brand][key]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const style = document.createElement("style");
|
|
78
|
+
const stringVariables = Object.entries(variables)
|
|
79
|
+
.map(([key, value]) => `${key}: ${value};`)
|
|
80
|
+
.join(" ");
|
|
81
|
+
|
|
82
|
+
style.innerHTML = `:root {${stringVariables}`;
|
|
83
|
+
|
|
84
|
+
document.head.appendChild(style);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function setDarkMode(config) {
|
|
88
|
+
config?.darkMode === undefined
|
|
89
|
+
? localStorage.removeItem(DARK_MODE_SELECTOR)
|
|
90
|
+
: localStorage.setItem(DARK_MODE_SELECTOR, Number(!!config?.darkMode));
|
|
91
|
+
|
|
92
|
+
const storedDarkMode = localStorage.getItem(DARK_MODE_SELECTOR);
|
|
93
|
+
|
|
94
|
+
let isDarkMode =
|
|
95
|
+
storedDarkMode !== null
|
|
96
|
+
? !!Number(storedDarkMode)
|
|
97
|
+
: !!(config?.darkMode ?? vuelessConfig?.darkMode ?? config?.systemDarkMode);
|
|
98
|
+
|
|
99
|
+
isDarkMode
|
|
100
|
+
? document.documentElement.classList.add(DARK_MODE_SELECTOR)
|
|
101
|
+
: document.documentElement.classList.remove(DARK_MODE_SELECTOR);
|
|
102
|
+
|
|
103
|
+
return isDarkMode;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function convertHexInRgb(hex) {
|
|
107
|
+
const color = hex.replace(/#/g, "");
|
|
108
|
+
|
|
109
|
+
let r, g, b;
|
|
110
|
+
|
|
111
|
+
if (color.length === 6) {
|
|
112
|
+
r = parseInt(color.substring(0, 2), 16);
|
|
113
|
+
g = parseInt(color.substring(2, 4), 16);
|
|
114
|
+
b = parseInt(color.substring(4, 6), 16);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (color.length === 3) {
|
|
118
|
+
r = parseInt(color.substring(0, 1).repeat(2), 16);
|
|
119
|
+
g = parseInt(color.substring(1, 2).repeat(2), 16);
|
|
120
|
+
b = parseInt(color.substring(2, 3).repeat(2), 16);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return color.length === 6 || color.length === 3 ? `${r}, ${g}, ${b}` : "";
|
|
124
|
+
}
|
package/service.ui/index.js
CHANGED
|
@@ -1,46 +1,36 @@
|
|
|
1
1
|
import { merge } from "lodash-es";
|
|
2
2
|
import { defineConfig } from "cva";
|
|
3
3
|
import { extendTailwindMerge } from "tailwind-merge";
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import { cloneDeep } from "../service.helper";
|
|
4
|
+
import { cloneDeep, isCSR, isSSR } from "../service.helper/index.js";
|
|
7
5
|
import {
|
|
8
|
-
GRAY_COLOR,
|
|
9
|
-
COOL_COLOR,
|
|
10
6
|
BRAND_COLOR,
|
|
11
|
-
BRAND_COLORS,
|
|
12
7
|
GRAYSCALE_COLOR,
|
|
13
|
-
DEFAULT_RING,
|
|
14
|
-
DEFAULT_RING_OFFSET,
|
|
15
|
-
DEFAULT_ROUNDING,
|
|
16
8
|
DEFAULT_BRAND_COLOR,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
GRAY_COLORS,
|
|
20
|
-
} from "../constants";
|
|
9
|
+
NESTED_COMPONENT_REG_EXP,
|
|
10
|
+
} from "../constants/index.js";
|
|
21
11
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
/**
|
|
13
|
+
Load Vueless config from the project root.
|
|
14
|
+
Both for server and client side renderings.
|
|
15
|
+
IIFE is used to cache the results.
|
|
16
|
+
*/
|
|
17
|
+
export const vuelessConfig = (() => {
|
|
18
|
+
let config = {};
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
export const {
|
|
32
|
-
layout,
|
|
33
|
-
strategy,
|
|
34
|
-
rounding,
|
|
35
|
-
gray,
|
|
36
|
-
brand,
|
|
37
|
-
tailwindMerge: globalTailwindMergeConfig,
|
|
38
|
-
component: globalComponentConfig,
|
|
39
|
-
} = vuelessConfig;
|
|
20
|
+
if (isSSR) {
|
|
21
|
+
// TODO: test it in SSR, maybe `await` is needed
|
|
22
|
+
config = import(/* @vite-ignore */ `${process.cwd()}/vueless.config.js`).default;
|
|
23
|
+
}
|
|
40
24
|
|
|
41
|
-
|
|
25
|
+
if (isCSR) {
|
|
26
|
+
config = Object.values(
|
|
27
|
+
import.meta.glob("/vueless.config.js", { eager: true, import: "default" }),
|
|
28
|
+
)[0];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return config;
|
|
32
|
+
})();
|
|
42
33
|
|
|
43
|
-
//
|
|
44
34
|
/**
|
|
45
35
|
Extend twMerge (tailwind merge) by vueless and user config:
|
|
46
36
|
All list of rules available here:
|
|
@@ -61,7 +51,7 @@ const twMerge = extendTailwindMerge(
|
|
|
61
51
|
},
|
|
62
52
|
},
|
|
63
53
|
},
|
|
64
|
-
|
|
54
|
+
vuelessConfig.tailwindMerge,
|
|
65
55
|
),
|
|
66
56
|
);
|
|
67
57
|
|
|
@@ -69,83 +59,52 @@ const twMerge = extendTailwindMerge(
|
|
|
69
59
|
Export cva (class variance authority) methods:
|
|
70
60
|
* extended with tailwind-merge
|
|
71
61
|
* remove all Vueless nested component names ({U...} strings) from class list string.
|
|
72
|
-
It helps to make class variation switchers and removes class duplications.
|
|
73
62
|
https://beta.cva.style
|
|
74
63
|
*/
|
|
75
|
-
export const {
|
|
76
|
-
cva: classVarianceAuthority,
|
|
77
|
-
cx,
|
|
78
|
-
compose,
|
|
79
|
-
} = defineConfig({
|
|
64
|
+
export const { cva, cx, compose } = defineConfig({
|
|
80
65
|
hooks: {
|
|
81
|
-
onComplete: (classNames) => twMerge(classNames).replace(
|
|
66
|
+
onComplete: (classNames) => twMerge(classNames).replace(NESTED_COMPONENT_REG_EXP, ""),
|
|
82
67
|
},
|
|
83
68
|
});
|
|
84
69
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
compoundVariants,
|
|
90
|
-
defaultVariants,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const PX_IN_REM = 16;
|
|
94
|
-
const HYPHEN_SYMBOL = "-";
|
|
95
|
-
|
|
96
|
-
(() => {
|
|
97
|
-
const prefersColorSchemeDark = window && window.matchMedia("(prefers-color-scheme: dark)");
|
|
98
|
-
|
|
99
|
-
setTheme({ systemDarkMode: prefersColorSchemeDark.matches });
|
|
70
|
+
/**
|
|
71
|
+
Return default values for component props, icons, etc..
|
|
72
|
+
@param { Object } defaultConfig
|
|
73
|
+
@param { String } name
|
|
100
74
|
|
|
101
|
-
|
|
102
|
-
|
|
75
|
+
@returns { Object }
|
|
76
|
+
*/
|
|
77
|
+
export function getDefault(defaultConfig, name) {
|
|
78
|
+
const defaults = merge(
|
|
79
|
+
cloneDeep(defaultConfig.defaults),
|
|
80
|
+
vuelessConfig?.component ? vuelessConfig?.component[name]?.defaults : {},
|
|
103
81
|
);
|
|
104
|
-
})();
|
|
105
|
-
|
|
106
|
-
function getRandomId(length = 15) {
|
|
107
|
-
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
108
|
-
const charactersLength = characters.length;
|
|
109
|
-
let id = "";
|
|
110
|
-
|
|
111
|
-
while (id.length < length) {
|
|
112
|
-
id += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return id;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function setTitle({ title, separator = " / ", suffix = "" }) {
|
|
119
|
-
document.title = title ? title + separator + suffix : suffix;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function setFavicon(faviconPath) {
|
|
123
|
-
if (!faviconPath) return;
|
|
124
|
-
|
|
125
|
-
const head = document.querySelector("head");
|
|
126
|
-
const faviconTag = document.createElement("link");
|
|
127
|
-
|
|
128
|
-
faviconTag.setAttribute("rel", "shortcut icon");
|
|
129
|
-
faviconTag.setAttribute("href", `${faviconPath}?${Math.random()}`);
|
|
130
|
-
|
|
131
|
-
head.appendChild(faviconTag);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function getDefault(defaultConfig, name) {
|
|
135
|
-
const defaults = merge(cloneDeep(defaultConfig.defaults), globalComponentConfig[name]?.defaults);
|
|
136
82
|
|
|
137
83
|
defaults.color = getColor(defaults.color);
|
|
138
84
|
|
|
139
85
|
return defaults;
|
|
140
86
|
}
|
|
141
87
|
|
|
142
|
-
|
|
143
|
-
|
|
88
|
+
/**
|
|
89
|
+
Return `grayscale` color if in component config it `brand` but in vueless config it `grayscale`
|
|
90
|
+
Otherwise return given color.
|
|
91
|
+
@param { String } color
|
|
92
|
+
@returns { String }
|
|
93
|
+
*/
|
|
94
|
+
export function getColor(color) {
|
|
95
|
+
return (vuelessConfig.brand ?? DEFAULT_BRAND_COLOR) === GRAYSCALE_COLOR && color === BRAND_COLOR
|
|
144
96
|
? GRAYSCALE_COLOR
|
|
145
97
|
: color;
|
|
146
98
|
}
|
|
147
99
|
|
|
148
|
-
|
|
100
|
+
/**
|
|
101
|
+
Replace in tailwind classes `{color}` variable into given color.
|
|
102
|
+
@param { String } classes
|
|
103
|
+
@param { String } color
|
|
104
|
+
|
|
105
|
+
@returns { String }
|
|
106
|
+
*/
|
|
107
|
+
export function setColor(classes, color) {
|
|
149
108
|
if (typeof classes !== "string") {
|
|
150
109
|
return "";
|
|
151
110
|
}
|
|
@@ -153,113 +112,20 @@ function setColor(classes, color) {
|
|
|
153
112
|
return classes?.replaceAll("{color}", color);
|
|
154
113
|
}
|
|
155
114
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
storedDarkMode !== null
|
|
165
|
-
? !!Number(storedDarkMode)
|
|
166
|
-
: !!(config?.darkMode ?? vuelessConfig?.darkMode ?? config?.systemDarkMode);
|
|
167
|
-
|
|
168
|
-
isDarkMode
|
|
169
|
-
? document.documentElement.classList.add(DARK_MODE_SELECTOR)
|
|
170
|
-
: document.documentElement.classList.remove(DARK_MODE_SELECTOR);
|
|
171
|
-
|
|
172
|
-
return isDarkMode;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function setTheme(config = {}) {
|
|
176
|
-
const isDarkMode = setDarkMode(config);
|
|
177
|
-
const ring = config?.ring ?? vuelessConfig?.ring ?? DEFAULT_RING;
|
|
178
|
-
const ringOffset = config?.ringOffset ?? vuelessConfig?.ringOffset ?? DEFAULT_RING_OFFSET;
|
|
179
|
-
const rounding = config?.rounding ?? vuelessConfig?.rounding ?? DEFAULT_ROUNDING;
|
|
180
|
-
let brand = config?.brand ?? vuelessConfig?.brand ?? DEFAULT_BRAND_COLOR;
|
|
181
|
-
let gray = config?.gray ?? vuelessConfig?.gray ?? DEFAULT_GRAY_COLOR;
|
|
182
|
-
|
|
183
|
-
const isBrandColor = BRAND_COLORS.some((color) => color === brand);
|
|
184
|
-
const isGrayColor = GRAY_COLORS.some((color) => color === gray);
|
|
185
|
-
|
|
186
|
-
if (!isBrandColor) {
|
|
187
|
-
// eslint-disable-next-line no-console
|
|
188
|
-
console.warn(`Brand color '${brand}' is incorrect.`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (!isGrayColor) {
|
|
192
|
-
// eslint-disable-next-line no-console
|
|
193
|
-
console.warn(`Gray color '${gray}' is incorrect.`);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const defaultBrandShade = isDarkMode ? 400 : 600;
|
|
197
|
-
const defaultGrayShade = isDarkMode ? 400 : 600;
|
|
198
|
-
|
|
199
|
-
if (gray === COOL_COLOR) {
|
|
200
|
-
gray = GRAY_COLOR;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (brand === GRAYSCALE_COLOR) {
|
|
204
|
-
brand = gray;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const variables = {
|
|
208
|
-
"--vl-ring": `${ring}px`,
|
|
209
|
-
"--vl-ring-offset": `${ringOffset}px`,
|
|
210
|
-
"--vl-rounding": `${Number(rounding) / PX_IN_REM}rem`,
|
|
211
|
-
"--vl-color-gray-default": convertHexInRgb(colors[gray][defaultBrandShade]),
|
|
212
|
-
"--vl-color-brand-default": convertHexInRgb(colors[brand][defaultGrayShade]),
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
for (const key in colors[gray]) {
|
|
216
|
-
variables[`--vl-color-gray-${key}`] = convertHexInRgb(colors[gray][key]);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
for (const key in colors[brand]) {
|
|
220
|
-
variables[`--vl-color-brand-${key}`] = convertHexInRgb(colors[brand][key]);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const style = document.createElement("style");
|
|
224
|
-
const stringVariables = Object.entries(variables)
|
|
225
|
-
.map(([key, value]) => `${key}: ${value};`)
|
|
226
|
-
.join(" ");
|
|
227
|
-
|
|
228
|
-
style.innerHTML = `:root {${stringVariables}`;
|
|
229
|
-
|
|
230
|
-
document.head.appendChild(style);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function convertHexInRgb(hex) {
|
|
234
|
-
const color = hex.replace(/#/g, "");
|
|
235
|
-
|
|
236
|
-
let r, g, b;
|
|
115
|
+
/**
|
|
116
|
+
Generates unique #id.
|
|
117
|
+
@param { Number } length
|
|
118
|
+
@returns { String }
|
|
119
|
+
*/
|
|
120
|
+
export function getRandomId(length = 15) {
|
|
121
|
+
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
122
|
+
const charactersLength = characters.length;
|
|
237
123
|
|
|
238
|
-
|
|
239
|
-
r = parseInt(color.substring(0, 2), 16);
|
|
240
|
-
g = parseInt(color.substring(2, 4), 16);
|
|
241
|
-
b = parseInt(color.substring(4, 6), 16);
|
|
242
|
-
}
|
|
124
|
+
let id = "";
|
|
243
125
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
g = parseInt(color.substring(1, 2).repeat(2), 16);
|
|
247
|
-
b = parseInt(color.substring(2, 3).repeat(2), 16);
|
|
126
|
+
while (id.length < length) {
|
|
127
|
+
id += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
248
128
|
}
|
|
249
129
|
|
|
250
|
-
return
|
|
130
|
+
return id;
|
|
251
131
|
}
|
|
252
|
-
|
|
253
|
-
export {
|
|
254
|
-
PX_IN_REM,
|
|
255
|
-
HYPHEN_SYMBOL,
|
|
256
|
-
getRandomId,
|
|
257
|
-
setTitle,
|
|
258
|
-
setFavicon,
|
|
259
|
-
getDefault,
|
|
260
|
-
getColor,
|
|
261
|
-
setColor,
|
|
262
|
-
setDarkMode,
|
|
263
|
-
setTheme,
|
|
264
|
-
convertHexInRgb,
|
|
265
|
-
};
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
<div
|
|
47
47
|
v-bind="attrs.bodyCellPrimaryAttrs"
|
|
48
48
|
ref="cellRef"
|
|
49
|
+
:title="isElementOverflown(cellRef?.[index]) ? value.primary : ''"
|
|
49
50
|
:data-test="`${dataTest}-${key}-cell`"
|
|
50
51
|
>
|
|
51
52
|
{{ value.primary || HYPHEN_SYMBOL }}
|
|
@@ -53,14 +54,23 @@
|
|
|
53
54
|
|
|
54
55
|
<div v-bind="attrs.bodyCellSecondaryAttrs">
|
|
55
56
|
<template v-if="Array.isArray(value.secondary)">
|
|
56
|
-
<div
|
|
57
|
+
<div
|
|
58
|
+
v-for="(secondary, idx) in value.secondary"
|
|
59
|
+
ref="cellRef"
|
|
60
|
+
:key="idx"
|
|
61
|
+
:title="isElementOverflown(cellRef?.[index]) ? value.secondary : ''"
|
|
62
|
+
>
|
|
57
63
|
<span v-bind="attrs.bodyCellSecondaryEmptyAttrs">
|
|
58
64
|
{{ secondary }}
|
|
59
65
|
</span>
|
|
60
66
|
</div>
|
|
61
67
|
</template>
|
|
62
68
|
|
|
63
|
-
<div
|
|
69
|
+
<div
|
|
70
|
+
v-else
|
|
71
|
+
ref="cellRef"
|
|
72
|
+
:title="isElementOverflown(cellRef?.[index]) ? value.secondary : ''"
|
|
73
|
+
>
|
|
64
74
|
{{ value.secondary }}
|
|
65
75
|
</div>
|
|
66
76
|
</div>
|
|
@@ -72,6 +82,7 @@
|
|
|
72
82
|
<div
|
|
73
83
|
v-bind="attrs.bodyCellPrimaryAttrs"
|
|
74
84
|
ref="cellRef"
|
|
85
|
+
:title="isElementOverflown(cellRef?.[index]) ? value : ''"
|
|
75
86
|
:data-test="`${dataTest}-${key}-cell`"
|
|
76
87
|
>
|
|
77
88
|
{{ value || value === 0 ? value : HYPHEN_SYMBOL }}
|
|
@@ -100,7 +111,7 @@
|
|
|
100
111
|
<script setup>
|
|
101
112
|
import { computed, ref } from "vue";
|
|
102
113
|
|
|
103
|
-
import { HYPHEN_SYMBOL } from "../../
|
|
114
|
+
import { HYPHEN_SYMBOL } from "../../constants";
|
|
104
115
|
import { getFilteredRow } from "../services/table.service.js";
|
|
105
116
|
|
|
106
117
|
import { useMutationObserver } from "../../composable.mutationObserver/index.js";
|
|
@@ -185,8 +196,7 @@ function setCellTitle(mutations) {
|
|
|
185
196
|
mutations.forEach((mutation) => {
|
|
186
197
|
const { target } = mutation;
|
|
187
198
|
|
|
188
|
-
const isOverflown =
|
|
189
|
-
target.clientWidth < target.scrollWidth || target.clientHeight < target.scrollHeight;
|
|
199
|
+
const isOverflown = isElementOverflown(target);
|
|
190
200
|
|
|
191
201
|
if (isOverflown) {
|
|
192
202
|
target.setAttribute("title", target.textContent);
|
|
@@ -197,4 +207,10 @@ function setCellTitle(mutations) {
|
|
|
197
207
|
}
|
|
198
208
|
});
|
|
199
209
|
}
|
|
210
|
+
|
|
211
|
+
function isElementOverflown(element) {
|
|
212
|
+
if (!cellRef.value) return false;
|
|
213
|
+
|
|
214
|
+
return element.clientWidth < element.scrollWidth || element.clientHeight < element.scrollHeight;
|
|
215
|
+
}
|
|
200
216
|
</script>
|
package/ui.data-table/index.vue
CHANGED
|
@@ -292,7 +292,7 @@ import {
|
|
|
292
292
|
getFlatRows,
|
|
293
293
|
} from "./services/table.service";
|
|
294
294
|
|
|
295
|
-
import { PX_IN_REM } from "../
|
|
295
|
+
import { PX_IN_REM } from "../constants";
|
|
296
296
|
import { UTable } from "./constants";
|
|
297
297
|
import useAttrs from "./composables/attrs.composable";
|
|
298
298
|
import { useLocale } from "../composable.locale";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import useUI from "../../composable.ui";
|
|
2
2
|
import { cva, cx } from "../../service.ui";
|
|
3
3
|
|
|
4
|
-
import defaultConfig from "../configs/default.config";
|
|
4
|
+
import defaultConfig from "../configs/default.config.js";
|
|
5
5
|
import { computed } from "vue";
|
|
6
6
|
|
|
7
7
|
export default function useAttrs(props) {
|
package/ui.text-notify/index.vue
CHANGED
|
@@ -80,8 +80,7 @@
|
|
|
80
80
|
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
|
|
81
81
|
import { merge } from "lodash-es";
|
|
82
82
|
|
|
83
|
-
import {
|
|
84
|
-
|
|
83
|
+
import { cx, getDefault, vuelessConfig } from "../service.ui";
|
|
85
84
|
import { useLocale } from "../composable.locale";
|
|
86
85
|
import useAttrs from "./composables/attrs.composable";
|
|
87
86
|
|
|
@@ -193,7 +192,7 @@ function getOffsetWidth(selector) {
|
|
|
193
192
|
}
|
|
194
193
|
|
|
195
194
|
function setPosition() {
|
|
196
|
-
const positionClasses =
|
|
195
|
+
const positionClasses = vuelessConfig.component?.UNotify?.positionClasses;
|
|
197
196
|
const pageClass = positionClasses?.page || config.value.positionClasses.page;
|
|
198
197
|
const asideClass = positionClasses?.aside || config.value.positionClasses.aside;
|
|
199
198
|
const pageWidth = getOffsetWidth(`${pageClass}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRandomId, vuelessConfig } from "../../service.ui";
|
|
2
2
|
import { DELAY_BETWEEN_CLONES, DURATION, LOCAL_STORAGE_ID, NOTIFY_TYPE } from "../constants";
|
|
3
3
|
|
|
4
|
-
const globalNotifyDuration =
|
|
4
|
+
const globalNotifyDuration = vuelessConfig.component?.UNotify?.duration;
|
|
5
5
|
const notifyClearAllEvent = new Event("notifyClearAll");
|
|
6
6
|
|
|
7
7
|
let lastMessageTime = undefined;
|