vueless 1.2.8-beta.9 → 1.2.9
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/constants.d.ts +1 -0
- package/constants.js +1 -0
- package/index.d.ts +3 -1
- package/index.ts +3 -1
- package/package.json +9 -5
- package/plugin-vite.js +6 -1
- package/types.ts +14 -2
- package/ui.button/config.ts +4 -4
- package/ui.button/tests/UButton.test.ts +3 -3
- package/ui.button-toggle/config.ts +2 -2
- package/ui.container-card/config.ts +1 -1
- package/ui.data-table/config.ts +4 -4
- package/ui.dropdown-badge/UDropdownBadge.vue +17 -1
- package/ui.dropdown-button/UDropdownButton.vue +18 -4
- package/ui.dropdown-link/UDropdownLink.vue +18 -4
- package/ui.form-calendar/config.ts +4 -2
- package/ui.form-checkbox/config.ts +1 -1
- package/ui.form-date-picker-range/config.ts +1 -1
- package/ui.form-input/config.ts +1 -1
- package/ui.form-input-counter/UInputCounter.vue +1 -1
- package/ui.form-input-counter/config.ts +1 -1
- package/ui.form-listbox/UListbox.vue +1 -5
- package/ui.form-listbox/config.ts +1 -1
- package/ui.form-radio/config.ts +1 -1
- package/ui.form-select/USelect.vue +1 -0
- package/ui.form-select/config.ts +1 -1
- package/ui.form-textarea/config.ts +1 -1
- package/ui.text-alert/config.ts +1 -1
- package/ui.text-badge/config.ts +1 -1
- package/utils/helper.ts +4 -0
- package/utils/node/dynamicProps.d.ts +5 -2
- package/utils/node/dynamicProps.js +126 -53
- package/utils/node/helper.d.ts +10 -7
- package/utils/node/helper.js +59 -2
- package/utils/node/tailwindSafelist.js +9 -2
- package/utils/theme.ts +14 -26
- package/utils/ui.ts +32 -3
package/constants.d.ts
CHANGED
package/constants.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export {
|
|
|
17
17
|
} from "./utils/helper";
|
|
18
18
|
export { isMac, isPWA, isIOS, isAndroid, isMobileApp, isWindows } from "./utils/platform";
|
|
19
19
|
export { cx, cva, compose, getDefaults, setVuelessConfig, setColor, vuelessConfig } from "./utils/ui";
|
|
20
|
-
export { getTheme, setTheme, resetTheme, normalizeThemeConfig, cssVar } from "./utils/theme";
|
|
20
|
+
export { getTheme, setTheme, resetTheme, normalizeThemeConfig, cssVar, setRootCSSVariables } from "./utils/theme";
|
|
21
21
|
export { getArgs, getArgTypes, getSlotNames, getSlotsFragment, getSource, getDocsDescription } from "./utils/storybook";
|
|
22
22
|
/* adapters */
|
|
23
23
|
export { default as defaultEnLocale } from "./adapter.locale/locales/en";
|
|
@@ -140,6 +140,8 @@ export type {
|
|
|
140
140
|
NestedComponent,
|
|
141
141
|
ComponentConfig,
|
|
142
142
|
ComponentDefaults,
|
|
143
|
+
ComponentCustomProp,
|
|
144
|
+
ComponentCustomProps,
|
|
143
145
|
CreateVuelessOptions,
|
|
144
146
|
/* Color and theme types */
|
|
145
147
|
StateColors,
|
package/index.ts
CHANGED
|
@@ -23,7 +23,7 @@ export {
|
|
|
23
23
|
} from "./utils/helper";
|
|
24
24
|
export { isMac, isPWA, isIOS, isAndroid, isMobileApp, isWindows } from "./utils/platform";
|
|
25
25
|
export { cx, cva, compose, getDefaults, setVuelessConfig, setColor, vuelessConfig } from "./utils/ui";
|
|
26
|
-
export { getTheme, setTheme, resetTheme, normalizeThemeConfig, cssVar } from "./utils/theme";
|
|
26
|
+
export { getTheme, setTheme, resetTheme, normalizeThemeConfig, cssVar, setRootCSSVariables } from "./utils/theme";
|
|
27
27
|
export { getArgs, getArgTypes, getSlotNames, getSlotsFragment, getSource, getDocsDescription } from "./utils/storybook";
|
|
28
28
|
/* adapters */
|
|
29
29
|
export { default as defaultEnLocale } from "./adapter.locale/locales/en";
|
|
@@ -146,6 +146,8 @@ export type {
|
|
|
146
146
|
NestedComponent,
|
|
147
147
|
ComponentConfig,
|
|
148
148
|
ComponentDefaults,
|
|
149
|
+
ComponentCustomProp,
|
|
150
|
+
ComponentCustomProps,
|
|
149
151
|
CreateVuelessOptions,
|
|
150
152
|
/* Color and theme types */
|
|
151
153
|
StateColors,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueless",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
|
|
5
5
|
"author": "Johnny Grid <hello@vueless.com> (https://vueless.com)",
|
|
6
6
|
"homepage": "https://vueless.com",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"release:icons": "npx node .scripts/icons",
|
|
19
19
|
"release:types": "rm -f ./node_modules/.tmp/tsconfig.app.tsbuildinfo && npx tsc --project tsconfig.build.json",
|
|
20
20
|
"release:prepare": "npm run release:icons && rm -rf dist && mkdir -p dist && cp -r src/. package.json LICENSE README.md dist/ && npx node .scripts/writeLocales && npm run release:types",
|
|
21
|
-
"release:beta": "release-it --
|
|
22
|
-
"release:patch": "release-it patch --ci
|
|
23
|
-
"release:minor": "release-it minor --ci
|
|
24
|
-
"release:major": "release-it major --ci
|
|
21
|
+
"release:beta": "release-it --increment=prerelease --preRelease=beta --ci --no-git.tag --no-github.release",
|
|
22
|
+
"release:patch": "release-it patch --ci",
|
|
23
|
+
"release:minor": "release-it minor --ci",
|
|
24
|
+
"release:major": "release-it major --ci",
|
|
25
25
|
"lint": "eslint --no-fix src/ test/ .storybook/ .vueless/ .scripts/",
|
|
26
26
|
"lint:fix": "eslint --fix src/ test/ .storybook/ .vueless/ .scripts/",
|
|
27
27
|
"lint:ci": "eslint --no-fix --max-warnings=0",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@material-symbols/svg-500": "^0.35.0",
|
|
49
49
|
"@release-it/bumper": "^7.0.5",
|
|
50
|
+
"@release-it/conventional-changelog": "^10.0.1",
|
|
50
51
|
"@tsconfig/node20": "^20.1.6",
|
|
51
52
|
"@types/jsdom": "^21.1.7",
|
|
52
53
|
"@types/node": "^24.1.0",
|
|
@@ -106,6 +107,9 @@
|
|
|
106
107
|
"types": "./modules.d.ts"
|
|
107
108
|
}
|
|
108
109
|
},
|
|
110
|
+
"overrides": {
|
|
111
|
+
"conventional-changelog-conventionalcommits": "8.0.0"
|
|
112
|
+
},
|
|
109
113
|
"resolutions": {
|
|
110
114
|
"jackspeak": "2.3.6"
|
|
111
115
|
},
|
package/plugin-vite.js
CHANGED
|
@@ -129,9 +129,14 @@ export const Vueless = function (options = {}) {
|
|
|
129
129
|
await cacheMergedConfigs({ vuelessSrcDir, basePath });
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
/* set custom prop types */
|
|
133
133
|
await setCustomPropTypes({ vuelessSrcDir, basePath });
|
|
134
134
|
|
|
135
|
+
/* build web-types.json with delay for right custom props behavior */
|
|
136
|
+
setTimeout(async () => {
|
|
137
|
+
await buildWebTypes({ vuelessSrcDir, basePath });
|
|
138
|
+
}, 2000);
|
|
139
|
+
|
|
135
140
|
/* collect used in project colors for tailwind safelist */
|
|
136
141
|
await createTailwindSafelist({ env, srcDir: vuelessSrcDir, targetFiles, basePath, debug });
|
|
137
142
|
|
package/types.ts
CHANGED
|
@@ -198,7 +198,7 @@ export type MergedThemeConfig = Omit<ThemeConfig, "text | outline | rounding"> &
|
|
|
198
198
|
|
|
199
199
|
export type UnknownObject = Record<string, unknown>;
|
|
200
200
|
export type UnknownArray = unknown[];
|
|
201
|
-
export type UnknownType = string | number | boolean | UnknownObject | undefined | null;
|
|
201
|
+
export type UnknownType = string | number | boolean | UnknownObject | undefined | null | unknown;
|
|
202
202
|
|
|
203
203
|
export type ComponentNames = keyof Components & string; // keys union
|
|
204
204
|
|
|
@@ -325,7 +325,19 @@ export interface NestedComponent {
|
|
|
325
325
|
|
|
326
326
|
export type ComponentDefaults = {
|
|
327
327
|
color?: string;
|
|
328
|
-
[key: string]:
|
|
328
|
+
[key: string]: UnknownType;
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
export type ComponentCustomProps = {
|
|
332
|
+
[key: string]: ComponentCustomProp;
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
export type ComponentCustomProp = {
|
|
336
|
+
required?: boolean;
|
|
337
|
+
ignore?: boolean;
|
|
338
|
+
values?: string[];
|
|
339
|
+
default?: UnknownType;
|
|
340
|
+
description?: string;
|
|
329
341
|
};
|
|
330
342
|
|
|
331
343
|
export interface CVA {
|
package/ui.button/config.ts
CHANGED
|
@@ -2,7 +2,7 @@ export default /*tw*/ {
|
|
|
2
2
|
button: {
|
|
3
3
|
base: `
|
|
4
4
|
flex items-center justify-center font-medium !leading-snug whitespace-nowrap
|
|
5
|
-
border border-
|
|
5
|
+
border border-solid transition cursor-pointer
|
|
6
6
|
focus-visible:outline-medium focus-visible:outline-offset-2 focus-visible:outline-{color}
|
|
7
7
|
disabled:cursor-not-allowed disabled:outline-0 disabled:outline-offset-0
|
|
8
8
|
`,
|
|
@@ -17,7 +17,7 @@ export default /*tw*/ {
|
|
|
17
17
|
},
|
|
18
18
|
variant: {
|
|
19
19
|
solid: `
|
|
20
|
-
|
|
20
|
+
bg-{color} border-transparent text-inverted
|
|
21
21
|
hover:bg-{color}-lifted
|
|
22
22
|
active:bg-{color}-accented
|
|
23
23
|
disabled:!bg-{color}/(--vl-disabled-opacity)
|
|
@@ -35,13 +35,13 @@ export default /*tw*/ {
|
|
|
35
35
|
disabled:!text-{color}/(--vl-disabled-opacity) disabled:!bg-{color}/5 disabled:!border-{color}/10
|
|
36
36
|
`,
|
|
37
37
|
soft: `
|
|
38
|
-
text-{color} bg-{color}/5
|
|
38
|
+
text-{color} bg-{color}/5 border-transparent
|
|
39
39
|
hover:text-{color}-lifted hover:bg-{color}-lifted/10
|
|
40
40
|
active:text-{color}-accented active:bg-{color}-accented/15
|
|
41
41
|
disabled:!text-{color}/(--vl-disabled-opacity) disabled:!bg-{color}/5
|
|
42
42
|
`,
|
|
43
43
|
ghost: `
|
|
44
|
-
text-{color} bg-transparent
|
|
44
|
+
text-{color} bg-transparent border-transparent
|
|
45
45
|
hover:text-{color}-lifted hover:bg-{color}-lifted/10
|
|
46
46
|
active:text-{color}-accented active:bg-{color}-accented/15
|
|
47
47
|
disabled:!text-{color}/(--vl-disabled-opacity) disabled:!bg-transparent
|
|
@@ -12,11 +12,11 @@ describe("UButton.vue", () => {
|
|
|
12
12
|
it("Variant – applies the correct variant class", async () => {
|
|
13
13
|
const color = "primary";
|
|
14
14
|
const variants = {
|
|
15
|
-
solid: "text-inverted
|
|
15
|
+
solid: "bg-primary border-transparent text-inverted",
|
|
16
16
|
outlined: "text-primary border-primary",
|
|
17
17
|
subtle: "text-primary bg-primary/5 border-primary/15",
|
|
18
|
-
soft: "text-primary bg-primary/5",
|
|
19
|
-
ghost: "text-primary bg-transparent",
|
|
18
|
+
soft: "text-primary bg-primary/5 border-transparent",
|
|
19
|
+
ghost: "text-primary bg-transparent border-transparent",
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
Object.entries(variants).forEach(([variant, classes]) => {
|
|
@@ -12,7 +12,7 @@ export default /*tw*/ {
|
|
|
12
12
|
},
|
|
13
13
|
split: {
|
|
14
14
|
true: "flex-wrap",
|
|
15
|
-
false: "flex-nowrap gap-px p-1 w-fit border rounded-medium border-default",
|
|
15
|
+
false: "flex-nowrap gap-px p-1 w-fit border border-solid rounded-medium border-default",
|
|
16
16
|
},
|
|
17
17
|
disabled: {
|
|
18
18
|
true: "bg-lifted cursor-not-allowed",
|
|
@@ -26,7 +26,7 @@ export default /*tw*/ {
|
|
|
26
26
|
},
|
|
27
27
|
},
|
|
28
28
|
divider: {
|
|
29
|
-
base: "my-1 border-r border-muted last:hidden",
|
|
29
|
+
base: "my-1 border-r border-solid border-muted last:hidden",
|
|
30
30
|
variants: {
|
|
31
31
|
split: {
|
|
32
32
|
true: "hidden",
|
package/ui.data-table/config.ts
CHANGED
|
@@ -2,7 +2,7 @@ export default /*tw*/ {
|
|
|
2
2
|
wrapper: "relative w-full overflow-auto",
|
|
3
3
|
headerCounterBase: "mr-1.5 pr-1.5 font-medium text-medium",
|
|
4
4
|
stickyHeader: {
|
|
5
|
-
base: "fixed top-0 flex items-center z-30 overflow-hidden border rounded-none",
|
|
5
|
+
base: "fixed top-0 flex items-center z-30 overflow-hidden border border-solid rounded-none",
|
|
6
6
|
variants: {
|
|
7
7
|
stickedHeader: {
|
|
8
8
|
false: "absolute",
|
|
@@ -29,12 +29,12 @@ export default /*tw*/ {
|
|
|
29
29
|
stickyHeaderLoader: "{ULoaderProgress} absolute top-auto bottom-0",
|
|
30
30
|
headerActionsCheckbox: "{UCheckbox}",
|
|
31
31
|
headerActionsCounter: "{>headerCounterBase} -ml-1.5",
|
|
32
|
-
tableWrapper: "border border-muted rounded-medium bg-default overflow-x-auto",
|
|
32
|
+
tableWrapper: "border border-solid border-muted rounded-medium bg-default overflow-x-auto",
|
|
33
33
|
table: "min-w-full border-none text-medium w-full table-auto",
|
|
34
34
|
header:
|
|
35
35
|
"border-b border-muted [&>tr:first-child>*]:first:rounded-tl-medium [&>tr:last-child>*]:last:rounded-tr-medium relative",
|
|
36
36
|
headerRow: "",
|
|
37
|
-
beforeHeaderRow: "border border-muted",
|
|
37
|
+
beforeHeaderRow: "border border-solid border-muted",
|
|
38
38
|
beforeHeaderCell: "{>headerCellBase}",
|
|
39
39
|
headerCellBase: {
|
|
40
40
|
base: "p-4 text-medium font-normal text-lifted text-left text-nowrap",
|
|
@@ -100,7 +100,7 @@ export default /*tw*/ {
|
|
|
100
100
|
},
|
|
101
101
|
},
|
|
102
102
|
stickyFooterRow: `
|
|
103
|
-
fixed bottom-0 -ml-px border border-
|
|
103
|
+
fixed bottom-0 -ml-px border-b border-solid border-muted bg-default
|
|
104
104
|
collapse group-[*]/footer-fixed:[visibility:inherit]
|
|
105
105
|
`,
|
|
106
106
|
i18n: {
|
|
@@ -66,6 +66,7 @@ const emit = defineEmits([
|
|
|
66
66
|
type UListboxRef = InstanceType<typeof UListbox>;
|
|
67
67
|
|
|
68
68
|
const isShownOptions = ref(false);
|
|
69
|
+
const isClickingOption = ref(false);
|
|
69
70
|
const listboxRef = useTemplateRef<UListboxRef>("dropdown-list");
|
|
70
71
|
const wrapperRef = useTemplateRef<HTMLDivElement>("wrapper");
|
|
71
72
|
|
|
@@ -157,14 +158,29 @@ function onClickBadge() {
|
|
|
157
158
|
|
|
158
159
|
function hideOptions() {
|
|
159
160
|
isShownOptions.value = false;
|
|
161
|
+
dropdownSearch.value = "";
|
|
160
162
|
|
|
161
163
|
emit("close");
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
function onClickOption(option: Option) {
|
|
167
|
+
isClickingOption.value = true;
|
|
168
|
+
|
|
165
169
|
emit("clickOption", option);
|
|
166
170
|
|
|
167
171
|
if (!props.multiple && props.closeOnSelect) hideOptions();
|
|
172
|
+
|
|
173
|
+
nextTick(() => {
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
isClickingOption.value = false;
|
|
176
|
+
}, 10);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function handleClickOutside() {
|
|
181
|
+
if (isClickingOption.value) return;
|
|
182
|
+
|
|
183
|
+
hideOptions();
|
|
168
184
|
}
|
|
169
185
|
|
|
170
186
|
defineExpose({
|
|
@@ -197,7 +213,7 @@ const { getDataTest, config, wrapperAttrs, dropdownBadgeAttrs, listboxAttrs, tog
|
|
|
197
213
|
<template>
|
|
198
214
|
<div
|
|
199
215
|
ref="wrapper"
|
|
200
|
-
v-click-outside="
|
|
216
|
+
v-click-outside="handleClickOutside"
|
|
201
217
|
v-bind="wrapperAttrs"
|
|
202
218
|
:data-test="getDataTest('wrapper')"
|
|
203
219
|
>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { nextTick, computed,
|
|
2
|
+
import { nextTick, computed, ref, useId, useTemplateRef } from "vue";
|
|
3
3
|
import { isEqual } from "lodash-es";
|
|
4
4
|
|
|
5
5
|
import useUI from "../composables/useUI";
|
|
@@ -63,11 +63,10 @@ const emit = defineEmits([
|
|
|
63
63
|
"update:search",
|
|
64
64
|
]);
|
|
65
65
|
|
|
66
|
-
provide("hideDropdownOptions", hideOptions);
|
|
67
|
-
|
|
68
66
|
type UListboxRef = InstanceType<typeof UListbox>;
|
|
69
67
|
|
|
70
68
|
const isShownOptions = ref(false);
|
|
69
|
+
const isClickingOption = ref(false);
|
|
71
70
|
const listboxRef = useTemplateRef<UListboxRef>("dropdown-list");
|
|
72
71
|
const wrapperRef = useTemplateRef<HTMLDivElement>("wrapper");
|
|
73
72
|
|
|
@@ -148,9 +147,23 @@ function getFullOptionLabels(value: Option | Option[]) {
|
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
function onClickOption(option: Option) {
|
|
150
|
+
isClickingOption.value = true;
|
|
151
|
+
|
|
151
152
|
emit("clickOption", option);
|
|
152
153
|
|
|
153
154
|
if (!props.multiple && props.closeOnSelect) hideOptions();
|
|
155
|
+
|
|
156
|
+
nextTick(() => {
|
|
157
|
+
setTimeout(() => {
|
|
158
|
+
isClickingOption.value = false;
|
|
159
|
+
}, 10);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function handleClickOutside() {
|
|
164
|
+
if (isClickingOption.value) return;
|
|
165
|
+
|
|
166
|
+
hideOptions();
|
|
154
167
|
}
|
|
155
168
|
|
|
156
169
|
function onClickButton() {
|
|
@@ -165,6 +178,7 @@ function onClickButton() {
|
|
|
165
178
|
|
|
166
179
|
function hideOptions() {
|
|
167
180
|
isShownOptions.value = false;
|
|
181
|
+
dropdownSearch.value = "";
|
|
168
182
|
|
|
169
183
|
emit("close");
|
|
170
184
|
}
|
|
@@ -199,7 +213,7 @@ const { getDataTest, config, dropdownButtonAttrs, listboxAttrs, toggleIconAttrs,
|
|
|
199
213
|
<template>
|
|
200
214
|
<div
|
|
201
215
|
ref="wrapper"
|
|
202
|
-
v-click-outside="
|
|
216
|
+
v-click-outside="handleClickOutside"
|
|
203
217
|
v-bind="wrapperAttrs"
|
|
204
218
|
:data-test="getDataTest('wrapper')"
|
|
205
219
|
>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { nextTick, computed,
|
|
2
|
+
import { nextTick, computed, ref, useId, useTemplateRef } from "vue";
|
|
3
3
|
import { isEqual } from "lodash-es";
|
|
4
4
|
|
|
5
5
|
import useUI from "../composables/useUI";
|
|
@@ -63,11 +63,10 @@ const emit = defineEmits([
|
|
|
63
63
|
"update:search",
|
|
64
64
|
]);
|
|
65
65
|
|
|
66
|
-
provide("hideDropdownOptions", hideOptions);
|
|
67
|
-
|
|
68
66
|
type ULisboxRef = InstanceType<typeof ULisbox>;
|
|
69
67
|
|
|
70
68
|
const isShownOptions = ref(false);
|
|
69
|
+
const isClickingOption = ref(false);
|
|
71
70
|
const listboxRef = useTemplateRef<ULisboxRef>("dropdown-list");
|
|
72
71
|
const wrapperRef = useTemplateRef<HTMLDivElement>("wrapper");
|
|
73
72
|
|
|
@@ -161,14 +160,29 @@ function onClickLink() {
|
|
|
161
160
|
|
|
162
161
|
function hideOptions() {
|
|
163
162
|
isShownOptions.value = false;
|
|
163
|
+
dropdownSearch.value = "";
|
|
164
164
|
|
|
165
165
|
emit("close");
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
function onClickOption(option: Option) {
|
|
169
|
+
isClickingOption.value = true;
|
|
170
|
+
|
|
169
171
|
emit("clickOption", option);
|
|
170
172
|
|
|
171
173
|
if (!props.multiple && props.closeOnSelect) hideOptions();
|
|
174
|
+
|
|
175
|
+
nextTick(() => {
|
|
176
|
+
setTimeout(() => {
|
|
177
|
+
isClickingOption.value = false;
|
|
178
|
+
}, 10);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function handleClickOutside() {
|
|
183
|
+
if (isClickingOption.value) return;
|
|
184
|
+
|
|
185
|
+
hideOptions();
|
|
172
186
|
}
|
|
173
187
|
|
|
174
188
|
defineExpose({
|
|
@@ -201,7 +215,7 @@ const { config, getDataTest, wrapperAttrs, dropdownLinkAttrs, listboxAttrs, togg
|
|
|
201
215
|
<template>
|
|
202
216
|
<div
|
|
203
217
|
ref="wrapper"
|
|
204
|
-
v-click-outside="
|
|
218
|
+
v-click-outside="handleClickOutside"
|
|
205
219
|
tabindex="1"
|
|
206
220
|
v-bind="wrapperAttrs"
|
|
207
221
|
:data-test="getDataTest('wrapper')"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
wrapper:
|
|
2
|
+
wrapper: `
|
|
3
|
+
p-3 w-[19rem] bg-default shadow-sm overflow-hidden focus:outline-hidden
|
|
4
|
+
border border-solid border-default rounded-medium`,
|
|
3
5
|
navigation: "mb-2 pb-2 border-b border-muted flex items-center justify-between",
|
|
4
6
|
viewSwitchButton: {
|
|
5
7
|
base: "{UButton}",
|
|
@@ -54,7 +56,7 @@ export default /*tw*/ {
|
|
|
54
56
|
timepicker: "mt-2 pl-1 pt-3 text-medium flex items-stretch justify-between gap-2 border-t border-muted",
|
|
55
57
|
timepickerLabel: "w-full self-center",
|
|
56
58
|
timepickerInputWrapper: `
|
|
57
|
-
flex items-center rounded-medium border border-default
|
|
59
|
+
flex items-center rounded-medium border border-solid border-default
|
|
58
60
|
hover:focus-within:border-primary focus-within:border-primary
|
|
59
61
|
focus-within:outline focus-within:outline-small focus-within:outline-primary
|
|
60
62
|
`,
|
|
@@ -3,7 +3,7 @@ export default /*tw*/ {
|
|
|
3
3
|
checkbox: {
|
|
4
4
|
base: `
|
|
5
5
|
bg-default cursor-pointer transition
|
|
6
|
-
border border-default rounded-small outline-transparent
|
|
6
|
+
border border-solid border-default rounded-small outline-transparent
|
|
7
7
|
appearance-none p-0 print:color-adjust-exact inline-block align-middle bg-origin-border select-none shrink-0
|
|
8
8
|
hover:border-lifted
|
|
9
9
|
active:border-{color} active:bg-{color}/15
|
|
@@ -31,7 +31,7 @@ export default /*tw*/ {
|
|
|
31
31
|
menu: {
|
|
32
32
|
base: `
|
|
33
33
|
absolute z-40 mb-3 w-80 overflow-hidden rounded-medium
|
|
34
|
-
border border-default bg-default p-2 shadow-sm focus:outline-hidden
|
|
34
|
+
border border-solid border-default bg-default p-2 shadow-sm focus:outline-hidden
|
|
35
35
|
`,
|
|
36
36
|
variants: {
|
|
37
37
|
openDirectionX: {
|
package/ui.form-input/config.ts
CHANGED
|
@@ -12,7 +12,7 @@ export default /*tw*/ {
|
|
|
12
12
|
wrapper: {
|
|
13
13
|
base: `
|
|
14
14
|
flex gap-3 w-full px-3 relative bg-default transition
|
|
15
|
-
border rounded-medium border-default outline-transparent
|
|
15
|
+
border border-solid rounded-medium border-default outline-transparent
|
|
16
16
|
hover:border-lifted hover:focus-within:border-primary focus-within:border-primary
|
|
17
17
|
focus-within:outline focus-within:outline-small focus-within:outline-primary focus-within:transition
|
|
18
18
|
`,
|
|
@@ -103,11 +103,7 @@ const selectedValue = computed({
|
|
|
103
103
|
|
|
104
104
|
return props.modelValue;
|
|
105
105
|
},
|
|
106
|
-
set: (value) =>
|
|
107
|
-
if (searchModel.value) searchModel.value = "";
|
|
108
|
-
|
|
109
|
-
emit("update:modelValue", value);
|
|
110
|
-
},
|
|
106
|
+
set: (value) => emit("update:modelValue", value),
|
|
111
107
|
});
|
|
112
108
|
|
|
113
109
|
const addOptionKeyCombination = computed(() => {
|
|
@@ -2,7 +2,7 @@ export default /*tw*/ {
|
|
|
2
2
|
wrapper: {
|
|
3
3
|
base: `
|
|
4
4
|
my-2 p-1 flex flex-col gap-1 w-auto absolute z-50 shadow-sm
|
|
5
|
-
rounded-medium border border-default bg-default
|
|
5
|
+
rounded-medium border border-solid border-default bg-default
|
|
6
6
|
overflow-auto [-webkit-overflow-scrolling:touch]
|
|
7
7
|
focus:outline-hidden
|
|
8
8
|
`,
|
package/ui.form-radio/config.ts
CHANGED
|
@@ -3,7 +3,7 @@ export default /*tw*/ {
|
|
|
3
3
|
radio: {
|
|
4
4
|
base: `
|
|
5
5
|
bg-default cursor-pointer transition
|
|
6
|
-
border border-default rounded-full outline-transparent
|
|
6
|
+
border border-solid border-default rounded-full outline-transparent
|
|
7
7
|
appearance-none p-0 print:color-adjust-exact inline-block align-middle bg-origin-border select-none shrink-0
|
|
8
8
|
hover:border-lifted hover:checked:border-{color}
|
|
9
9
|
active:border-{color} active:bg-{color}/15
|
package/ui.form-select/config.ts
CHANGED
|
@@ -12,7 +12,7 @@ export default /*tw*/ {
|
|
|
12
12
|
wrapper: {
|
|
13
13
|
base: `
|
|
14
14
|
flex flex-row-reverse justify-between w-full min-h-full box-border relative
|
|
15
|
-
rounded-medium border border-default bg-default outline-transparent
|
|
15
|
+
rounded-medium border border-solid border-default bg-default outline-transparent
|
|
16
16
|
hover:border-lifted hover:transition hover:focus-within:border-primary focus-within:border-primary
|
|
17
17
|
focus-within:outline focus-within:outline-small focus-within:outline-primary focus-within:transition
|
|
18
18
|
`,
|
|
@@ -15,7 +15,7 @@ export default /*tw*/ {
|
|
|
15
15
|
wrapper: {
|
|
16
16
|
base: `
|
|
17
17
|
flex px-3 py-2 gap-3 w-full bg-default transition
|
|
18
|
-
rounded-medium border border-default outline-transparent
|
|
18
|
+
rounded-medium border border-solid border-default outline-transparent
|
|
19
19
|
hover:border-lifted hover:focus-within:border-primary focus-within:border-primary
|
|
20
20
|
focus-within:outline focus-within:outline-small focus-within:outline-primary focus-within:transition
|
|
21
21
|
`,
|
package/ui.text-alert/config.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
2
|
wrapper: {
|
|
3
|
-
base: "p-4 border-box flex flex-col border rounded-medium w-full",
|
|
3
|
+
base: "p-4 border-box flex flex-col border border-solid rounded-medium w-full",
|
|
4
4
|
variants: {
|
|
5
5
|
variant: {
|
|
6
6
|
solid: "text-inverted bg-{color} border-transparent",
|
package/ui.text-badge/config.ts
CHANGED
package/utils/helper.ts
CHANGED
|
@@ -196,6 +196,10 @@ export function toNumber(value: unknown): number | undefined {
|
|
|
196
196
|
return value;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
if (typeof value === "boolean") {
|
|
200
|
+
return Number(value);
|
|
201
|
+
}
|
|
202
|
+
|
|
199
203
|
if (typeof value === "string" && value.trim() !== "") {
|
|
200
204
|
const number = Number(value);
|
|
201
205
|
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
export function setCustomPropTypes({ vuelessSrcDir, basePath }?: {
|
|
2
|
-
|
|
1
|
+
export function setCustomPropTypes({ vuelessSrcDir, basePath }?: {
|
|
2
|
+
vuelessSrcDir: string;
|
|
3
|
+
basePath: string;
|
|
4
|
+
}): Promise<void>;
|
|
5
|
+
export function removeCustomPropTypes(srcDir: string): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import fs from "node:fs/promises";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
import { removeFolderIfEmpty } from "./helper.js";
|
|
6
6
|
import { getVuelessConfig } from "./vuelessConfig.js";
|
|
@@ -8,86 +8,97 @@ import { getVuelessConfig } from "./vuelessConfig.js";
|
|
|
8
8
|
import {
|
|
9
9
|
CACHE_DIR,
|
|
10
10
|
COMPONENTS,
|
|
11
|
-
|
|
11
|
+
TEXT_COLOR,
|
|
12
12
|
INHERIT_COLOR,
|
|
13
13
|
PRIMARY_COLOR,
|
|
14
|
-
|
|
14
|
+
GRAYSCALE_COLOR,
|
|
15
|
+
VUELESS_CACHE_DIR,
|
|
15
16
|
} from "../../constants.js";
|
|
17
|
+
import { buildWebTypes } from "./webTypes.js";
|
|
16
18
|
|
|
19
|
+
/* local constants */
|
|
20
|
+
const SAFE_COLORS = [PRIMARY_COLOR, GRAYSCALE_COLOR, INHERIT_COLOR, TEXT_COLOR];
|
|
17
21
|
const OPTIONAL_MARK = "?";
|
|
18
22
|
const CLOSING_BRACKET = "}";
|
|
19
23
|
const IGNORE_PROP = "@ignore";
|
|
20
24
|
const CUSTOM_PROP = "@custom";
|
|
21
25
|
|
|
26
|
+
/* regular expressions */
|
|
22
27
|
const PROPS_INTERFACE_REG_EXP = /export\s+interface\s+Props(?:<[^>]+>)?\s*{([^}]*)}/s;
|
|
23
28
|
const UNION_SYMBOLS_REG_EXP = /[?|:"|;]/g;
|
|
24
29
|
const WORD_IN_QUOTE_REG_EXP = /"([^"]+)"/g;
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Updates custom PropTypes for components based on provided configuration and colors.
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} options Configuration options.
|
|
35
|
+
* @param {string} options.vuelessSrcDir The source directory for Vueless components.
|
|
36
|
+
* @param {string} options.basePath The base path for retrieving the Vueless configuration file.
|
|
37
|
+
* @return {Promise<void>} Resolves when custom PropTypes for all components are updated successfully.
|
|
38
|
+
*/
|
|
28
39
|
export async function setCustomPropTypes({ vuelessSrcDir, basePath } = {}) {
|
|
29
40
|
const vuelessConfig = await getVuelessConfig(basePath);
|
|
30
41
|
|
|
42
|
+
const hasCustomColors = vuelessConfig.colors?.length;
|
|
43
|
+
const hasCustomColorProp = !!Object.values(vuelessConfig.components || {}).find(
|
|
44
|
+
(component) => component.props?.color,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
let componentsWithColorProp = [];
|
|
48
|
+
|
|
49
|
+
/* Build web-types.json to get list of components with color prop */
|
|
50
|
+
if (hasCustomColors || hasCustomColorProp) {
|
|
51
|
+
await buildWebTypes({ vuelessSrcDir, basePath });
|
|
52
|
+
|
|
53
|
+
componentsWithColorProp = await getComponentsWithColors();
|
|
54
|
+
}
|
|
55
|
+
|
|
31
56
|
for await (const [componentName, componentDir] of Object.entries(COMPONENTS)) {
|
|
32
57
|
let componentGlobalConfig = vuelessConfig.components?.[componentName];
|
|
58
|
+
const hasDefaultColorProp = componentsWithColorProp.some((item) => item.name === componentName);
|
|
59
|
+
|
|
60
|
+
/* Skip components without props and without global colors in config */
|
|
61
|
+
if (!componentGlobalConfig?.props && !(hasCustomColors && hasDefaultColorProp)) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
33
64
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
65
|
+
/* Add colors to the default or custom color prop */
|
|
66
|
+
if (componentGlobalConfig?.props?.color || (hasCustomColors && hasDefaultColorProp)) {
|
|
67
|
+
// eslint-disable-next-line prettier/prettier
|
|
68
|
+
const defaultColors = componentsWithColorProp.find((component) => component.name === componentName)?.colors || [];
|
|
69
|
+
const safelistedColors = defaultColors.filter((color) => SAFE_COLORS.includes(color));
|
|
38
70
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
71
|
+
componentGlobalConfig = {
|
|
72
|
+
...(componentGlobalConfig || {}),
|
|
73
|
+
props: {
|
|
74
|
+
...(componentGlobalConfig?.props || {}),
|
|
75
|
+
color: {
|
|
76
|
+
...(componentGlobalConfig?.props?.color || {}),
|
|
43
77
|
values: [
|
|
44
78
|
...new Set([
|
|
45
|
-
...(
|
|
46
|
-
...vuelessConfig.colors,
|
|
47
|
-
...
|
|
79
|
+
...(componentGlobalConfig?.props?.color?.values || []),
|
|
80
|
+
...(vuelessConfig.colors || []),
|
|
81
|
+
...safelistedColors,
|
|
48
82
|
]),
|
|
49
83
|
],
|
|
50
|
-
})
|
|
51
|
-
: undefined;
|
|
52
|
-
|
|
53
|
-
const customPropsWithColor = [
|
|
54
|
-
...customProps,
|
|
55
|
-
{
|
|
56
|
-
name: "color",
|
|
57
|
-
values: [...new Set([...vuelessConfig.colors, ...DEFAULT_SAFE_COLORS])],
|
|
58
|
-
required: false,
|
|
59
|
-
},
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
componentGlobalConfig = {
|
|
63
|
-
...componentGlobalConfig,
|
|
64
|
-
props: isCustomColorProp ? modifiedCustomColorProp : customPropsWithColor,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (vuelessConfig.colors && vuelessConfig.colors.length && !componentGlobalConfig) {
|
|
69
|
-
componentGlobalConfig = {
|
|
70
|
-
props: [
|
|
71
|
-
{
|
|
72
|
-
name: "color",
|
|
73
|
-
values: [...new Set([...vuelessConfig.colors, ...DEFAULT_SAFE_COLORS])],
|
|
74
|
-
required: false,
|
|
75
84
|
},
|
|
76
|
-
|
|
85
|
+
},
|
|
77
86
|
};
|
|
78
87
|
}
|
|
79
88
|
|
|
80
|
-
const
|
|
89
|
+
const cachePath = path.join(vuelessSrcDir, componentDir);
|
|
81
90
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
await cacheComponentTypes(cachePath);
|
|
86
|
-
await modifyComponentTypes(cachePath, componentGlobalConfig.props);
|
|
87
|
-
}
|
|
91
|
+
await cacheComponentTypes(cachePath);
|
|
92
|
+
await modifyComponentTypes(cachePath, componentGlobalConfig.props);
|
|
88
93
|
}
|
|
89
94
|
}
|
|
90
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Removes custom prop types definitions for components.
|
|
98
|
+
*
|
|
99
|
+
* @param {string} srcDir - The source directory containing the component directories.
|
|
100
|
+
* @return {Promise<void>} - A promise that resolves when custom prop types have been removed.
|
|
101
|
+
*/
|
|
91
102
|
export async function removeCustomPropTypes(srcDir) {
|
|
92
103
|
for await (const componentDir of Object.values(COMPONENTS)) {
|
|
93
104
|
await restoreComponentTypes(path.join(srcDir, componentDir));
|
|
@@ -95,6 +106,39 @@ export async function removeCustomPropTypes(srcDir) {
|
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Retrieves a list of components that have a "color" prop from the `web-types.json` file.
|
|
111
|
+
*
|
|
112
|
+
* @return {Promise<Array<string>>} A promise that resolves with an array of component names.
|
|
113
|
+
*/
|
|
114
|
+
async function getComponentsWithColors() {
|
|
115
|
+
const webTypesPath = path.join(VUELESS_CACHE_DIR, "web-types.json");
|
|
116
|
+
|
|
117
|
+
if (!existsSync(webTypesPath)) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const webTypesContent = await fs.readFile(webTypesPath, "utf8");
|
|
122
|
+
const webTypes = JSON.parse(webTypesContent);
|
|
123
|
+
|
|
124
|
+
if (!webTypes.contributions?.html?.tags) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return webTypes.contributions.html.tags
|
|
129
|
+
.filter((component) => component?.attributes.some((attribute) => attribute.name === "color"))
|
|
130
|
+
.map((component) => ({
|
|
131
|
+
name: component.name,
|
|
132
|
+
colors: component.attributes.find((attribute) => attribute.name === "color")?.enum,
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Caches the component types by copying a source file to a specified cache directory.
|
|
138
|
+
*
|
|
139
|
+
* @param {string} filePath - The directory path where the source file is located and the cache directory will be created.
|
|
140
|
+
* @return {Promise<void>} A promise that resolves when the file has been successfully copied, or immediately if no action is taken.
|
|
141
|
+
*/
|
|
98
142
|
async function cacheComponentTypes(filePath) {
|
|
99
143
|
const cacheDir = path.join(filePath, CACHE_DIR);
|
|
100
144
|
const sourceFile = path.join(filePath, "types.ts");
|
|
@@ -111,6 +155,13 @@ async function cacheComponentTypes(filePath) {
|
|
|
111
155
|
await fs.cp(sourceFile, destFile);
|
|
112
156
|
}
|
|
113
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Clears the cached component types by removing the specified cache file
|
|
160
|
+
* and deleting the corresponding folder if it is empty.
|
|
161
|
+
*
|
|
162
|
+
* @param {string} filePath - The base file path where the cache directory resides.
|
|
163
|
+
* @return {Promise<void>} A promise that resolves when the cache has been cleared.
|
|
164
|
+
*/
|
|
114
165
|
async function clearComponentTypesCache(filePath) {
|
|
115
166
|
const cacheDir = path.join(filePath, CACHE_DIR);
|
|
116
167
|
const sourceFile = path.join(cacheDir, "types.ts");
|
|
@@ -122,6 +173,13 @@ async function clearComponentTypesCache(filePath) {
|
|
|
122
173
|
await removeFolderIfEmpty(cacheDir);
|
|
123
174
|
}
|
|
124
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Restores the component type definitions by copying a cached file to the destination.
|
|
178
|
+
*
|
|
179
|
+
* @param {string} filePath - The directory path where the component types should be restored.
|
|
180
|
+
* This path serves as the base for locating the cached file and the destination file.
|
|
181
|
+
* @return {Promise<void>} A promise that resolves when the component types have been successfully restored.
|
|
182
|
+
*/
|
|
125
183
|
async function restoreComponentTypes(filePath) {
|
|
126
184
|
const cacheDir = path.join(filePath, CACHE_DIR);
|
|
127
185
|
const sourceFile = path.join(cacheDir, "types.ts");
|
|
@@ -132,6 +190,14 @@ async function restoreComponentTypes(filePath) {
|
|
|
132
190
|
}
|
|
133
191
|
}
|
|
134
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Extracts and processes the values from multiple lines based on the given indices.
|
|
195
|
+
*
|
|
196
|
+
* @param {Array<string>} lines - The array of lines to process.
|
|
197
|
+
* @param {number} propIndex - The index from which to start slicing the lines.
|
|
198
|
+
* @param {number} propEndIndex - The index until which to slice the lines (inclusive).
|
|
199
|
+
* @return {Array<string>} An array of strings with processed values, trimmed of unnecessary symbols.
|
|
200
|
+
*/
|
|
135
201
|
function getMultiLineUnionValues(lines, propIndex, propEndIndex) {
|
|
136
202
|
return lines
|
|
137
203
|
.slice(propIndex)
|
|
@@ -139,6 +205,15 @@ function getMultiLineUnionValues(lines, propIndex, propEndIndex) {
|
|
|
139
205
|
.map((item) => item.replace(UNION_SYMBOLS_REG_EXP, "").trim());
|
|
140
206
|
}
|
|
141
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Extracts and returns inline union values from the specified lines of text,
|
|
210
|
+
* based on provided property indices.
|
|
211
|
+
*
|
|
212
|
+
* @param {string[]} lines - The array of string lines to extract union values from.
|
|
213
|
+
* @param {number} propIndex - The starting index in the lines array from where extraction begins.
|
|
214
|
+
* @param {number} propEndIndex - The ending index in the lines array up to which extraction is performed.
|
|
215
|
+
* @return {string[]} An array of extracted union values, or an empty array if no matches are found.
|
|
216
|
+
*/
|
|
142
217
|
function getInlineUnionValues(lines, propIndex, propEndIndex) {
|
|
143
218
|
const types = lines
|
|
144
219
|
.slice(propIndex)
|
|
@@ -167,10 +242,8 @@ async function modifyComponentTypes(filePath, props) {
|
|
|
167
242
|
|
|
168
243
|
const lines = propsInterface.split("\n");
|
|
169
244
|
|
|
170
|
-
for (const
|
|
171
|
-
const {
|
|
172
|
-
|
|
173
|
-
if (!name) return;
|
|
245
|
+
for (const name in props) {
|
|
246
|
+
const { type = "string", values = [], description, required, ignore } = props[name];
|
|
174
247
|
|
|
175
248
|
/* Find line with prop. */
|
|
176
249
|
const propRegex = new RegExp(`^\\s*${name}[?:]?\\s*:`);
|
package/utils/node/helper.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
export function getDirFiles(dirPath:
|
|
1
|
+
export function getDirFiles(dirPath: string, ext: string, { recursive, exclude }?: {
|
|
2
2
|
recursive?: boolean | undefined;
|
|
3
|
-
exclude?:
|
|
3
|
+
exclude?: string[] | undefined;
|
|
4
4
|
}): Promise<string[]>;
|
|
5
5
|
export function getNuxtDirs(): string[];
|
|
6
6
|
export function getVueDirs(): string[];
|
|
7
7
|
export function getVuelessConfigDirs(): string[];
|
|
8
|
-
export function getMergedComponentConfig(name:
|
|
9
|
-
export function getDefaultComponentConfig(name:
|
|
10
|
-
export function cacheMergedConfigs({ vuelessSrcDir, basePath }?: {
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
export function getMergedComponentConfig(name: string): Promise<Object>;
|
|
9
|
+
export function getDefaultComponentConfig(name: string, configDir: string): Promise<Object>;
|
|
10
|
+
export function cacheMergedConfigs({ vuelessSrcDir, basePath }?: {
|
|
11
|
+
vuelessSrcDir: string;
|
|
12
|
+
basePath: string;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
export function buildTSFile(entryPath: string, configOutFile: string): Promise<void>;
|
|
15
|
+
export function removeFolderIfEmpty(dirPath: string): Promise<void>;
|
|
13
16
|
export function detectTypeScript(): Promise<boolean>;
|
|
14
17
|
export function autoImportUserConfigs(basePath?: string): Promise<void>;
|
|
15
18
|
export function generateConfigIndexContent(imports?: string[], componentEntries?: string[]): Promise<string>;
|
package/utils/node/helper.js
CHANGED
|
@@ -20,6 +20,16 @@ import {
|
|
|
20
20
|
CONFIG_INDEX_FILE_NAME,
|
|
21
21
|
} from "../../constants.js";
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Retrieves a list of file names in a specified directory that match the given extension and filtering criteria.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} dirPath - The path of the directory to search for files.
|
|
27
|
+
* @param {string} ext - The extension of the files to include in the result.
|
|
28
|
+
* @param {Object} [options] - Optional settings to customize the file search.
|
|
29
|
+
* @param {boolean} [options.recursive=true] - Whether to search directories recursively.
|
|
30
|
+
* @param {string[]} [options.exclude=[]] - A list of file or directory names to exclude from the result.
|
|
31
|
+
* @return {Promise<string[]>} - A promise that resolves to an array of file paths that match the specified criteria.
|
|
32
|
+
*/
|
|
23
33
|
export async function getDirFiles(dirPath, ext, { recursive = true, exclude = [] } = {}) {
|
|
24
34
|
let fileNames = [];
|
|
25
35
|
|
|
@@ -65,6 +75,10 @@ export async function getDirFiles(dirPath, ext, { recursive = true, exclude = []
|
|
|
65
75
|
.filter((filePath) => !statSync(filePath).isDirectory());
|
|
66
76
|
}
|
|
67
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Retrieves an array of directory paths and specific file paths within the current working directory related to a Nuxt.js project.
|
|
80
|
+
* @return {string[]}.
|
|
81
|
+
*/
|
|
68
82
|
export function getNuxtDirs() {
|
|
69
83
|
return [
|
|
70
84
|
path.join(cwd(), "app"),
|
|
@@ -82,14 +96,28 @@ export function getNuxtDirs() {
|
|
|
82
96
|
];
|
|
83
97
|
}
|
|
84
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Retrieves an array of directory paths and specific file paths within the current working directory related to a Vue.js project.
|
|
101
|
+
* @return {string[]}.
|
|
102
|
+
*/
|
|
85
103
|
export function getVueDirs() {
|
|
86
104
|
return [path.join(cwd(), "src")];
|
|
87
105
|
}
|
|
88
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Retrieves an array of directory paths and specific file paths within the current working directory related to a Vueless project.
|
|
109
|
+
* @return {string[]}.
|
|
110
|
+
*/
|
|
89
111
|
export function getVuelessConfigDirs() {
|
|
90
112
|
return [path.join(cwd(), VUELESS_CONFIG_DIR)];
|
|
91
113
|
}
|
|
92
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Retrieves the merged config for a specific component.
|
|
117
|
+
*
|
|
118
|
+
* @param {string} name - The name of the component.
|
|
119
|
+
* @return {Promise<Object>} A promise that resolves to the merged configuration object for the specified component.
|
|
120
|
+
*/
|
|
93
121
|
export async function getMergedComponentConfig(name) {
|
|
94
122
|
const configOutPath = path.join(cwd(), `${VUELESS_MERGED_CONFIGS_CACHED_DIR}/${name}.json`);
|
|
95
123
|
|
|
@@ -100,6 +128,13 @@ export async function getMergedComponentConfig(name) {
|
|
|
100
128
|
}
|
|
101
129
|
}
|
|
102
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Retrieves the default config for a specific component.
|
|
133
|
+
*
|
|
134
|
+
* @param {string} name - The name of the component.
|
|
135
|
+
* @param {string} configDir - The directory path where the component's configuration file is located.
|
|
136
|
+
* @return {Promise<Object>} A promise that resolves to the default configuration object for the specified component.
|
|
137
|
+
*/
|
|
103
138
|
export async function getDefaultComponentConfig(name, configDir) {
|
|
104
139
|
const configOutPath = path.join(cwd(), `${VUELESS_CONFIGS_CACHED_DIR}/${name}.mjs`);
|
|
105
140
|
let config = {};
|
|
@@ -117,6 +152,14 @@ export async function getDefaultComponentConfig(name, configDir) {
|
|
|
117
152
|
return config;
|
|
118
153
|
}
|
|
119
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Caches merged configs for all components.
|
|
157
|
+
*
|
|
158
|
+
* @param {Object} options - Configuration options.
|
|
159
|
+
* @param {string} options.vuelessSrcDir - The source directory for Vueless components.
|
|
160
|
+
* @param {string} options.basePath - The base path for retrieving the Vueless configuration file.
|
|
161
|
+
* @return {Promise<void>} A promise that resolves when all merged configs have been cached.
|
|
162
|
+
*/
|
|
120
163
|
export async function cacheMergedConfigs({ vuelessSrcDir, basePath } = {}) {
|
|
121
164
|
const vuelessConfig = await getVuelessConfig(basePath);
|
|
122
165
|
const componentNames = Object.entries(COMPONENTS);
|
|
@@ -146,6 +189,13 @@ export async function cacheMergedConfigs({ vuelessSrcDir, basePath } = {}) {
|
|
|
146
189
|
}
|
|
147
190
|
}
|
|
148
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Builds a TypeScript file into a JavaScript file using esbuild.
|
|
194
|
+
*
|
|
195
|
+
* @param {string} entryPath - The path to the TypeScript file to be built.
|
|
196
|
+
* @param {string} configOutFile - The output path for the resulting JavaScript file.
|
|
197
|
+
* @return {Promise<void>} A promise that resolves when the build is complete.
|
|
198
|
+
*/
|
|
149
199
|
export async function buildTSFile(entryPath, configOutFile) {
|
|
150
200
|
await esbuild.build({
|
|
151
201
|
entryPoints: [entryPath],
|
|
@@ -158,13 +208,20 @@ export async function buildTSFile(entryPath, configOutFile) {
|
|
|
158
208
|
});
|
|
159
209
|
}
|
|
160
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Removes a folder if it is empty.
|
|
213
|
+
* @param {string} dirPath - The path to the directory to be removed.
|
|
214
|
+
* @return {Promise<void>} A promise that resolves when the directory has been removed.
|
|
215
|
+
*/
|
|
161
216
|
export async function removeFolderIfEmpty(dirPath) {
|
|
162
|
-
|
|
217
|
+
try {
|
|
163
218
|
const files = await readdir(dirPath);
|
|
164
219
|
|
|
165
220
|
if (!files.length) {
|
|
166
|
-
await rmdir(dirPath);
|
|
221
|
+
await rmdir(dirPath, { recursive: false, force: true });
|
|
167
222
|
}
|
|
223
|
+
} catch {
|
|
224
|
+
// suppress errors
|
|
168
225
|
}
|
|
169
226
|
}
|
|
170
227
|
|
|
@@ -233,7 +233,14 @@ function getClassesToSafelist(config) {
|
|
|
233
233
|
const safelistItems = [];
|
|
234
234
|
|
|
235
235
|
for (const key in config) {
|
|
236
|
-
|
|
236
|
+
const nonClassKeys = [
|
|
237
|
+
SYSTEM_CONFIG_KEY.defaults,
|
|
238
|
+
SYSTEM_CONFIG_KEY.props,
|
|
239
|
+
SYSTEM_CONFIG_KEY.i18n,
|
|
240
|
+
SYSTEM_CONFIG_KEY.colors,
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
if (nonClassKeys.some((item) => key === item)) continue;
|
|
237
244
|
|
|
238
245
|
if (Object.hasOwn(config, key)) {
|
|
239
246
|
const classes = config[key];
|
|
@@ -267,7 +274,7 @@ function getClassesToSafelist(config) {
|
|
|
267
274
|
*/
|
|
268
275
|
function getSafelistClasses(config, colors) {
|
|
269
276
|
const classes = new Set();
|
|
270
|
-
const defaultColor = config.defaults?.color || "";
|
|
277
|
+
const defaultColor = config.defaults?.color || config.props?.color?.default || "";
|
|
271
278
|
|
|
272
279
|
getClassesToSafelist(config).map((safelistClass) => {
|
|
273
280
|
[...colors, defaultColor].forEach((color) => {
|
package/utils/theme.ts
CHANGED
|
@@ -51,18 +51,6 @@ import type {
|
|
|
51
51
|
} from "../types";
|
|
52
52
|
import { ColorMode } from "../types";
|
|
53
53
|
|
|
54
|
-
declare interface RootCSSVariableOptions {
|
|
55
|
-
primary: PrimaryColors | string;
|
|
56
|
-
neutral: NeutralColors | string;
|
|
57
|
-
text: ThemeConfigText;
|
|
58
|
-
rounding: ThemeConfigRounding;
|
|
59
|
-
outline: ThemeConfigOutline;
|
|
60
|
-
letterSpacing: number;
|
|
61
|
-
disabledOpacity: number;
|
|
62
|
-
lightTheme: Partial<VuelessCssVariables>;
|
|
63
|
-
darkTheme: Partial<VuelessCssVariables>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
54
|
declare interface SetColorMode {
|
|
67
55
|
colorMode: `${ColorMode}`;
|
|
68
56
|
isColorModeAuto: boolean;
|
|
@@ -334,10 +322,10 @@ export function setTheme(config: ThemeConfig = {}) {
|
|
|
334
322
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
335
323
|
export function normalizeThemeConfig(theme: any): MergedThemeConfig {
|
|
336
324
|
return {
|
|
337
|
-
colorMode: theme.colorMode,
|
|
338
|
-
isColorModeAuto: theme.isColorModeAuto,
|
|
339
|
-
primary: theme.primary,
|
|
340
|
-
neutral: theme.neutral,
|
|
325
|
+
colorMode: String(theme.colorMode ?? "") as ColorMode,
|
|
326
|
+
isColorModeAuto: !!toNumber(theme.isColorModeAuto),
|
|
327
|
+
primary: String(theme.primary ?? ""),
|
|
328
|
+
neutral: String(theme.neutral ?? ""),
|
|
341
329
|
text: {
|
|
342
330
|
xs: toNumber(theme.text?.xs),
|
|
343
331
|
sm: toNumber(theme.text?.sm),
|
|
@@ -696,20 +684,20 @@ function getDarkTheme(darkTheme?: Partial<VuelessCssVariables>) {
|
|
|
696
684
|
* Generate and apply Vueless CSS variables.
|
|
697
685
|
* @return string - Vueless CSS variables string.
|
|
698
686
|
*/
|
|
699
|
-
function setRootCSSVariables(vars:
|
|
687
|
+
export function setRootCSSVariables(vars: MergedThemeConfig) {
|
|
700
688
|
let darkVariables: Partial<VuelessCssVariables> = {};
|
|
701
689
|
|
|
702
690
|
let variables: Partial<VuelessCssVariables> = {
|
|
703
|
-
"--vl-text-xs": `${vars.text
|
|
704
|
-
"--vl-text-sm": `${vars.text
|
|
705
|
-
"--vl-text-md": `${vars.text
|
|
706
|
-
"--vl-text-lg": `${vars.text
|
|
691
|
+
"--vl-text-xs": `${Number(vars.text?.xs ?? 0) / PX_IN_REM}rem`,
|
|
692
|
+
"--vl-text-sm": `${Number(vars.text?.sm ?? 0) / PX_IN_REM}rem`,
|
|
693
|
+
"--vl-text-md": `${Number(vars.text?.md ?? 0) / PX_IN_REM}rem`,
|
|
694
|
+
"--vl-text-lg": `${Number(vars.text?.lg ?? 0) / PX_IN_REM}rem`,
|
|
707
695
|
"--vl-outline-sm": `${vars.outline.sm}px`,
|
|
708
696
|
"--vl-outline-md": `${vars.outline.md}px`,
|
|
709
697
|
"--vl-outline-lg": `${vars.outline.lg}px`,
|
|
710
|
-
"--vl-rounding-sm": `${vars.rounding.sm / PX_IN_REM}rem`,
|
|
711
|
-
"--vl-rounding-md": `${vars.rounding.md / PX_IN_REM}rem`,
|
|
712
|
-
"--vl-rounding-lg": `${vars.rounding.lg / PX_IN_REM}rem`,
|
|
698
|
+
"--vl-rounding-sm": `${Number(vars.rounding.sm ?? 0) / PX_IN_REM}rem`,
|
|
699
|
+
"--vl-rounding-md": `${Number(vars.rounding.md ?? 0) / PX_IN_REM}rem`,
|
|
700
|
+
"--vl-rounding-lg": `${Number(vars.rounding.lg ?? 0) / PX_IN_REM}rem`,
|
|
713
701
|
"--vl-letter-spacing": `${vars.letterSpacing}em`,
|
|
714
702
|
"--vl-disabled-opacity": `${vars.disabledOpacity}%`,
|
|
715
703
|
};
|
|
@@ -724,7 +712,7 @@ function setRootCSSVariables(vars: RootCSSVariableOptions) {
|
|
|
724
712
|
`var(--color-${vars.neutral}-${shade})`;
|
|
725
713
|
}
|
|
726
714
|
|
|
727
|
-
const [light, dark] = generateCSSColorVariables(vars.lightTheme, vars.darkTheme);
|
|
715
|
+
const [light, dark] = generateCSSColorVariables(vars.lightTheme ?? {}, vars.darkTheme ?? {});
|
|
728
716
|
|
|
729
717
|
variables = { ...variables, ...light };
|
|
730
718
|
darkVariables = { ...darkVariables, ...dark };
|
|
@@ -775,7 +763,7 @@ function setCSSVariables(
|
|
|
775
763
|
.join(" ");
|
|
776
764
|
|
|
777
765
|
const rootVariables = `
|
|
778
|
-
:root {${variablesString}}
|
|
766
|
+
:host, :root {${variablesString}}
|
|
779
767
|
.${DARK_MODE_CLASS} {${darkVariablesString}}
|
|
780
768
|
`;
|
|
781
769
|
|
package/utils/ui.ts
CHANGED
|
@@ -7,7 +7,13 @@ import { createGetMergedConfig } from "./node/mergeConfigs";
|
|
|
7
7
|
import { COMPONENT_NAME as U_ICON } from "../ui.image-icon/constants";
|
|
8
8
|
import { ICON_NON_PROPS_DEFAULTS, TAILWIND_MERGE_EXTENSION } from "../constants";
|
|
9
9
|
|
|
10
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
Config,
|
|
12
|
+
UnknownObject,
|
|
13
|
+
ComponentNames,
|
|
14
|
+
ComponentDefaults,
|
|
15
|
+
ComponentCustomProps,
|
|
16
|
+
} from "../types";
|
|
11
17
|
|
|
12
18
|
interface MergedConfigOptions {
|
|
13
19
|
defaultConfig: unknown;
|
|
@@ -87,10 +93,14 @@ export const cva = ({ base = "", variants = {}, compoundVariants = [], defaultVa
|
|
|
87
93
|
* Return default values for component props, icons, etc..
|
|
88
94
|
*/
|
|
89
95
|
export function getDefaults<Props, Config>(defaultConfig: Config, name: ComponentNames) {
|
|
90
|
-
const componentDefaults = (defaultConfig as UnknownObject).defaults || {};
|
|
96
|
+
const componentDefaults = (defaultConfig as Config & UnknownObject).defaults || {};
|
|
91
97
|
const globalDefaults = vuelessConfig.components?.[name]?.defaults || {};
|
|
92
98
|
|
|
93
|
-
const
|
|
99
|
+
const customProps = vuelessConfig.components?.[name]?.props as ComponentCustomProps;
|
|
100
|
+
const customPropsDefaults = getCustomPropsDefaults(customProps) || {};
|
|
101
|
+
|
|
102
|
+
const defaults = merge({}, componentDefaults, globalDefaults, customPropsDefaults) as Props &
|
|
103
|
+
ComponentDefaults;
|
|
94
104
|
|
|
95
105
|
/* Remove non a props defaults. */
|
|
96
106
|
for (const key in defaults) {
|
|
@@ -116,3 +126,22 @@ export function getDefaults<Props, Config>(defaultConfig: Config, name: Componen
|
|
|
116
126
|
export function setColor(classes: string, color: string) {
|
|
117
127
|
return classes?.replace(/{color}/g, color);
|
|
118
128
|
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Retrieves the default values from the provided component custom properties.
|
|
132
|
+
*/
|
|
133
|
+
export function getCustomPropsDefaults(props: ComponentCustomProps) {
|
|
134
|
+
const customPropsDefaults: ComponentDefaults = {};
|
|
135
|
+
|
|
136
|
+
if (!props) {
|
|
137
|
+
return customPropsDefaults;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
for (const [key, value] of Object.entries(props)) {
|
|
141
|
+
if (value.default) {
|
|
142
|
+
customPropsDefaults[key] = value.default;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return customPropsDefaults;
|
|
147
|
+
}
|