vueless 0.0.674 → 0.0.676
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/bin/commands/create.js +77 -0
- package/bin/commands/index.js +2 -0
- package/bin/commands/init.js +4 -8
- package/bin/constants.js +2 -5
- package/bin/index.js +1 -1
- package/bin/utils/dataUtils.js +53 -0
- package/bin/utils/formatUtil.js +48 -0
- package/composables/useUI.ts +12 -1
- package/constants.js +6 -0
- package/package.json +2 -2
- package/plugin-vite.js +3 -1
- package/types.ts +1 -1
- package/ui.boilerplate/storybook/stories.ts +1 -1
- package/ui.boilerplate/types.ts +1 -1
- package/ui.button/UButton.vue +9 -6
- package/ui.button/types.ts +1 -1
- package/ui.button-link/ULink.vue +37 -62
- package/ui.button-link/config.ts +8 -35
- package/ui.button-link/storybook/stories.ts +0 -22
- package/ui.button-link/types.ts +1 -11
- package/ui.button-toggle/types.ts +1 -1
- package/ui.button-toggle-item/types.ts +1 -1
- package/ui.container-accordion/types.ts +1 -1
- package/ui.container-card/types.ts +1 -1
- package/ui.container-col/types.ts +1 -1
- package/ui.container-divider/types.ts +1 -1
- package/ui.container-group/types.ts +1 -1
- package/ui.container-groups/types.ts +1 -1
- package/ui.container-modal/UModal.vue +21 -20
- package/ui.container-modal/config.ts +3 -2
- package/ui.container-modal/types.ts +1 -1
- package/ui.container-modal-confirm/types.ts +1 -1
- package/ui.container-page/UPage.vue +31 -19
- package/ui.container-page/config.ts +1 -0
- package/ui.container-page/types.ts +1 -1
- package/ui.container-row/types.ts +1 -1
- package/ui.data-list/types.ts +1 -1
- package/ui.data-table/types.ts +1 -1
- package/ui.dropdown-badge/types.ts +1 -1
- package/ui.dropdown-button/types.ts +1 -1
- package/ui.dropdown-link/UDropdownLink.vue +29 -33
- package/ui.dropdown-link/config.ts +3 -3
- package/ui.dropdown-link/types.ts +1 -1
- package/ui.dropdown-list/types.ts +1 -1
- package/ui.form-calendar/types.ts +1 -1
- package/ui.form-checkbox/types.ts +1 -1
- package/ui.form-checkbox-group/types.ts +1 -1
- package/ui.form-checkbox-multi-state/types.ts +1 -1
- package/ui.form-date-picker/types.ts +1 -1
- package/ui.form-date-picker-range/types.ts +1 -1
- package/ui.form-input/types.ts +1 -1
- package/ui.form-input-file/types.ts +1 -1
- package/ui.form-input-money/types.ts +1 -1
- package/ui.form-input-number/types.ts +1 -1
- package/ui.form-input-rating/types.ts +1 -1
- package/ui.form-input-search/types.ts +1 -1
- package/ui.form-label/types.ts +1 -1
- package/ui.form-radio/types.ts +1 -1
- package/ui.form-radio-group/types.ts +1 -1
- package/ui.form-select/USelect.vue +8 -6
- package/ui.form-select/types.ts +1 -1
- package/ui.form-switch/types.ts +1 -1
- package/ui.form-textarea/types.ts +1 -1
- package/ui.image-avatar/types.ts +1 -1
- package/ui.image-icon/UIcon.vue +2 -18
- package/ui.image-icon/storybook/stories.ts +0 -3
- package/ui.image-icon/types.ts +1 -13
- package/ui.loader/types.ts +1 -1
- package/ui.loader-overlay/types.ts +1 -1
- package/ui.loader-progress/types.ts +1 -1
- package/ui.navigation-pagination/types.ts +1 -1
- package/ui.navigation-progress/types.ts +2 -2
- package/ui.navigation-tab/types.ts +1 -1
- package/ui.navigation-tabs/types.ts +1 -1
- package/ui.other-dot/types.ts +1 -1
- package/ui.other-theme-color-toggle/storybook/stories.ts +1 -1
- package/ui.other-theme-color-toggle/types.ts +1 -1
- package/ui.text-alert/types.ts +1 -1
- package/ui.text-badge/types.ts +1 -1
- package/ui.text-block/types.ts +1 -1
- package/ui.text-empty/types.ts +1 -1
- package/ui.text-file/types.ts +1 -1
- package/ui.text-files/types.ts +1 -1
- package/ui.text-header/types.ts +1 -1
- package/ui.text-money/types.ts +1 -1
- package/ui.text-notify/types.ts +1 -1
- package/ui.text-number/types.ts +1 -1
- package/utils/theme.ts +5 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { cwd } from "node:process";
|
|
5
|
+
import { cp, readFile, writeFile, rename } from "node:fs/promises";
|
|
6
|
+
import { styleText } from "node:util";
|
|
7
|
+
|
|
8
|
+
import { getDirFiles } from "../../utils/node/helper.js";
|
|
9
|
+
import { replaceRelativeImports } from "../utils/formatUtil.js";
|
|
10
|
+
import { getLastStorybookId } from "../utils/dataUtils.js";
|
|
11
|
+
|
|
12
|
+
import { SRC_COMPONENTS_PATH, COMPONENTS_PATH } from "../constants.js";
|
|
13
|
+
|
|
14
|
+
import { COMPONENTS, VUELESS_DIR, VUELESS_LOCAL_DIR } from "../../constants.js";
|
|
15
|
+
|
|
16
|
+
const boilerplateName = "UBoilerplate";
|
|
17
|
+
const boilerplatePath = path.join(cwd(), VUELESS_DIR, "ui.boilerplate");
|
|
18
|
+
|
|
19
|
+
export async function createVuelessComponent(options) {
|
|
20
|
+
const [componentName] = options;
|
|
21
|
+
|
|
22
|
+
if (!componentName) {
|
|
23
|
+
throw new Error("Component name is required");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isSrcDir = existsSync(path.join(cwd(), VUELESS_LOCAL_DIR));
|
|
27
|
+
const destPath = isSrcDir
|
|
28
|
+
? path.join(cwd(), SRC_COMPONENTS_PATH, componentName)
|
|
29
|
+
: path.join(cwd(), COMPONENTS_PATH, componentName);
|
|
30
|
+
|
|
31
|
+
const isComponentExists = componentName in COMPONENTS || existsSync(destPath);
|
|
32
|
+
|
|
33
|
+
if (isComponentExists) {
|
|
34
|
+
throw new Error(`Component with name ${componentName} alrady exists`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await cp(boilerplatePath, destPath, { recursive: true });
|
|
38
|
+
|
|
39
|
+
await modifyCreatedComponent(destPath, componentName);
|
|
40
|
+
|
|
41
|
+
const successMessage = styleText(
|
|
42
|
+
"green",
|
|
43
|
+
`Success: ${componentName} was created in ${destPath} directory`,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
console.log(successMessage);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function modifyCreatedComponent(destPath, componentName) {
|
|
50
|
+
const destFiles = await getDirFiles(destPath, "");
|
|
51
|
+
const lastStorybookId = await getLastStorybookId();
|
|
52
|
+
|
|
53
|
+
for await (const filePath of destFiles) {
|
|
54
|
+
const fileContent = await readFile(filePath, "utf-8");
|
|
55
|
+
|
|
56
|
+
let updatedContent = replaceRelativeImports(componentName, filePath, fileContent);
|
|
57
|
+
let targetPath = filePath;
|
|
58
|
+
|
|
59
|
+
if (filePath.endsWith("constants.ts")) {
|
|
60
|
+
updatedContent = updatedContent.replace(boilerplateName, componentName);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (filePath.endsWith("stories.ts")) {
|
|
64
|
+
updatedContent = updatedContent
|
|
65
|
+
.replaceAll(boilerplateName, componentName)
|
|
66
|
+
.replace("{{component_id}}", String(lastStorybookId + 10));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (targetPath.endsWith(`${boilerplateName}.vue`)) {
|
|
70
|
+
targetPath = targetPath.replace(boilerplateName, componentName);
|
|
71
|
+
|
|
72
|
+
await rename(filePath, targetPath);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await writeFile(targetPath, updatedContent);
|
|
76
|
+
}
|
|
77
|
+
}
|
package/bin/commands/index.js
CHANGED
package/bin/commands/init.js
CHANGED
|
@@ -5,14 +5,10 @@ import path from "node:path";
|
|
|
5
5
|
import { writeFile } from "node:fs/promises";
|
|
6
6
|
import { styleText } from "node:util";
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
JAVASCRIPT_EXT,
|
|
13
|
-
} from "../constants.js";
|
|
14
|
-
|
|
15
|
-
const destPath = path.join(cwd(), DEFAULT_VUELESS_CONFIG_NAME);
|
|
8
|
+
import { DEFAULT_VUELESS_CONFIG_CONTNET } from "../constants.js";
|
|
9
|
+
import { JAVASCRIPT_EXT, TYPESCRIPT_EXT, VUELESS_CONFIG_FILE_NAME } from "../../constants.js";
|
|
10
|
+
|
|
11
|
+
const destPath = path.join(cwd(), VUELESS_CONFIG_FILE_NAME);
|
|
16
12
|
|
|
17
13
|
const vuelessInitOptions = ["--ts", "--js"];
|
|
18
14
|
|
package/bin/constants.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
3
|
-
export const FAILURE_CODE = 1;
|
|
4
|
-
export const TYPESCRIPT_EXT = ".ts";
|
|
5
|
-
export const JAVASCRIPT_EXT = ".js";
|
|
1
|
+
export const SRC_COMPONENTS_PATH = "/src/components";
|
|
2
|
+
export const COMPONENTS_PATH = "/components";
|
|
6
3
|
export const DEFAULT_VUELESS_CONFIG_CONTNET = `
|
|
7
4
|
export default {
|
|
8
5
|
/**
|
package/bin/index.js
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { cwd } from "node:process";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
|
|
6
|
+
import { getDirFiles } from "../../utils/node/helper.js";
|
|
7
|
+
|
|
8
|
+
import { SRC_COMPONENTS_PATH, COMPONENTS_PATH } from "../constants.js";
|
|
9
|
+
import { VUELESS_DIR } from "../../constants.js";
|
|
10
|
+
|
|
11
|
+
const storiesName = "stories.ts";
|
|
12
|
+
|
|
13
|
+
export async function getLastStorybookId() {
|
|
14
|
+
const srcComponentsDir = path.join(cwd(), SRC_COMPONENTS_PATH);
|
|
15
|
+
const componentsDir = path.join(cwd(), COMPONENTS_PATH);
|
|
16
|
+
const vuelessPackagePath = path.join(cwd(), VUELESS_DIR);
|
|
17
|
+
const isSrcComponentsDir = existsSync(srcComponentsDir);
|
|
18
|
+
const isComponentsDir = existsSync(componentsDir);
|
|
19
|
+
|
|
20
|
+
const stories = await getDirFiles(vuelessPackagePath, storiesName);
|
|
21
|
+
|
|
22
|
+
if (isSrcComponentsDir) {
|
|
23
|
+
const srcComponentsDirStories = await getDirFiles(srcComponentsDir, storiesName);
|
|
24
|
+
|
|
25
|
+
stories.push(...srcComponentsDirStories);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (isComponentsDir) {
|
|
29
|
+
const componentsDirStories = await getDirFiles(componentsDir, storiesName);
|
|
30
|
+
|
|
31
|
+
stories.push(...componentsDirStories);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let id = 200000;
|
|
35
|
+
|
|
36
|
+
for await (const storyPath of stories) {
|
|
37
|
+
const storyContent = await readFile(storyPath, "utf-8");
|
|
38
|
+
|
|
39
|
+
const storyIdLine = storyContent.split("\n").find((line, idx, array) => {
|
|
40
|
+
return line.includes("id:") && idx && array[idx - 1].includes("export default");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (!storyIdLine) continue;
|
|
44
|
+
|
|
45
|
+
const currentId = parseInt(storyIdLine.split(" ").at(-1).replaceAll('"', ""));
|
|
46
|
+
|
|
47
|
+
if (currentId > id && !Number.isNaN(currentId)) {
|
|
48
|
+
id = currentId;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return id;
|
|
53
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
export function replaceRelativeImports(componentName, filePath, fileContent) {
|
|
4
|
+
const isTopLevelFile = path.dirname(filePath).endsWith(componentName);
|
|
5
|
+
const contentLines = fileContent.split("\n");
|
|
6
|
+
|
|
7
|
+
return contentLines.map((line) => replaceRelativeLineImports(line, isTopLevelFile)).join("\n");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function replaceRelativeLineImports(line, isTopLevelFile) {
|
|
11
|
+
const importRegex = /import\s+(?:[\w\s{},*]+)\s+from\s+(['"])(\.\.?\/.*?)(\.[tj]s)?\1(?!\?)/g;
|
|
12
|
+
|
|
13
|
+
const isTopLevelLocalImport = isTopLevelFile && !line.includes("../");
|
|
14
|
+
const isInnerLocalImport =
|
|
15
|
+
!isTopLevelFile && (line.includes("../") || line.includes("./")) && !line.includes("../../");
|
|
16
|
+
|
|
17
|
+
if (isTopLevelLocalImport || isInnerLocalImport) {
|
|
18
|
+
return line;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return line.replace(importRegex, (match, quote, oldPath, ext) => {
|
|
22
|
+
const isDefaultImport = match.includes("{");
|
|
23
|
+
|
|
24
|
+
if (!isDefaultImport) {
|
|
25
|
+
match = defaultToNamedImport(match);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return match.replace(oldPath + (ext || ""), "vueless");
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function defaultToNamedImport(importString) {
|
|
33
|
+
const splittedImport = importString.split(" ");
|
|
34
|
+
|
|
35
|
+
return splittedImport
|
|
36
|
+
.map((importStringToken) => {
|
|
37
|
+
if (importStringToken.includes("import")) {
|
|
38
|
+
return `${importStringToken} { `;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (importStringToken.includes("from")) {
|
|
42
|
+
return ` } ${importStringToken} `;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return importStringToken;
|
|
46
|
+
})
|
|
47
|
+
.join("");
|
|
48
|
+
}
|
package/composables/useUI.ts
CHANGED
|
@@ -241,7 +241,18 @@ export default function useUI<T>(
|
|
|
241
241
|
return vuelessAttrs;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Get data test attribute value if exist.
|
|
246
|
+
*/
|
|
247
|
+
function getDataTest(suffix?: string) {
|
|
248
|
+
if (!props.dataTest) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return suffix ? `${props.dataTest}-${suffix}` : props.dataTest;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return { config, getDataTest, ...getKeysAttrs(mutatedProps) } as UseUI<T>;
|
|
245
256
|
}
|
|
246
257
|
|
|
247
258
|
/**
|
package/constants.js
CHANGED
|
@@ -221,6 +221,10 @@ export const VUELESS_ICONS_LOCAL_DIR = `src/${ICONS_DIR}`;
|
|
|
221
221
|
export const VUELESS_ICONS_CACHED_DIR = `${VUELESS_CACHE_DIR}/${ICONS_DIR}`;
|
|
222
222
|
export const VUELESS_CONFIGS_CACHED_DIR = `${VUELESS_CACHE_DIR}/configs`;
|
|
223
223
|
|
|
224
|
+
/* System error codes */
|
|
225
|
+
export const DEFAULT_EXIT_CODE = 0;
|
|
226
|
+
export const FAILURE_CODE = 1;
|
|
227
|
+
|
|
224
228
|
/* Other */
|
|
225
229
|
export const PX_IN_REM = 16;
|
|
226
230
|
export const NESTED_COMPONENT_PATTERN_REG_EXP = /\{(U[^}]*)}/;
|
|
@@ -229,3 +233,5 @@ export const DYNAMIC_COLOR_PATTERN = "{color}";
|
|
|
229
233
|
export const TAILWIND_COLOR_OPACITY_DELIMITER = "/";
|
|
230
234
|
export const TAILWIND_VARIANT_DELIMITER = ":";
|
|
231
235
|
export const TAILWIND_VARIANT_DELIMITER_REG_EXP = /:(?![^[]*])/;
|
|
236
|
+
export const JAVASCRIPT_EXT = ".js";
|
|
237
|
+
export const TYPESCRIPT_EXT = ".ts";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueless",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.676",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
|
|
6
6
|
"keywords": [
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"build": "npm run pre:start && storybook build --docs",
|
|
34
34
|
"preview": "vite preview --host --outDir=storybook-static",
|
|
35
35
|
"ts:check": "vue-tsc --build --force",
|
|
36
|
-
"release:prepare": "npm run pre:start && rm -rf dist && mkdir -p dist && cp -r src/. package.json LICENSE README.md dist/
|
|
36
|
+
"release:prepare": "npm run pre:start && rm -rf dist && mkdir -p dist && cp -r src/. package.json LICENSE README.md dist/",
|
|
37
37
|
"release:beta": "release-it --ci --npm.publish --preRelease=beta --increment=prerelease",
|
|
38
38
|
"release:patch": "release-it patch --ci --npm.publish",
|
|
39
39
|
"release:minor": "release-it minor --ci --npm.publish --git.tag --github.release",
|
package/plugin-vite.js
CHANGED
|
@@ -14,6 +14,8 @@ import { setCustomPropTypes, removeCustomPropTypes } from "./utils/node/dynamicP
|
|
|
14
14
|
import { buildWebTypes } from "./utils/node/webTypes.js";
|
|
15
15
|
import { hideHiddenStories, showHiddenStories } from "./utils/node/dynamicStories.js";
|
|
16
16
|
|
|
17
|
+
import { DEFAULT_EXIT_CODE } from "./constants.js";
|
|
18
|
+
|
|
17
19
|
/* Automatically importing Vueless components on demand */
|
|
18
20
|
export const VuelessUnpluginComponents = (options) =>
|
|
19
21
|
UnpluginVueComponents({
|
|
@@ -48,7 +50,7 @@ export const Vueless = function (options = {}) {
|
|
|
48
50
|
clearTailwindSafelist(debug);
|
|
49
51
|
|
|
50
52
|
/* stop command line process */
|
|
51
|
-
process.exit(
|
|
53
|
+
process.exit(DEFAULT_EXIT_CODE);
|
|
52
54
|
});
|
|
53
55
|
|
|
54
56
|
return {
|
package/types.ts
CHANGED
|
@@ -297,7 +297,7 @@ export type MutatedProps = ComputedRef<UnknownObject>;
|
|
|
297
297
|
|
|
298
298
|
export type UseUI<T> = {
|
|
299
299
|
config: Ref<T & ComponentConfig<T>>;
|
|
300
|
-
|
|
300
|
+
getDataTest: (suffix?: string) => string | null;
|
|
301
301
|
} & KeysAttrs<T>;
|
|
302
302
|
|
|
303
303
|
export type KeysAttrs<T> = Record<
|
package/ui.boilerplate/types.ts
CHANGED
package/ui.button/UButton.vue
CHANGED
|
@@ -67,10 +67,8 @@ const mutatedProps = computed(() => ({
|
|
|
67
67
|
label: Boolean(props.label),
|
|
68
68
|
}));
|
|
69
69
|
|
|
70
|
-
const { buttonAttrs, loaderAttrs, leftIconAttrs, rightIconAttrs, centerIconAttrs } =
|
|
71
|
-
defaultConfig,
|
|
72
|
-
mutatedProps,
|
|
73
|
-
);
|
|
70
|
+
const { getDataTest, buttonAttrs, loaderAttrs, leftIconAttrs, rightIconAttrs, centerIconAttrs } =
|
|
71
|
+
useUI<Config>(defaultConfig, mutatedProps);
|
|
74
72
|
</script>
|
|
75
73
|
|
|
76
74
|
<template>
|
|
@@ -82,10 +80,15 @@ const { buttonAttrs, loaderAttrs, leftIconAttrs, rightIconAttrs, centerIconAttrs
|
|
|
82
80
|
v-bind="buttonAttrs"
|
|
83
81
|
:style="buttonStyle"
|
|
84
82
|
:tabindex="!loading ? tabindex : -1"
|
|
85
|
-
:data-test="
|
|
83
|
+
:data-test="getDataTest()"
|
|
86
84
|
>
|
|
87
85
|
<template v-if="loading">
|
|
88
|
-
<ULoader
|
|
86
|
+
<ULoader
|
|
87
|
+
:loading="loading"
|
|
88
|
+
color="inherit"
|
|
89
|
+
v-bind="loaderAttrs"
|
|
90
|
+
:data-test="getDataTest('loader')"
|
|
91
|
+
/>
|
|
89
92
|
</template>
|
|
90
93
|
|
|
91
94
|
<template v-else>
|
package/ui.button/types.ts
CHANGED
package/ui.button-link/ULink.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed,
|
|
2
|
+
import { computed, useSlots } from "vue";
|
|
3
3
|
import { RouterLink, useLink } from "vue-router";
|
|
4
4
|
|
|
5
5
|
import useUI from "../composables/useUI.ts";
|
|
@@ -71,13 +71,6 @@ const useLinkOptions = {
|
|
|
71
71
|
|
|
72
72
|
const { route, isActive, isExactActive } = useLink(useLinkOptions);
|
|
73
73
|
|
|
74
|
-
const wrapperRef = ref(null);
|
|
75
|
-
|
|
76
|
-
const wrapperActiveClasses = computed(() => [
|
|
77
|
-
isActive.value && props.wrapperActiveClass,
|
|
78
|
-
isExactActive.value && props.wrapperExactActiveClass,
|
|
79
|
-
]);
|
|
80
|
-
|
|
81
74
|
const linkActiveClasses = computed(() => [
|
|
82
75
|
isActive.value && props.activeClass,
|
|
83
76
|
isExactActive.value && props.exactActiveClass,
|
|
@@ -117,14 +110,6 @@ function onBlur(event: FocusEvent) {
|
|
|
117
110
|
emit("blur", event);
|
|
118
111
|
}
|
|
119
112
|
|
|
120
|
-
defineExpose({
|
|
121
|
-
/**
|
|
122
|
-
* A reference to the link wrapper element for direct DOM manipulation.
|
|
123
|
-
* @property {HTMLElement}
|
|
124
|
-
*/
|
|
125
|
-
wrapperRef,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
113
|
/**
|
|
129
114
|
* Get element / nested component attributes for each config token ✨
|
|
130
115
|
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
@@ -134,53 +119,43 @@ const mutatedProps = computed(() => ({
|
|
|
134
119
|
defaultSlot: hasSlotContent(slots["default"]),
|
|
135
120
|
}));
|
|
136
121
|
|
|
137
|
-
const {
|
|
122
|
+
const { getDataTest, linkAttrs } = useUI<Config>(defaultConfig, mutatedProps);
|
|
138
123
|
</script>
|
|
139
124
|
|
|
140
125
|
<template>
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
@keydown="onKeydown"
|
|
177
|
-
@mouseover="onMouseover"
|
|
178
|
-
>
|
|
179
|
-
<!-- @slot Use it replace the label. -->
|
|
180
|
-
<slot>{{ label }}</slot>
|
|
181
|
-
</a>
|
|
182
|
-
|
|
183
|
-
<!-- @slot Use it to add something after the label. -->
|
|
184
|
-
<slot name="right" />
|
|
185
|
-
</div>
|
|
126
|
+
<router-link
|
|
127
|
+
v-if="isPresentRoute"
|
|
128
|
+
:to="route"
|
|
129
|
+
:target="targetValue"
|
|
130
|
+
v-bind="linkAttrs"
|
|
131
|
+
:class="linkActiveClasses"
|
|
132
|
+
:data-test="getDataTest()"
|
|
133
|
+
tabindex="0"
|
|
134
|
+
@blur="onBlur"
|
|
135
|
+
@focus="onFocus"
|
|
136
|
+
@click="onClick"
|
|
137
|
+
@keydown="onKeydown"
|
|
138
|
+
@mouseover="onMouseover"
|
|
139
|
+
>
|
|
140
|
+
<!-- @slot Use it replace the label. -->
|
|
141
|
+
<slot>{{ label }}</slot>
|
|
142
|
+
</router-link>
|
|
143
|
+
|
|
144
|
+
<a
|
|
145
|
+
v-else
|
|
146
|
+
:href="prefixedHref"
|
|
147
|
+
:target="targetValue"
|
|
148
|
+
v-bind="linkAttrs"
|
|
149
|
+
:class="linkActiveClasses"
|
|
150
|
+
:data-test="getDataTest()"
|
|
151
|
+
tabindex="0"
|
|
152
|
+
@blur="onBlur"
|
|
153
|
+
@focus="onFocus"
|
|
154
|
+
@click="onClick"
|
|
155
|
+
@keydown="onKeydown"
|
|
156
|
+
@mouseover="onMouseover"
|
|
157
|
+
>
|
|
158
|
+
<!-- @slot Use it replace the label. -->
|
|
159
|
+
<slot>{{ label }}</slot>
|
|
160
|
+
</a>
|
|
186
161
|
</template>
|
package/ui.button-link/config.ts
CHANGED
|
@@ -1,40 +1,12 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
wrapper: {
|
|
3
|
-
base: `
|
|
4
|
-
w-fit inline-flex items-center rounded transition focus-visible:outline-none
|
|
5
|
-
focus-within:ring-dynamic focus-within:ring-offset-4 focus-within:ring-{color}-700/15
|
|
6
|
-
`,
|
|
7
|
-
variants: {
|
|
8
|
-
size: {
|
|
9
|
-
sm: "gap-1",
|
|
10
|
-
md: "gap-1",
|
|
11
|
-
lg: "gap-1.5",
|
|
12
|
-
},
|
|
13
|
-
color: {
|
|
14
|
-
grayscale: "focus-within:ring-gray-700/15",
|
|
15
|
-
white: "focus-within:ring-white/15",
|
|
16
|
-
},
|
|
17
|
-
disabled: {
|
|
18
|
-
true: "!ring-0 !ring-offset-0 cursor-not-allowed",
|
|
19
|
-
},
|
|
20
|
-
defaultSlot: {
|
|
21
|
-
true: "flex items-center focus-within:ring-0 focus-within:ring-offset-0",
|
|
22
|
-
},
|
|
23
|
-
ring: {
|
|
24
|
-
false: "!ring-0 !ring-offset-0",
|
|
25
|
-
},
|
|
26
|
-
block: {
|
|
27
|
-
true: "w-full",
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
2
|
link: {
|
|
32
3
|
base: `
|
|
33
|
-
inline-block cursor-pointer !leading-none transition
|
|
4
|
+
inline-block cursor-pointer !leading-none rounded transition
|
|
34
5
|
text-{color}-600 decoration-{color}-600 underline-offset-4
|
|
35
6
|
hover:text-{color}-700 hover:decoration-{color}-700
|
|
36
7
|
focus:text-{color}-700 focus:decoration-{color}-700 focus:outline-0
|
|
37
8
|
active:text-{color}-800 active:decoration-{color}-800
|
|
9
|
+
focus:ring-dynamic focus:ring-offset-4 focus:ring-{color}-700/15
|
|
38
10
|
`,
|
|
39
11
|
variants: {
|
|
40
12
|
size: {
|
|
@@ -57,10 +29,10 @@ export default /*tw*/ {
|
|
|
57
29
|
grayscale: `
|
|
58
30
|
text-gray-900 decoration-gray-900
|
|
59
31
|
hover:text-gray-800 hover:decoration-gray-800
|
|
60
|
-
focus:text-gray-800 focus:decoration-gray-800
|
|
32
|
+
focus:text-gray-800 focus:decoration-gray-800 focus:ring-gray-700/15
|
|
61
33
|
active:text-gray-700 active:decoration-gray-700
|
|
62
34
|
`,
|
|
63
|
-
white: "decoration-white text-white",
|
|
35
|
+
white: "decoration-white text-white focus:ring-white/15",
|
|
64
36
|
},
|
|
65
37
|
defaultSlot: {
|
|
66
38
|
true: "flex items-center no-underline hover:no-underline",
|
|
@@ -71,6 +43,9 @@ export default /*tw*/ {
|
|
|
71
43
|
disabled: {
|
|
72
44
|
true: "text-gray-400 pointer-events-none",
|
|
73
45
|
},
|
|
46
|
+
ring: {
|
|
47
|
+
false: "!ring-0 !ring-offset-0",
|
|
48
|
+
},
|
|
74
49
|
block: {
|
|
75
50
|
true: "w-full",
|
|
76
51
|
},
|
|
@@ -83,11 +58,9 @@ export default /*tw*/ {
|
|
|
83
58
|
ariaCurrentValue: "page",
|
|
84
59
|
activeClass: "",
|
|
85
60
|
exactActiveClass: "",
|
|
86
|
-
wrapperActiveClass: "",
|
|
87
|
-
wrapperExactActiveClass: "",
|
|
88
61
|
underlined: undefined,
|
|
89
62
|
block: false,
|
|
90
|
-
ring:
|
|
63
|
+
ring: false,
|
|
91
64
|
dashed: false,
|
|
92
65
|
disabled: false,
|
|
93
66
|
targetBlank: false,
|
|
@@ -196,25 +196,3 @@ DefaultSlot.args = {
|
|
|
196
196
|
</template>
|
|
197
197
|
`,
|
|
198
198
|
};
|
|
199
|
-
|
|
200
|
-
export const LeftAndRightSlots: StoryFn<ULinkArgs> = (args: ULinkArgs) => ({
|
|
201
|
-
components: { ULink, UIcon, URow },
|
|
202
|
-
setup() {
|
|
203
|
-
return { args };
|
|
204
|
-
},
|
|
205
|
-
template: `
|
|
206
|
-
<URow no-mobile>
|
|
207
|
-
<ULink label="Download">
|
|
208
|
-
<template #left>
|
|
209
|
-
<UIcon name="download" size="xs" color="green" />
|
|
210
|
-
</template>
|
|
211
|
-
</ULink>
|
|
212
|
-
|
|
213
|
-
<ULink label="Open">
|
|
214
|
-
<template #right>
|
|
215
|
-
<UIcon name="open_in_new" size="xs" color="green" />
|
|
216
|
-
</template>
|
|
217
|
-
</ULink>
|
|
218
|
-
</URow>
|
|
219
|
-
`,
|
|
220
|
-
});
|
package/ui.button-link/types.ts
CHANGED
|
@@ -87,16 +87,6 @@ export interface Props {
|
|
|
87
87
|
*/
|
|
88
88
|
exactActiveClass?: string;
|
|
89
89
|
|
|
90
|
-
/**
|
|
91
|
-
* Apply classes to the wrapper div when link route is active or when it matches any parent route.
|
|
92
|
-
*/
|
|
93
|
-
wrapperActiveClass?: string;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Apply classes to the wrapper div when link route is active.
|
|
97
|
-
*/
|
|
98
|
-
wrapperExactActiveClass?: string;
|
|
99
|
-
|
|
100
90
|
/**
|
|
101
91
|
* Show underline.
|
|
102
92
|
*/
|
|
@@ -130,5 +120,5 @@ export interface Props {
|
|
|
130
120
|
/**
|
|
131
121
|
* Data-test attribute for automated testing.
|
|
132
122
|
*/
|
|
133
|
-
dataTest?: string;
|
|
123
|
+
dataTest?: string | null;
|
|
134
124
|
}
|