vueless 0.0.477 → 0.0.478-beta.1
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/composables/useBreakpoint.js +1 -1
- package/composables/useUI.js +204 -1
- package/composablesTs/useAutoPosition.ts +115 -0
- package/composablesTs/useBreakpoint.ts +106 -0
- package/composablesTs/useLocale.ts +25 -0
- package/composablesTs/useMutationObserver.ts +50 -0
- package/composablesTs/useUI.ts +562 -0
- package/constants.js +2 -1
- package/constants.ts +73 -0
- package/directives/clickOutside/vClickOutside.js +2 -2
- package/directives/tooltip/storybook/stories.js +5 -5
- package/{index.js → index.ts} +10 -7
- package/package.json +28 -17
- package/preset.tailwind.js +16 -7
- package/types.ts +223 -0
- package/ui.button/config.js +12 -0
- package/ui.button-link/ULink.vue +1 -1
- package/ui.button-link/config.js +9 -0
- package/ui.data-list/UDataList.vue +4 -4
- package/ui.dropdown-badge/config.js +1 -0
- package/ui.dropdown-button/config.js +1 -0
- package/ui.form-checkbox/config.js +9 -0
- package/ui.form-color-picker/config.js +7 -0
- package/ui.form-input/UInput.vue +1 -1
- package/ui.form-input-money/useFormatCurrency.js +1 -1
- package/ui.form-input-number/UInputNumber.vue +4 -3
- package/ui.form-label/config.js +2 -2
- package/ui.form-radio/config.js +6 -0
- package/ui.form-switch/config.js +6 -0
- package/ui.image-avatar/config.js +5 -0
- package/ui.image-icon/config.js +5 -0
- package/ui.loader/config.js +1 -0
- package/ui.loader-overlay/config.js +1 -0
- package/ui.loader-progress/config.js +1 -0
- package/ui.navigation-progress/config.js +9 -0
- package/ui.other-dot/config.js +1 -0
- package/ui.text-alert/config.js +7 -0
- package/ui.text-badge/config.js +8 -0
- package/ui.text-block/UText.vue +18 -62
- package/ui.text-block/storybook/Docs.mdx +3 -3
- package/ui.text-block/storybook/{stories.js → stories.ts} +13 -8
- package/ui.text-block/types.ts +33 -0
- package/ui.text-block/useAttrs.ts +20 -0
- package/ui.text-file/UFile.vue +12 -14
- package/ui.text-file/config.js +12 -2
- package/ui.text-files/config.js +1 -1
- package/ui.text-header/config.js +1 -0
- package/ui.text-money/config.js +1 -0
- package/ui.text-money/utilMoney.js +2 -2
- package/utils/utilUI.js +0 -204
- package/utilsTs/utilHelper.ts +68 -0
- package/utilsTs/utilPlatform.ts +53 -0
- package/utilsTs/utilStorybook.ts +296 -0
- package/utilsTs/utilTailwind.ts +38 -0
- package/{utils/utilTheme.js → utilsTs/utilTheme.ts} +31 -27
- package/utilsTs/utilUI.ts +143 -0
- package/web-types.json +1 -1
- package/ui.text-block/useAttrs.js +0 -15
- /package/ui.text-block/{config.js → config.ts} +0 -0
- /package/ui.text-block/{constants.js → constants.ts} +0 -0
|
@@ -107,4 +107,13 @@ export default /*tw*/ {
|
|
|
107
107
|
variant: "progress",
|
|
108
108
|
indicator: false,
|
|
109
109
|
},
|
|
110
|
+
safelist: (colors) => [
|
|
111
|
+
{ pattern: `text-(${colors})-600` },
|
|
112
|
+
{ pattern: `text-(${colors})-100` },
|
|
113
|
+
{ pattern: `stroke-(${colors})-100` },
|
|
114
|
+
{
|
|
115
|
+
pattern: `bg-(${colors})-50`,
|
|
116
|
+
variants: ["[&::-webkit-progress-bar]", "[@supports(selector(&::-moz-progress-bar))]"],
|
|
117
|
+
},
|
|
118
|
+
],
|
|
110
119
|
};
|
package/ui.other-dot/config.js
CHANGED
package/ui.text-alert/config.js
CHANGED
|
@@ -54,4 +54,11 @@ export default /*tw*/ {
|
|
|
54
54
|
/* icons */
|
|
55
55
|
closeIcon: "close",
|
|
56
56
|
},
|
|
57
|
+
safelist: (colors) => [
|
|
58
|
+
{ pattern: `bg-(${colors})-50` },
|
|
59
|
+
{ pattern: `bg-(${colors})-600` },
|
|
60
|
+
{ pattern: `text-(${colors})-600` },
|
|
61
|
+
{ pattern: `border-(${colors})-100` },
|
|
62
|
+
{ pattern: `border-(${colors})-600` },
|
|
63
|
+
],
|
|
57
64
|
};
|
package/ui.text-badge/config.js
CHANGED
|
@@ -63,4 +63,12 @@ export default /*tw*/ {
|
|
|
63
63
|
round: false,
|
|
64
64
|
bordered: false,
|
|
65
65
|
},
|
|
66
|
+
safelist: (colors) => [
|
|
67
|
+
{ pattern: `bg-(${colors})-50` },
|
|
68
|
+
{ pattern: `bg-(${colors})-600` },
|
|
69
|
+
{ pattern: `border-(${colors})-100` },
|
|
70
|
+
{ pattern: `border-(${colors})-600` },
|
|
71
|
+
{ pattern: `text-(${colors})-600` },
|
|
72
|
+
{ pattern: `ring-(${colors})-700`, variants: ["focus", "focus-within"] },
|
|
73
|
+
],
|
|
66
74
|
};
|
package/ui.text-block/UText.vue
CHANGED
|
@@ -1,71 +1,27 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
<!-- @slot Use it to add something inside. -->
|
|
4
|
-
<div v-if="!hasSlotContent($slots['default'])" v-bind="htmlAttrs" v-html="html" />
|
|
5
|
-
<slot />
|
|
6
|
-
</div>
|
|
7
|
-
</template>
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { getDefault } from "../utilsTs/utilUI.ts";
|
|
8
3
|
|
|
9
|
-
|
|
10
|
-
import
|
|
4
|
+
import { UText } from "./constants.ts";
|
|
5
|
+
import defaultConfig from "./config.ts";
|
|
6
|
+
import useAttrs from "./useAttrs.ts";
|
|
11
7
|
|
|
12
|
-
import {
|
|
13
|
-
import defaultConfig from "./config.js";
|
|
14
|
-
import useAttrs from "./useAttrs.js";
|
|
8
|
+
import type { UTextProps } from "./types.ts";
|
|
15
9
|
|
|
16
10
|
defineOptions({ inheritAttrs: false });
|
|
17
11
|
|
|
18
|
-
const props = defineProps({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
html: {
|
|
23
|
-
type: String,
|
|
24
|
-
default: undefined,
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Text size.
|
|
29
|
-
* @values sm, md, lg
|
|
30
|
-
*/
|
|
31
|
-
size: {
|
|
32
|
-
type: String,
|
|
33
|
-
default: getDefault(defaultConfig, UText).size,
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Text align.
|
|
38
|
-
* @values left, center, right
|
|
39
|
-
*/
|
|
40
|
-
align: {
|
|
41
|
-
type: String,
|
|
42
|
-
default: getDefault(defaultConfig, UText).align,
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Remove line height (useful for 1-line text).
|
|
47
|
-
*/
|
|
48
|
-
line: {
|
|
49
|
-
type: Boolean,
|
|
50
|
-
default: getDefault(defaultConfig, UText).line,
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Component config object.
|
|
55
|
-
*/
|
|
56
|
-
config: {
|
|
57
|
-
type: Object,
|
|
58
|
-
default: () => ({}),
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Data-test attribute for automated testing.
|
|
63
|
-
*/
|
|
64
|
-
dataTest: {
|
|
65
|
-
type: String,
|
|
66
|
-
default: "",
|
|
67
|
-
},
|
|
12
|
+
const props = withDefaults(defineProps<UTextProps>(), {
|
|
13
|
+
size: getDefault<UTextProps>(defaultConfig, UText).size,
|
|
14
|
+
align: getDefault<UTextProps>(defaultConfig, UText).align,
|
|
15
|
+
line: getDefault<UTextProps>(defaultConfig, UText).line,
|
|
68
16
|
});
|
|
69
17
|
|
|
70
18
|
const { wrapperAttrs, htmlAttrs, hasSlotContent } = useAttrs(props);
|
|
71
19
|
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<div v-bind="wrapperAttrs" :data-test="dataTest">
|
|
23
|
+
<!-- @slot Use it to add something inside. -->
|
|
24
|
+
<div v-if="!hasSlotContent($slots['default'])" v-bind="htmlAttrs" v-html="html" />
|
|
25
|
+
<slot />
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
|
|
2
|
-
import { getSource } from "../../
|
|
2
|
+
import { getSource } from "../../utilsTs/utilStorybook.ts";
|
|
3
3
|
|
|
4
|
-
import * as stories from "./stories.
|
|
5
|
-
import defaultConfig from "../config.
|
|
4
|
+
import * as stories from "./stories.ts";
|
|
5
|
+
import defaultConfig from "../config.ts?raw"
|
|
6
6
|
|
|
7
7
|
<Meta of={stories} />
|
|
8
8
|
<Title of={stories} />
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Meta, StoryFn } from "@storybook/vue3";
|
|
2
|
+
import { getArgTypes, getSlotNames, getSlotsFragment } from "../../utilsTs/utilStorybook.ts";
|
|
2
3
|
|
|
3
4
|
import UText from "../../ui.text-block/UText.vue";
|
|
4
5
|
import URow from "../../ui.container-row/URow.vue";
|
|
5
6
|
|
|
7
|
+
import type { UTextProps } from "../types.ts";
|
|
8
|
+
|
|
9
|
+
interface UTextArgs extends UTextProps {
|
|
10
|
+
slotTemplate?: string;
|
|
11
|
+
enum: "size";
|
|
12
|
+
}
|
|
13
|
+
|
|
6
14
|
/**
|
|
7
15
|
* The `UText` component. | [View on GitHub](https://github.com/vuelessjs/vueless/tree/main/src/ui.text-block)
|
|
8
16
|
*/
|
|
@@ -14,7 +22,7 @@ export default {
|
|
|
14
22
|
...getArgTypes(UText.__name),
|
|
15
23
|
},
|
|
16
24
|
args: {},
|
|
17
|
-
};
|
|
25
|
+
} as Meta;
|
|
18
26
|
|
|
19
27
|
const defaultTemplate = `
|
|
20
28
|
<p>
|
|
@@ -24,7 +32,7 @@ const defaultTemplate = `
|
|
|
24
32
|
</p>
|
|
25
33
|
`;
|
|
26
34
|
|
|
27
|
-
const DefaultTemplate = (args) => ({
|
|
35
|
+
const DefaultTemplate: StoryFn<UTextArgs> = (args) => ({
|
|
28
36
|
components: { UText, URow },
|
|
29
37
|
setup() {
|
|
30
38
|
const slots = getSlotNames(UText.__name);
|
|
@@ -38,12 +46,12 @@ const DefaultTemplate = (args) => ({
|
|
|
38
46
|
`,
|
|
39
47
|
});
|
|
40
48
|
|
|
41
|
-
const EnumVariantTemplate = (args, { argTypes }
|
|
49
|
+
const EnumVariantTemplate: StoryFn<UTextArgs> = (args, { argTypes }) => ({
|
|
42
50
|
components: { UText, URow },
|
|
43
51
|
setup() {
|
|
44
52
|
return {
|
|
45
53
|
args,
|
|
46
|
-
options: argTypes[args.enum]
|
|
54
|
+
options: argTypes?.[args.enum]?.options || [],
|
|
47
55
|
};
|
|
48
56
|
},
|
|
49
57
|
template: `
|
|
@@ -88,7 +96,6 @@ Paragraphs.args = {
|
|
|
88
96
|
rapidly changing landscape and emerge stronger and more competitive.
|
|
89
97
|
</p>
|
|
90
98
|
</template>
|
|
91
|
-
|
|
92
99
|
`,
|
|
93
100
|
};
|
|
94
101
|
|
|
@@ -102,8 +109,6 @@ List.args = {
|
|
|
102
109
|
<li>Update your profile information</li>
|
|
103
110
|
<li>Check your email for updates</li>
|
|
104
111
|
</ul>
|
|
105
|
-
|
|
106
|
-
|
|
107
112
|
<ol>
|
|
108
113
|
<li>Create an account by signing up</li>
|
|
109
114
|
<li>Verify your email address</li>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import defaultConfig from "./config.ts";
|
|
2
|
+
|
|
3
|
+
export interface UTextProps {
|
|
4
|
+
/**
|
|
5
|
+
* HTML markdown or plain text.
|
|
6
|
+
*/
|
|
7
|
+
html?: string;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Text size.
|
|
11
|
+
*/
|
|
12
|
+
size?: "sm" | "md" | "lg";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Text align.
|
|
16
|
+
*/
|
|
17
|
+
align?: "left" | "center" | "right";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Remove line height (useful for 1-line text).
|
|
21
|
+
*/
|
|
22
|
+
line?: boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Component config object.
|
|
26
|
+
*/
|
|
27
|
+
config?: Partial<typeof defaultConfig>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Data-test attribute for automated testing.
|
|
31
|
+
*/
|
|
32
|
+
dataTest?: string;
|
|
33
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import useUI from "../composablesTs/useUI.ts";
|
|
2
|
+
|
|
3
|
+
import defaultConfig from "./config.ts";
|
|
4
|
+
|
|
5
|
+
import type { UseAttrs } from "../types.ts";
|
|
6
|
+
import type { UTextProps } from "./types.ts";
|
|
7
|
+
|
|
8
|
+
type Config = Partial<typeof defaultConfig>;
|
|
9
|
+
|
|
10
|
+
export default function useAttrs(props: UTextProps): UseAttrs {
|
|
11
|
+
const { config, getKeysAttrs, hasSlotContent } = useUI<Config>(defaultConfig, () => props.config);
|
|
12
|
+
|
|
13
|
+
const keysAttrs = getKeysAttrs();
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
config,
|
|
17
|
+
...keysAttrs,
|
|
18
|
+
hasSlotContent,
|
|
19
|
+
};
|
|
20
|
+
}
|
package/ui.text-file/UFile.vue
CHANGED
|
@@ -23,16 +23,14 @@
|
|
|
23
23
|
</slot>
|
|
24
24
|
|
|
25
25
|
<slot name="right" :file="{ elementId, label, url, imageUrl }">
|
|
26
|
-
<
|
|
26
|
+
<UIcon
|
|
27
27
|
v-if="removable"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
:icon="config.defaults.removeIcon"
|
|
35
|
-
v-bind="removeButtonAttrs"
|
|
28
|
+
internal
|
|
29
|
+
interactive
|
|
30
|
+
color="gray"
|
|
31
|
+
:size="removeIconSize"
|
|
32
|
+
:name="config.defaults.removeIcon"
|
|
33
|
+
v-bind="removeIconAttrs"
|
|
36
34
|
:data-test="`${dataTest}-remove-item`"
|
|
37
35
|
@click.stop.prevent="onRemove"
|
|
38
36
|
/>
|
|
@@ -141,20 +139,20 @@ const {
|
|
|
141
139
|
fileIconAttrs,
|
|
142
140
|
fileLabelAttrs,
|
|
143
141
|
fileImageAttrs,
|
|
144
|
-
|
|
142
|
+
removeIconAttrs,
|
|
145
143
|
} = useAttrs(props);
|
|
146
144
|
|
|
147
145
|
const iconSize = computed(() => {
|
|
148
146
|
const sizes = {
|
|
149
|
-
sm: "
|
|
150
|
-
md: "
|
|
151
|
-
lg: "
|
|
147
|
+
sm: "xs",
|
|
148
|
+
md: "sm",
|
|
149
|
+
lg: "md",
|
|
152
150
|
};
|
|
153
151
|
|
|
154
152
|
return sizes[props.size];
|
|
155
153
|
});
|
|
156
154
|
|
|
157
|
-
const
|
|
155
|
+
const removeIconSize = computed(() => {
|
|
158
156
|
const sizes = {
|
|
159
157
|
sm: "2xs",
|
|
160
158
|
md: "xs",
|
package/ui.text-file/config.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
file:
|
|
2
|
+
file: {
|
|
3
|
+
component: "{ULink}",
|
|
4
|
+
base: "flex items-center",
|
|
5
|
+
variants: {
|
|
6
|
+
size: {
|
|
7
|
+
sm: "gap-0.5",
|
|
8
|
+
md: "gap-1",
|
|
9
|
+
lg: "gap-1.5",
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
3
13
|
body: {
|
|
4
14
|
base: "flex items-center",
|
|
5
15
|
variants: {
|
|
@@ -13,7 +23,7 @@ export default /*tw*/ {
|
|
|
13
23
|
fileImage: "rounded-sm max-w-7",
|
|
14
24
|
fileIcon: "{UIcon}",
|
|
15
25
|
fileLabel: "{ULink}",
|
|
16
|
-
|
|
26
|
+
removeIcon: "{UIcon}",
|
|
17
27
|
defaults: {
|
|
18
28
|
size: "md",
|
|
19
29
|
/* icons */
|
package/ui.text-files/config.js
CHANGED
package/ui.text-header/config.js
CHANGED
package/ui.text-money/config.js
CHANGED
|
@@ -16,8 +16,8 @@ export function separatedMoney(
|
|
|
16
16
|
thousandsSeparator = " ",
|
|
17
17
|
) {
|
|
18
18
|
const options = {
|
|
19
|
-
minimumFractionDigits: minFractionDigits,
|
|
20
|
-
maximumFractionDigits: maxFractionDigits,
|
|
19
|
+
minimumFractionDigits: Number(minFractionDigits),
|
|
20
|
+
maximumFractionDigits: Number(maxFractionDigits),
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const formattedMoney =
|
package/utils/utilUI.js
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
GRAYSCALE_COLOR,
|
|
8
8
|
DEFAULT_BRAND_COLOR,
|
|
9
9
|
NESTED_COMPONENT_REG_EXP,
|
|
10
|
-
SYSTEM_CONFIG_KEY,
|
|
11
10
|
} from "../constants.js";
|
|
12
11
|
|
|
13
12
|
/**
|
|
@@ -41,209 +40,6 @@ if (isCSR) {
|
|
|
41
40
|
)[0] || {};
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
/**
|
|
45
|
-
* Recursively merge config objects with removing tailwind classes duplicates.
|
|
46
|
-
* @param {Object} defaultConfig
|
|
47
|
-
* @param {Object} globalConfig
|
|
48
|
-
* @param {Object} propsConfig
|
|
49
|
-
* @param {Object} config - final merged config.
|
|
50
|
-
* @param {boolean} isReplace - enables class replacement instead of merge.
|
|
51
|
-
* @param {boolean} isVarinants - if true, prevents adding a "base" key into nested objects.
|
|
52
|
-
*
|
|
53
|
-
* @returns {Object}
|
|
54
|
-
*/
|
|
55
|
-
export function mergeConfigs({
|
|
56
|
-
defaultConfig,
|
|
57
|
-
globalConfig,
|
|
58
|
-
propsConfig,
|
|
59
|
-
config = {},
|
|
60
|
-
isReplace = false,
|
|
61
|
-
isVariants = false,
|
|
62
|
-
}) {
|
|
63
|
-
globalConfig = cloneDeep(globalConfig || {});
|
|
64
|
-
propsConfig = cloneDeep(propsConfig || {});
|
|
65
|
-
|
|
66
|
-
const isGlobalConfig = Object.keys(globalConfig).length;
|
|
67
|
-
const isPropsConfig = Object.keys(propsConfig).length;
|
|
68
|
-
|
|
69
|
-
// Add unique keys from defaultConfig to composedConfig
|
|
70
|
-
let composedConfig = cloneDeep(defaultConfig);
|
|
71
|
-
|
|
72
|
-
// Add unique keys from globalConfig to composedConfig
|
|
73
|
-
for (let key in globalConfig) {
|
|
74
|
-
if (!Object.keys(composedConfig).includes(key)) {
|
|
75
|
-
composedConfig[key] = globalConfig[key];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Add unique keys from propsConfig to composedConfig
|
|
80
|
-
for (let key in propsConfig) {
|
|
81
|
-
if (!Object.keys(composedConfig).includes(key)) {
|
|
82
|
-
composedConfig[key] = propsConfig[key];
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const {
|
|
87
|
-
i18n,
|
|
88
|
-
defaults,
|
|
89
|
-
strategy,
|
|
90
|
-
safelist,
|
|
91
|
-
component,
|
|
92
|
-
safelistColors,
|
|
93
|
-
defaultVariants,
|
|
94
|
-
compoundVariants,
|
|
95
|
-
} = SYSTEM_CONFIG_KEY;
|
|
96
|
-
|
|
97
|
-
for (let key in composedConfig) {
|
|
98
|
-
if (isGlobalConfig || isPropsConfig) {
|
|
99
|
-
if (key === safelist || key === safelistColors) {
|
|
100
|
-
if (propsConfig[key]) {
|
|
101
|
-
// eslint-disable-next-line no-console
|
|
102
|
-
console.warn(`Passing '${key}' key in 'config' prop is not allowed.`);
|
|
103
|
-
}
|
|
104
|
-
} else if (key === component) {
|
|
105
|
-
config[key] = propsConfig[key] || defaultConfig[key];
|
|
106
|
-
|
|
107
|
-
if (globalConfig[key]) {
|
|
108
|
-
// eslint-disable-next-line no-console
|
|
109
|
-
console.warn(`Passing '${key}' key in 'config' prop or by global config is not allowed.`);
|
|
110
|
-
}
|
|
111
|
-
} else if (key === strategy) {
|
|
112
|
-
config[key] = propsConfig[key] || globalConfig[key] || defaultConfig[key];
|
|
113
|
-
} else if (key === defaults || key === defaultVariants) {
|
|
114
|
-
config[key] = { ...defaultConfig[key], ...globalConfig[key], ...propsConfig[key] };
|
|
115
|
-
} else if (key === compoundVariants) {
|
|
116
|
-
config[key] = mergeCompoundVariants({
|
|
117
|
-
defaultConfig: composedConfig,
|
|
118
|
-
globalConfig,
|
|
119
|
-
propsConfig,
|
|
120
|
-
isReplace,
|
|
121
|
-
key,
|
|
122
|
-
});
|
|
123
|
-
} else {
|
|
124
|
-
const isObjectComposedConfig = typeof composedConfig[key] === "object";
|
|
125
|
-
const isObjectGlobalConfig = typeof globalConfig[key] === "object";
|
|
126
|
-
const isObjectPropsConfig = typeof propsConfig[key] === "object";
|
|
127
|
-
|
|
128
|
-
const isObject = isObjectComposedConfig || isObjectGlobalConfig || isObjectPropsConfig;
|
|
129
|
-
const isEmpty = composedConfig[key] === null;
|
|
130
|
-
const isI18n = key === i18n;
|
|
131
|
-
|
|
132
|
-
if (key === "variants" && !isVariants) {
|
|
133
|
-
isVariants = true;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
config[key] =
|
|
137
|
-
isObject && !isEmpty && !isI18n
|
|
138
|
-
? mergeConfigs({
|
|
139
|
-
defaultConfig: stringToObject(composedConfig[key], { addBase: !isVariants }),
|
|
140
|
-
globalConfig: stringToObject(globalConfig[key], { addBase: !isVariants }),
|
|
141
|
-
propsConfig: stringToObject(propsConfig[key], { addBase: !isVariants }),
|
|
142
|
-
config: stringToObject(composedConfig[key], { addBase: !isVariants }),
|
|
143
|
-
isReplace,
|
|
144
|
-
isVariants,
|
|
145
|
-
})
|
|
146
|
-
: isReplace || isI18n
|
|
147
|
-
? propsConfig[key] || globalConfig[key] || defaultConfig[key]
|
|
148
|
-
: cx([defaultConfig[key], globalConfig[key], propsConfig[key]]);
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
config[key] = composedConfig[key];
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return config;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
Turn simplified nested component config to regular config.
|
|
160
|
-
@param {Object | String} value
|
|
161
|
-
@param {Boolean} addBase
|
|
162
|
-
@returns {Object}
|
|
163
|
-
*/
|
|
164
|
-
function stringToObject(value, { addBase = false }) {
|
|
165
|
-
if (value === undefined) value = "";
|
|
166
|
-
|
|
167
|
-
return typeof value !== "object" ? addBase && { base: value } : value;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Merge CVA compound variants arrays.
|
|
172
|
-
* @param {Object} defaultConfig
|
|
173
|
-
* @param {Object} globalConfig
|
|
174
|
-
* @param {Object} propsConfig
|
|
175
|
-
* @param {string} key
|
|
176
|
-
* @param {boolean} isReplace - enables class replacement instead of merge.
|
|
177
|
-
*
|
|
178
|
-
* @returns {Array}
|
|
179
|
-
*/
|
|
180
|
-
function mergeCompoundVariants({ defaultConfig, globalConfig, propsConfig, key, isReplace }) {
|
|
181
|
-
if (
|
|
182
|
-
(globalConfig[key] && !Array.isArray(globalConfig[key])) ||
|
|
183
|
-
(propsConfig[key] && !Array.isArray(propsConfig[key])) ||
|
|
184
|
-
(defaultConfig[key] && !Array.isArray(defaultConfig[key]))
|
|
185
|
-
) {
|
|
186
|
-
// eslint-disable-next-line no-console
|
|
187
|
-
console.error("CompoundVariants should be an array.");
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
let globalConfigUniqueItems = cloneDeep(globalConfig[key] || []);
|
|
191
|
-
let propsConfigUniqueItems = cloneDeep(propsConfig[key] || []);
|
|
192
|
-
|
|
193
|
-
const config = defaultConfig[key].map((defaultConfigItem) => {
|
|
194
|
-
/**
|
|
195
|
-
* Compare two objects by keys for match.
|
|
196
|
-
* @param {Object} configItem
|
|
197
|
-
* @returns {Boolean}
|
|
198
|
-
*/
|
|
199
|
-
function isSameItem(configItem) {
|
|
200
|
-
const hasConfigItemKeys = Object.keys(defaultConfigItem)
|
|
201
|
-
.map((key) => defaultConfigItem[key] === configItem[key] || key === "class")
|
|
202
|
-
.every((item) => !!item);
|
|
203
|
-
|
|
204
|
-
const hasDefaultConfigItemKeys = Object.keys(configItem)
|
|
205
|
-
.map((key) => defaultConfigItem[key] === configItem[key] || key === "class")
|
|
206
|
-
.every((item) => !!item);
|
|
207
|
-
|
|
208
|
-
return hasConfigItemKeys && hasDefaultConfigItemKeys;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Find the same compound variant item in custom config if exist.
|
|
213
|
-
* @param {Object} config
|
|
214
|
-
* @returns {Object|undefined}
|
|
215
|
-
*/
|
|
216
|
-
function findItem(config = []) {
|
|
217
|
-
const globalConfigUniqueItemIndex = globalConfigUniqueItems.findIndex(isSameItem);
|
|
218
|
-
const propsConfigUniqueItemIndex = propsConfigUniqueItems.findIndex(isSameItem);
|
|
219
|
-
|
|
220
|
-
if (~globalConfigUniqueItemIndex) {
|
|
221
|
-
globalConfigUniqueItems.splice(globalConfigUniqueItemIndex, 1);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (~propsConfigUniqueItemIndex) {
|
|
225
|
-
propsConfigUniqueItems.splice(propsConfigUniqueItemIndex, 1);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return config.find(isSameItem);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const globalConfigItem = findItem(globalConfig[key]);
|
|
232
|
-
const propsConfigItem = findItem(propsConfig[key]);
|
|
233
|
-
|
|
234
|
-
return globalConfigItem || propsConfigItem
|
|
235
|
-
? {
|
|
236
|
-
...defaultConfigItem,
|
|
237
|
-
class: isReplace
|
|
238
|
-
? propsConfigItem?.class || globalConfigItem?.class || defaultConfigItem.class
|
|
239
|
-
: cx([defaultConfigItem.class, globalConfigItem?.class, propsConfigItem?.class]),
|
|
240
|
-
}
|
|
241
|
-
: defaultConfigItem;
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
return [...config, ...globalConfigUniqueItems, ...propsConfigUniqueItems];
|
|
245
|
-
}
|
|
246
|
-
|
|
247
43
|
/**
|
|
248
44
|
* Extend twMerge (tailwind merge) by vueless and user config:
|
|
249
45
|
* All list of rules available here:
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deeply clone given object (same as lodash.cloneDeep).
|
|
3
|
+
*/
|
|
4
|
+
export function cloneDeep(entity: unknown, cache = new WeakMap()): unknown {
|
|
5
|
+
// primitives
|
|
6
|
+
if (Object(entity) !== entity || !entity) {
|
|
7
|
+
return entity;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// cyclic reference
|
|
11
|
+
if (cache.has(entity)) {
|
|
12
|
+
return cache.get(entity);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const result =
|
|
16
|
+
entity instanceof Set
|
|
17
|
+
? new Set(entity)
|
|
18
|
+
: entity instanceof Map
|
|
19
|
+
? new Map(Array.from(entity, ([key, val]) => [key, cloneDeep(val, cache)]))
|
|
20
|
+
: entity instanceof Date
|
|
21
|
+
? new Date(entity)
|
|
22
|
+
: entity instanceof RegExp
|
|
23
|
+
? new RegExp(entity.source, entity.flags)
|
|
24
|
+
: entity.constructor
|
|
25
|
+
? new (entity.constructor as { new (): typeof entity })()
|
|
26
|
+
: Object.create(null);
|
|
27
|
+
|
|
28
|
+
cache.set(entity, result);
|
|
29
|
+
|
|
30
|
+
return Object.assign(
|
|
31
|
+
result,
|
|
32
|
+
...Object.keys(entity).map((key) => ({
|
|
33
|
+
[key]: cloneDeep((entity as Record<string | number, unknown>)[key], cache),
|
|
34
|
+
})),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates a debounced function with delay (same as lodash.debounce).
|
|
40
|
+
*/
|
|
41
|
+
export function createDebounce(func: () => void, ms: number) {
|
|
42
|
+
let timeout: ReturnType<typeof setTimeout>;
|
|
43
|
+
|
|
44
|
+
return function (...args: []) {
|
|
45
|
+
clearTimeout(timeout);
|
|
46
|
+
// @ts-expect-error - this implicitly has type any because it does not have a type annotation.
|
|
47
|
+
timeout = setTimeout(() => func.apply(this as unknown, args), ms);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Change page title in runtime by provided config.
|
|
53
|
+
*/
|
|
54
|
+
export function setTitle({ title = "", separator = " / ", suffix = "" }) {
|
|
55
|
+
if (isCSR) {
|
|
56
|
+
document.title = title ? title + separator + suffix : suffix;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check is code rendering on the server side.
|
|
62
|
+
*/
|
|
63
|
+
export const isSSR: boolean = typeof window === "undefined";
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Check is code rendering on the client side.
|
|
67
|
+
*/
|
|
68
|
+
export const isCSR: boolean = typeof window !== "undefined";
|