From 342ba880f1a601b5ed4bfe6541b3ed3def1320c8 Mon Sep 17 00:00:00 2001 From: mrholek Date: Sat, 16 Nov 2024 12:10:42 +0100 Subject: [PATCH 01/19] refactor(CNavItem): pass anchor attributes to the internal element if the href attribute is set --- packages/coreui-vue/src/components/nav/CNavItem.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/coreui-vue/src/components/nav/CNavItem.ts b/packages/coreui-vue/src/components/nav/CNavItem.ts index 48290ba7..e660c01a 100644 --- a/packages/coreui-vue/src/components/nav/CNavItem.ts +++ b/packages/coreui-vue/src/components/nav/CNavItem.ts @@ -5,10 +5,12 @@ import type { ComponentProps } from '../../utils/ComponentProps' interface CNavItemProps extends ComponentProps { as: string + class: string } const CNavItem = defineComponent({ name: 'CNavItem', + inheritAttrs: false, props: { /** * Toggle the active state for the component. @@ -21,6 +23,10 @@ const CNavItem = defineComponent({ type: String, default: 'li', }, + /** + * A string of all className you want applied to the component. + */ + class: String, /** * Toggle the disabled state for the component. */ @@ -30,17 +36,18 @@ const CNavItem = defineComponent({ */ href: String, }, - setup(props: CNavItemProps, { slots }) { + setup(props: CNavItemProps, { attrs, slots }) { return () => h( props.as, { - class: 'nav-item', + class: ['nav-item', props.class], }, props.href ? h( CNavLink, { + ...attrs, active: props.active, disabled: props.disabled, href: props.href, From 8c2827790d607a449aeafc821a80d7848a8438ba Mon Sep 17 00:00:00 2001 From: mrholek Date: Tue, 7 Jan 2025 22:39:15 +0100 Subject: [PATCH 02/19] refactor(CAccordion): improve component accessibility --- .../src/components/accordion/CAccordionBody.ts | 3 ++- .../src/components/accordion/CAccordionButton.ts | 4 +++- .../src/components/accordion/CAccordionItem.ts | 14 +++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/coreui-vue/src/components/accordion/CAccordionBody.ts b/packages/coreui-vue/src/components/accordion/CAccordionBody.ts index 4a8d83ff..c8907021 100644 --- a/packages/coreui-vue/src/components/accordion/CAccordionBody.ts +++ b/packages/coreui-vue/src/components/accordion/CAccordionBody.ts @@ -4,11 +4,12 @@ import { CCollapse } from '../collapse/CCollapse' const CAccordionBody = defineComponent({ name: 'CAccordionBody', setup(_, { slots }) { + const id = inject('id') const visible = inject('visible') as Ref return () => h( CCollapse, - { class: 'accordion-collapse', visible: visible.value }, + { class: 'accordion-collapse', id, visible: visible.value }, { default: () => h('div', { class: ['accordion-body'] }, slots.default && slots.default()), }, diff --git a/packages/coreui-vue/src/components/accordion/CAccordionButton.ts b/packages/coreui-vue/src/components/accordion/CAccordionButton.ts index 69ab7a00..f9820b4a 100644 --- a/packages/coreui-vue/src/components/accordion/CAccordionButton.ts +++ b/packages/coreui-vue/src/components/accordion/CAccordionButton.ts @@ -3,6 +3,7 @@ import { defineComponent, h, inject, Ref } from 'vue' const CAccordionButton = defineComponent({ name: 'CAccordionButton', setup(_, { slots }) { + const id = inject('id') as string const toggleVisibility = inject('toggleVisibility') as () => void const visible = inject('visible') as Ref @@ -11,7 +12,8 @@ const CAccordionButton = defineComponent({ 'button', { type: 'button', - 'aria-expanded': !visible.value, + 'aria-control': id, + 'aria-expanded': visible.value, class: ['accordion-button', { ['collapsed']: !visible.value }], onClick: () => toggleVisibility(), }, diff --git a/packages/coreui-vue/src/components/accordion/CAccordionItem.ts b/packages/coreui-vue/src/components/accordion/CAccordionItem.ts index 20575085..f2ebe594 100644 --- a/packages/coreui-vue/src/components/accordion/CAccordionItem.ts +++ b/packages/coreui-vue/src/components/accordion/CAccordionItem.ts @@ -1,8 +1,12 @@ -import { defineComponent, h, inject, provide, ref, watch, Ref } from 'vue' +import { defineComponent, h, inject, provide, ref, watch, Ref, useId } from 'vue' const CAccordionItem = defineComponent({ name: 'CAccordionItem', props: { + /** + * The id global attribute defines an identifier (ID) that must be unique in the whole document. + */ + id: String, /** * The item key. */ @@ -13,16 +17,20 @@ const CAccordionItem = defineComponent({ const alwaysOpen = inject('alwaysOpen') as boolean const setActiveItemKey = inject('setActiveItemKey') as (key: number | string) => void - const itemKey = ref(props.itemKey ?? Math.random().toString(36).slice(2, 11)) + const id = props.id ?? useId() + const itemKey = ref(props.itemKey ?? id) const visible = ref(Boolean(activeItemKey.value === itemKey.value)) watch(activeItemKey, () => (visible.value = Boolean(activeItemKey.value === itemKey.value))) const toggleVisibility = () => { visible.value = !visible.value - !alwaysOpen && visible && setActiveItemKey(itemKey.value) + if (!alwaysOpen && visible) { + setActiveItemKey(itemKey.value) + } } + provide('id', id) provide('visible', visible) provide('toggleVisibility', toggleVisibility) From 7a65f3674bca057e74196736d8d052f7c765034b Mon Sep 17 00:00:00 2001 From: mrholek Date: Tue, 7 Jan 2025 22:46:32 +0100 Subject: [PATCH 03/19] fix(CNavGroup): add the missing href attribute to the toggler --- packages/coreui-vue/src/components/nav/CNavGroup.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/coreui-vue/src/components/nav/CNavGroup.ts b/packages/coreui-vue/src/components/nav/CNavGroup.ts index 2c83ccdf..7c45bd7c 100644 --- a/packages/coreui-vue/src/components/nav/CNavGroup.ts +++ b/packages/coreui-vue/src/components/nav/CNavGroup.ts @@ -41,7 +41,10 @@ const CNavGroup = defineComponent({ onMounted(() => { visible.value = props.visible - props.visible && navGroupRef.value.classList.add('show') + if (props.visible) { + navGroupRef.value.classList.add('show') + } + emit('visible-change', visible.value) }) @@ -60,7 +63,8 @@ const CNavGroup = defineComponent({ emit('visible-change', visible.value) }) - const handleTogglerClick = () => { + const handleTogglerClick = (event: Event) => { + event.preventDefault() visible.value = !visible.value emit('visible-change', visible.value) } @@ -111,6 +115,7 @@ const CNavGroup = defineComponent({ 'a', { class: ['nav-link', 'nav-group-toggle'], + href: '#', onClick: handleTogglerClick, }, slots.togglerContent && slots.togglerContent(), From 0f0a66d2dce66b99e449484a38fdb09550f00ea2 Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 8 Jan 2025 11:10:59 +0100 Subject: [PATCH 04/19] build: upgrade ESLint to v9.x --- .eslintignore | 3 -- .eslintrc.js | 75 ---------------------------------------------- eslint.config.mjs | 76 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 18 +++++------ 4 files changed, 84 insertions(+), 88 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js create mode 100644 eslint.config.mjs diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 1846284b..00000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -/dist/** -/docs/** -.eslintrc.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index a0662dcd..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2013-present, creativeLabs Lukasz Holeczek. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -'use strict' - -module.exports = { - root: true, // So parent files don't get applied - env: { - es6: true, - browser: true, - node: true, - }, - parser: '@typescript-eslint/parser', // Specifies the ESLint parser - parserOptions: { - ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features - sourceType: 'module', // Allows for the use of imports - extraFileExtensions: ['.vue'], - }, - extends: [ - 'eslint:recommended', - 'plugin:vue/vue3-recommended', - 'plugin:prettier/recommended', - 'plugin:unicorn/recommended', - '@vue/eslint-config-typescript/recommended', - '@vue/eslint-config-prettier', - ], - rules: { - 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'unicorn/filename-case': 'off', - 'unicorn/no-array-for-each': 'off', - 'unicorn/no-null': 'off', - 'unicorn/prefer-dom-node-append': 'off', - 'unicorn/prefer-export-from': 'off', - 'unicorn/prefer-query-selector': 'off', - 'unicorn/prevent-abbreviations': 'off', - 'vue/require-default-prop': 'off', - }, - overrides: [ - { - files: ['**/*.mjs'], - env: { - browser: false, - node: true, - }, - parserOptions: { - sourceType: 'module', - }, - }, - { - files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'], - env: { - jest: true, - }, - }, - { - files: ['packages/docs/build/**'], - env: { - browser: false, - node: true, - }, - parserOptions: { - sourceType: 'script', - }, - rules: { - 'no-console': 'off', - strict: 'error', - }, - }, - ], -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..3cee3965 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,76 @@ +import eslint from '@eslint/js' +import eslintPluginUnicorn from 'eslint-plugin-unicorn' +import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' +import eslintPluginVue from 'eslint-plugin-vue' +import globals from 'globals' +import typescriptEslint from 'typescript-eslint' + +export default typescriptEslint.config( + { ignores: ['**/*.d.ts', '**/coverage', '**/dist', '**/docs', 'eslint.config.mjs'] }, + { + extends: [ + eslint.configs.recommended, + ...typescriptEslint.configs.recommended, + ...eslintPluginVue.configs['flat/recommended'], + eslintPluginUnicorn.configs['flat/recommended'], + ], + files: ['packages/**/src/**/*.{js,ts,tsx}'], + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: globals.browser, + parserOptions: { + parser: typescriptEslint.parser, + }, + }, + rules: { + 'no-console': 'off', + 'no-debugger': 'off', + 'unicorn/filename-case': 'off', + 'unicorn/no-array-for-each': 'off', + 'unicorn/no-null': 'off', + 'unicorn/prefer-dom-node-append': 'off', + 'unicorn/prefer-export-from': 'off', + 'unicorn/prefer-query-selector': 'off', + 'unicorn/prevent-abbreviations': 'off', + 'vue/require-default-prop': 'off', + }, + }, + { + files: ['**/*.mjs'], + languageOptions: { + globals: { + ...Object.fromEntries(Object.entries(globals.browser).map(([key]) => [key, 'off'])), + ...globals.node, + }, + + ecmaVersion: 5, + sourceType: 'module', + }, + }, + { + files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'], + languageOptions: { + globals: { + ...globals.jest, + }, + }, + }, + { + files: ['packages/docs/build/**'], + languageOptions: { + globals: { + ...Object.fromEntries(Object.entries(globals.browser).map(([key]) => [key, 'off'])), + ...globals.node, + }, + + ecmaVersion: 5, + sourceType: 'commonjs', + }, + rules: { + 'no-console': 'off', + strict: 'error', + }, + }, + eslintPluginPrettierRecommended, +) diff --git a/package.json b/package.json index a8e640de..37eb604e 100644 --- a/package.json +++ b/package.json @@ -17,23 +17,21 @@ "lib:build": "lerna run --scope \"@coreui/vue\" build --stream", "lib:test": "lerna run --scope \"@coreui/vue\" test --stream", "lib:test:update": "lerna run --scope \"@coreui/vue\" test:update --stream", - "lint": "eslint \"packages/**/src/**/*.{js,ts,tsx}\"", + "lint": "eslint", "test": "npm-run-all charts:test icons:test lib:test", "test:update": "npm-run-all charts:test:update icons:test:update lib:test:update" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^8.6.0", - "@typescript-eslint/parser": "^8.6.0", - "@vue/eslint-config-prettier": "^9.0.0", - "@vue/eslint-config-typescript": "^13.0.0", "@vue/vue3-jest": "29.2.6", - "eslint": "8.57.0", - "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-vue": "^9.28.0", + "eslint": "^9.17.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-unicorn": "^55.0.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-unicorn": "^56.0.1", + "eslint-plugin-vue": "^9.32.0", + "globals": "^15.14.0", "lerna": "^8.1.8", "npm-run-all": "^4.1.5", - "prettier": "^3.3.3" + "prettier": "^3.3.3", + "typescript-eslint": "^8.19.1" } } From ad4bfdfdb99fae7b710b688089731c33812ce742 Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 8 Jan 2025 11:17:13 +0100 Subject: [PATCH 05/19] build: migrate `.prettierrc.js` to `eslint.config.mjs` --- .prettierrc.js | 7 ------- eslint.config.mjs | 4 ++-- prettier.config.mjs | 13 +++++++++++++ 3 files changed, 15 insertions(+), 9 deletions(-) delete mode 100644 .prettierrc.js create mode 100644 prettier.config.mjs diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index 415ca057..00000000 --- a/.prettierrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - semi: false, - trailingComma: "all", - singleQuote: true, - printWidth: 100, - tabWidth: 2 -}; \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs index 3cee3965..15164bf5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -6,7 +6,7 @@ import globals from 'globals' import typescriptEslint from 'typescript-eslint' export default typescriptEslint.config( - { ignores: ['**/*.d.ts', '**/coverage', '**/dist', '**/docs', 'eslint.config.mjs'] }, + { ignores: ['**/*.d.ts', '**/coverage', '**/dist', '**/docs'] }, { extends: [ eslint.configs.recommended, @@ -44,7 +44,7 @@ export default typescriptEslint.config( ...globals.node, }, - ecmaVersion: 5, + ecmaVersion: 'latest', sourceType: 'module', }, }, diff --git a/prettier.config.mjs b/prettier.config.mjs new file mode 100644 index 00000000..6e0ae723 --- /dev/null +++ b/prettier.config.mjs @@ -0,0 +1,13 @@ +/** + * @see https://prettier.io/docs/en/configuration.html + * @type {import("prettier").Config} + */ +const config = { + printWidth: 100, + semi: false, + singleQuote: true, + tabWidth: 2, + trailingComma: 'es5', +}; + +export default config; \ No newline at end of file From 83d380c315404eb6152cfed0b2d687a82507fed1 Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 8 Jan 2025 11:18:14 +0100 Subject: [PATCH 06/19] chore: dependencies and devDependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lerna ^8.1.8 → ^8.1.9 prettier ^3.3.3 → ^3.4.2 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 37eb604e..9b945921 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,9 @@ "eslint-plugin-unicorn": "^56.0.1", "eslint-plugin-vue": "^9.32.0", "globals": "^15.14.0", - "lerna": "^8.1.8", + "lerna": "^8.1.9", "npm-run-all": "^4.1.5", - "prettier": "^3.3.3", + "prettier": "^3.4.2", "typescript-eslint": "^8.19.1" } } From 9eb188014652f1c912900539e2aa3145f5123edc Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 8 Jan 2025 11:19:46 +0100 Subject: [PATCH 07/19] chore: update dependencies and devDependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @rollup/plugin-commonjs ^28.0.1 → ^28.0.2 @rollup/plugin-node-resolve ^15.3.0 → ^16.0.0 @rollup/plugin-typescript ^12.1.1 → ^12.1.2 rollup ^4.24.2 → ^4.30.1 typescript ^5.6.3 → ^5.7.2 vue ^3.5.12 → ^3.5.13 --- packages/coreui-vue/package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/coreui-vue/package.json b/packages/coreui-vue/package.json index 02a7b5e2..bc94fec7 100644 --- a/packages/coreui-vue/package.json +++ b/packages/coreui-vue/package.json @@ -45,20 +45,20 @@ "@popperjs/core": "^2.11.8" }, "devDependencies": { - "@rollup/plugin-commonjs": "^28.0.1", - "@rollup/plugin-node-resolve": "^15.3.0", - "@rollup/plugin-typescript": "^12.1.1", + "@rollup/plugin-commonjs": "^28.0.2", + "@rollup/plugin-node-resolve": "^16.0.0", + "@rollup/plugin-typescript": "^12.1.2", "@types/jest": "^29.5.14", "@vue/test-utils": "^2.4.6", "@vue/vue3-jest": "29.2.6", "cross-env": "^7.0.3", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", - "rollup": "^4.24.2", + "rollup": "^4.30.1", "rollup-plugin-vue": "^6.0.0", "ts-jest": "^29.2.5", - "typescript": "^5.6.3", - "vue": "^3.5.12", + "typescript": "^5.7.2", + "vue": "^3.5.13", "vue-types": "^5.1.3" }, "peerDependencies": { From 9ffefe651379f6a02b7f9748811b83ee4095c125 Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 8 Jan 2025 11:23:55 +0100 Subject: [PATCH 08/19] chore: update dependencies and devDependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @docsearch/css ^3.6.2 → ^3.8.2 @docsearch/js ^3.6.2 → ^3.8.2 @vuepress/bundler-vite 2.0.0-rc.18 → 2.0.0-rc.19 @vuepress/bundler-webpack 2.0.0-rc.18 → 2.0.0-rc.19 @vuepress/plugin-active-header-links 2.0.0-rc.55 → 2.0.0-rc.69 @vuepress/plugin-git 2.0.0-rc.56 → 2.0.0-rc.68 @vuepress/plugin-markdown-container 2.0.0-rc.54 → 2.0.0-rc.66 @vuepress/plugin-register-components 2.0.0-rc.54 → 2.0.0-rc.66 @vuepress/plugin-theme-data 2.0.0-rc.57 → 2.0.0-rc.69 @vuepress/plugin-toc 2.0.0-rc.55 → 2.0.0-rc.66 @vuepress/shared 2.0.0-rc.18 → 2.0.0-rc.19 @vuepress/utils 2.0.0-rc.18 → 2.0.0-rc.19 sass ^1.80.4 → ^1.83.1 vuepress 2.0.0-rc.18 → 2.0.0-rc.19 --- packages/docs/package.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/docs/package.json b/packages/docs/package.json index 43b43f9c..45028b48 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -14,23 +14,23 @@ "@coreui/icons-vue": "^2.2.0", "@coreui/utils": "^2.0.2", "@coreui/vue-chartjs": "^3.0.0", - "@docsearch/css": "^3.6.2", - "@docsearch/js": "^3.6.2", - "@vuepress/bundler-vite": "2.0.0-rc.18", - "@vuepress/bundler-webpack": "2.0.0-rc.18", - "@vuepress/plugin-active-header-links": "2.0.0-rc.55", - "@vuepress/plugin-git": "2.0.0-rc.56", - "@vuepress/plugin-markdown-container": "2.0.0-rc.54", + "@docsearch/css": "^3.8.2", + "@docsearch/js": "^3.8.2", + "@vuepress/bundler-vite": "2.0.0-rc.19", + "@vuepress/bundler-webpack": "2.0.0-rc.19", + "@vuepress/plugin-active-header-links": "2.0.0-rc.69", + "@vuepress/plugin-git": "2.0.0-rc.68", + "@vuepress/plugin-markdown-container": "2.0.0-rc.66", "@vuepress/plugin-prismjs": "2.0.0-rc.37", - "@vuepress/plugin-theme-data": "2.0.0-rc.57", - "@vuepress/plugin-register-components": "2.0.0-rc.54", - "@vuepress/plugin-toc": "2.0.0-rc.55", - "@vuepress/shared": "2.0.0-rc.18", - "@vuepress/utils": "2.0.0-rc.18", + "@vuepress/plugin-theme-data": "2.0.0-rc.69", + "@vuepress/plugin-register-components": "2.0.0-rc.66", + "@vuepress/plugin-toc": "2.0.0-rc.66", + "@vuepress/shared": "2.0.0-rc.19", + "@vuepress/utils": "2.0.0-rc.19", "markdown-it-anchor": "^9.2.0", "markdown-it-include": "^2.0.0", - "sass": "^1.80.4", + "sass": "^1.83.1", "vue-docgen-cli": "^4.79.0", - "vuepress": "2.0.0-rc.18" + "vuepress": "2.0.0-rc.19" } } From 8b7e683d8eb50ca3a030d2b05ede1cf9e2c4bf75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Holeczek?= Date: Wed, 8 Jan 2025 11:37:43 +0100 Subject: [PATCH 09/19] chore: update the current year --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index f19fc729..fbb053e0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 creativeLabs Łukasz Holeczek +Copyright (c) 2025 creativeLabs Łukasz Holeczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. From 49180937bf5172e80f3fb2a578db44012cff1b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Holeczek?= Date: Wed, 8 Jan 2025 11:38:12 +0100 Subject: [PATCH 10/19] chore: update the current year --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e21d4f28..3d4aab99 100644 --- a/README.md +++ b/README.md @@ -227,4 +227,4 @@ CoreUI is an MIT-licensed open source project and is completely free to use. How ## Copyright and license -Copyright 2024 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-vue/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). +Copyright 2025 creativeLabs Łukasz Holeczek. Code released under the [MIT License](https://github.com/coreui/coreui-vue/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). From 9f310bb700dee6f30dab3748de333a605127d0fc Mon Sep 17 00:00:00 2001 From: mrholek Date: Tue, 6 May 2025 13:45:48 +0200 Subject: [PATCH 11/19] build: add .prettierc for docgen cli --- packages/docs/.prettierrc | 8 ++++++++ packages/docs/api/accordion/CAccordionItem.api.md | 7 ++++--- packages/docs/api/form/CFormControlWrapper.api.md | 11 ++++++----- packages/docs/api/nav/CNavItem.api.md | 1 + 4 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 packages/docs/.prettierrc diff --git a/packages/docs/.prettierrc b/packages/docs/.prettierrc new file mode 100644 index 00000000..53e4559d --- /dev/null +++ b/packages/docs/.prettierrc @@ -0,0 +1,8 @@ +{ + "semi": false, + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2 + +} diff --git a/packages/docs/api/accordion/CAccordionItem.api.md b/packages/docs/api/accordion/CAccordionItem.api.md index 753acd83..3e07d5aa 100644 --- a/packages/docs/api/accordion/CAccordionItem.api.md +++ b/packages/docs/api/accordion/CAccordionItem.api.md @@ -8,6 +8,7 @@ import CAccordionItem from '@coreui/vue/src/components/accordion/CAccordionItem' #### Props -| Prop name | Description | Type | Values | Default | -| ------------ | ------------- | -------------- | ------ | ------- | -| **item-key** | The item key. | number\|string | - | - | +| Prop name | Description | Type | Values | Default | +| ------------ | --------------------------------------------------------------------------------------------- | -------------- | ------ | ------- | +| **id** | The id global attribute defines an identifier (ID) that must be unique in the whole document. | string | - | - | +| **item-key** | The item key. | number\|string | - | - | diff --git a/packages/docs/api/form/CFormControlWrapper.api.md b/packages/docs/api/form/CFormControlWrapper.api.md index c4d97891..ebce3a46 100644 --- a/packages/docs/api/form/CFormControlWrapper.api.md +++ b/packages/docs/api/form/CFormControlWrapper.api.md @@ -8,8 +8,9 @@ import CFormControlWrapper from '@coreui/vue/src/components/form/CFormControlWra #### Props -| Prop name | Description | Type | Values | Default | -| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------ | ------- | -| **floating-label**
4.3.0+
| Provide valuable, actionable valid feedback when using standard HTML form validation which applied two CSS pseudo-classes, `:invalid` and `:valid`. | string | - | - | -| **label**
4.3.0+
| Add a caption for a component. | string | - | - | -| **text**
4.3.0+
| Add helper text to the component. | string | - | - | +| Prop name | Description | Type | Values | Default | +| ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------ | ------- | +| **floating-class-name**
5.5.0+
| A string of all className you want applied to the floating label wrapper. | string | - | - | +| **floating-label**
4.3.0+
| Provide valuable, actionable valid feedback when using standard HTML form validation which applied two CSS pseudo-classes, `:invalid` and `:valid`. | string | - | - | +| **label**
4.3.0+
| Add a caption for a component. | string | - | - | +| **text**
4.3.0+
| Add helper text to the component. | string | - | - | diff --git a/packages/docs/api/nav/CNavItem.api.md b/packages/docs/api/nav/CNavItem.api.md index bba531c6..788b3792 100644 --- a/packages/docs/api/nav/CNavItem.api.md +++ b/packages/docs/api/nav/CNavItem.api.md @@ -12,4 +12,5 @@ import CNavItem from '@coreui/vue/src/components/nav/CNavItem' | ------------ | --------------------------------------------------------------------------------------- | ------- | ------ | ------- | | **active** | Toggle the active state for the component. | boolean | - | - | | **as** | Component used for the root node. Either a string to use a HTML element or a component. | string | - | 'li' | +| **class** | A string of all className you want applied to the component. | string | - | - | | **disabled** | Toggle the disabled state for the component. | boolean | - | - | From c43c76b9d991041b19ad06912469585031236928 Mon Sep 17 00:00:00 2001 From: mrholek Date: Tue, 6 May 2025 13:48:40 +0200 Subject: [PATCH 12/19] feat(CFormControlWrapper): allow passing class names to the CFormFloaging component --- .../components/form/CFormControlWrapper.ts | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/coreui-vue/src/components/form/CFormControlWrapper.ts b/packages/coreui-vue/src/components/form/CFormControlWrapper.ts index bdecc2ff..0ed3d195 100644 --- a/packages/coreui-vue/src/components/form/CFormControlWrapper.ts +++ b/packages/coreui-vue/src/components/form/CFormControlWrapper.ts @@ -7,6 +7,7 @@ import { CFormText } from './CFormText' import type { ComponentProps } from '../../utils/ComponentProps' interface CFormControlWrapperProps extends ComponentProps { + floatingClassName?: string floatingLabel?: string id?: string label?: string @@ -18,6 +19,12 @@ const CFormControlWrapper = defineComponent({ inheritAttrs: false, props: { ...CFormControlValidation.props, + /** + * A string of all className you want applied to the floating label wrapper. + * + * @since 5.5.0 + */ + floatingClassName: String, /** * Provide valuable, actionable valid feedback when using standard HTML form validation which applied two CSS pseudo-classes, `:invalid` and `:valid`. * @@ -69,29 +76,36 @@ const CFormControlWrapper = defineComponent({ return () => props.floatingLabel - ? h(CFormFloating, () => [ - slots.default && slots.default(), - h( - CFormLabel, - { - for: props.id, - }, - { - default: () => (slots.label && slots.label()) || props.label || props.floatingLabel, - }, - ), - (props.text || slots.text) && + ? h( + CFormFloating, + { + class: props.floatingClassName, + }, + () => [ + slots.default && slots.default(), h( - CFormText, + CFormLabel, { - id: props.describedby, + for: props.id, }, { - default: () => (slots.text && slots.text()) || props.text, + default: () => + (slots.label && slots.label()) || props.label || props.floatingLabel, }, ), - formControlValidation(), - ]) + (props.text || slots.text) && + h( + CFormText, + { + id: props.describedby, + }, + { + default: () => (slots.text && slots.text()) || props.text, + }, + ), + formControlValidation(), + ], + ) : [ (props.label || slots.label) && h( From e024754a69ab46b041d781de23c0401cfed8bcdd Mon Sep 17 00:00:00 2001 From: mrholek Date: Tue, 6 May 2025 14:05:22 +0200 Subject: [PATCH 13/19] chore: clean-up --- prettier.config.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prettier.config.mjs b/prettier.config.mjs index 6e0ae723..c901ceaf 100644 --- a/prettier.config.mjs +++ b/prettier.config.mjs @@ -8,6 +8,6 @@ const config = { singleQuote: true, tabWidth: 2, trailingComma: 'es5', -}; +} -export default config; \ No newline at end of file +export default config From ed1b8df741c2d37a1da4a854d72557e48491384c Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 4 Jun 2025 12:12:02 +0200 Subject: [PATCH 14/19] chore: update dependencies and devDependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @coreui/coreui ^5.2.0 → ^5.4.0 @docsearch/css ^3.8.2 → ^3.9.0 @docsearch/js ^3.8.2 → ^3.9.0 @rollup/plugin-commonjs ^28.0.2 → ^28.0.3 @rollup/plugin-node-resolve ^16.0.0 → ^16.0.1 eslint ^9.17.0 → ^9.28.0 eslint-config-prettier ^9.1.0 → ^10.1.5 eslint-plugin-prettier ^5.2.1 → ^5.4.1 eslint-plugin-unicorn ^56.0.1 → ^59.0.1 eslint-plugin-vue ^9.32.0 → ^10.1.0 globals ^15.14.0 → ^16.2.0 lerna ^8.1.9 → ^8.2.2 prettier ^3.4.2 → ^3.5.3 rollup ^4.30.1 → ^4.41.1 sass ^1.83.1 → ^1.89.1 ts-jest ^29.2.5 → ^29.3.4 typescript ^5.7.2 → ^5.8.3 typescript-eslint ^8.19.1 → ^8.33.1 vue ^3.5.13 → ^3.5.16 vue-types ^5.1.3 → ^6.0.0 --- package.json | 18 +- packages/coreui-vue/package.json | 16 +- .../src/components/stepper/CStepper.ts | 266 ++++++++++++++++++ .../stepper/__tests__/CBadge.spec.ts | 39 +++ .../__snapshots__/CBadge.spec.ts.snap | 15 + .../src/components/stepper/index.ts | 10 + .../src/components/stepper/types.ts | 20 ++ packages/docs/package.json | 8 +- 8 files changed, 371 insertions(+), 21 deletions(-) create mode 100644 packages/coreui-vue/src/components/stepper/CStepper.ts create mode 100644 packages/coreui-vue/src/components/stepper/__tests__/CBadge.spec.ts create mode 100644 packages/coreui-vue/src/components/stepper/__tests__/__snapshots__/CBadge.spec.ts.snap create mode 100644 packages/coreui-vue/src/components/stepper/index.ts create mode 100644 packages/coreui-vue/src/components/stepper/types.ts diff --git a/package.json b/package.json index 9b945921..7b5343e7 100644 --- a/package.json +++ b/package.json @@ -23,15 +23,15 @@ }, "devDependencies": { "@vue/vue3-jest": "29.2.6", - "eslint": "^9.17.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-unicorn": "^56.0.1", - "eslint-plugin-vue": "^9.32.0", - "globals": "^15.14.0", - "lerna": "^8.1.9", + "eslint": "^9.28.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.4.1", + "eslint-plugin-unicorn": "^59.0.1", + "eslint-plugin-vue": "^10.1.0", + "globals": "^16.2.0", + "lerna": "^8.2.2", "npm-run-all": "^4.1.5", - "prettier": "^3.4.2", - "typescript-eslint": "^8.19.1" + "prettier": "^3.5.3", + "typescript-eslint": "^8.33.1" } } diff --git a/packages/coreui-vue/package.json b/packages/coreui-vue/package.json index bc94fec7..7cbb6585 100644 --- a/packages/coreui-vue/package.json +++ b/packages/coreui-vue/package.json @@ -41,12 +41,12 @@ "test:update": "jest --coverage --updateSnapshot" }, "dependencies": { - "@coreui/coreui": "^5.2.0", + "@coreui/coreui": "^5.4.0", "@popperjs/core": "^2.11.8" }, "devDependencies": { - "@rollup/plugin-commonjs": "^28.0.2", - "@rollup/plugin-node-resolve": "^16.0.0", + "@rollup/plugin-commonjs": "^28.0.3", + "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-typescript": "^12.1.2", "@types/jest": "^29.5.14", "@vue/test-utils": "^2.4.6", @@ -54,12 +54,12 @@ "cross-env": "^7.0.3", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", - "rollup": "^4.30.1", + "rollup": "^4.41.1", "rollup-plugin-vue": "^6.0.0", - "ts-jest": "^29.2.5", - "typescript": "^5.7.2", - "vue": "^3.5.13", - "vue-types": "^5.1.3" + "ts-jest": "^29.3.4", + "typescript": "^5.8.3", + "vue": "^3.5.16", + "vue-types": "^6.0.0" }, "peerDependencies": { "vue": "^3.5.0" diff --git a/packages/coreui-vue/src/components/stepper/CStepper.ts b/packages/coreui-vue/src/components/stepper/CStepper.ts new file mode 100644 index 00000000..42df9bf4 --- /dev/null +++ b/packages/coreui-vue/src/components/stepper/CStepper.ts @@ -0,0 +1,266 @@ +// CStepper.ts +import { + defineComponent, + h, + ref, + watch, + computed, + nextTick, + onMounted, + toRefs, + shallowRef, + watchEffect, +} from 'vue' +import { CCollapse } from '../collapse' +import type { StepperStepData, StepperStepValidationResult } from './types' + +export const CStepper = defineComponent({ + name: 'CStepper', + inheritAttrs: false, + props: { + modelValue: Number, + defaultActiveStepIndex: { + type: Number, + default: 0, + }, + layout: { + type: String as () => 'horizontal' | 'vertical', + default: 'horizontal', + }, + linear: { + type: Boolean, + default: true, + }, + steps: { + type: Array as () => StepperStepData[], + required: true, + }, + stepButtonLayout: { + type: String as () => 'horizontal' | 'vertical', + default: 'horizontal', + }, + validation: { + type: Boolean, + default: true, + }, + id: String, + }, + emits: ['update:modelValue', 'finish', 'reset', 'stepChange', 'stepValidationComplete'], + setup(props, { emit, slots, attrs, expose }) { + const { modelValue, defaultActiveStepIndex, validation, steps, layout, linear } = toRefs(props) + + const activeStepIndex = ref(modelValue.value ?? defaultActiveStepIndex.value ?? 0) + const isControlled = computed(() => modelValue.value !== undefined) + const isFinished = ref(false) + const stepsRef = ref(null) + const stepButtonRefs = shallowRef<(HTMLButtonElement | null)[]>([]) + + watch(modelValue, (val) => { + if (val !== undefined) activeStepIndex.value = val + }) + + watch(activeStepIndex, (val) => { + if (isControlled.value) emit('update:modelValue', val) + }) + + const isStepValid = (index: number): boolean => { + if (!validation.value) return true + + const form = steps.value[index]?.formRef?.value + if (!form) return true + + const valid = form.checkValidity() + emit('stepValidationComplete', { stepNumber: index + 1, isValid: valid }) + if (!valid) form.reportValidity() + return valid + } + + const setActiveStep = (index: number, bypassValidation = false) => { + if (index < 0 || index >= steps.value.length || index === activeStepIndex.value) return + if (!bypassValidation && index > activeStepIndex.value && !isStepValid(activeStepIndex.value)) + return + + activeStepIndex.value = index + emit('stepChange', index + 1) + } + + const next = () => { + if (activeStepIndex.value < steps.value.length - 1) { + setActiveStep(activeStepIndex.value + 1) + } else { + finish() + } + } + + const prev = () => { + if (activeStepIndex.value > 0) { + setActiveStep(activeStepIndex.value - 1, true) + } + } + + const finish = () => { + if (activeStepIndex.value === steps.value.length - 1 && isStepValid(activeStepIndex.value)) { + isFinished.value = true + emit('finish') + } + } + + const reset = () => { + if (validation.value) { + steps.value.forEach((s) => s.formRef?.value?.reset?.()) + } + activeStepIndex.value = defaultActiveStepIndex.value + isFinished.value = false + emit('reset') + emit('stepChange', defaultActiveStepIndex.value) + nextTick(() => { + stepButtonRefs.value[defaultActiveStepIndex.value]?.focus() + }) + } + + const handleKeyDown = (event: KeyboardEvent) => { + const buttons = stepButtonRefs.value + const current = event.target as HTMLButtonElement + const index = buttons.findIndex((b) => b === current) + if (index === -1) return + + let nextIndex = index + switch (event.key) { + case 'ArrowRight': + case 'ArrowDown': + nextIndex = (index + 1) % buttons.length + break + case 'ArrowLeft': + case 'ArrowUp': + nextIndex = (index - 1 + buttons.length) % buttons.length + break + case 'Home': + nextIndex = 0 + break + case 'End': + nextIndex = buttons.length - 1 + break + default: + return + } + + event.preventDefault() + buttons[nextIndex]?.focus() + } + + expose({ next, prev, finish, reset }) + + return () => { + const isVertical = layout.value === 'vertical' + stepButtonRefs.value = [] + + return h( + 'div', + { + ...attrs, + class: ['stepper', { 'stepper-vertical': isVertical }, attrs.class], + }, + [ + h( + 'ol', + { + class: 'stepper-steps', + role: 'tablist', + 'aria-orientation': isVertical ? 'vertical' : 'horizontal', + onKeydown: handleKeyDown, + ref: stepsRef, + }, + steps.value.map((step, index) => { + const isActive = !isFinished.value && index === activeStepIndex.value + const isComplete = isFinished.value || index < activeStepIndex.value + const isDisabled = + isFinished.value || (linear.value && index > activeStepIndex.value + 1) + const stepId = `step-${props.id || 'stepper'}-${index}` + const panelId = `panel-${props.id || 'stepper'}-${index}` + + return h( + 'li', + { + key: index, + class: ['stepper-step', props.stepButtonLayout], + role: 'presentation', + }, + [ + h( + 'button', + { + type: 'button', + class: ['stepper-step-button', { active: isActive, complete: isComplete }], + disabled: isDisabled, + id: stepId, + role: 'tab', + 'aria-selected': isActive, + tabindex: isActive ? 0 : -1, + 'aria-controls': step.content ? panelId : undefined, + onClick: () => + setActiveStep(index, !linear.value || index <= activeStepIndex.value), + ref: (el) => (stepButtonRefs.value[index] = el as HTMLButtonElement), + }, + [ + h('span', { class: 'stepper-step-indicator' }, [ + isComplete + ? h('span', { class: 'stepper-step-indicator-icon' }) + : h( + 'span', + { class: 'stepper-step-indicator-text' }, + step.indicator ?? index + 1 + ), + ]), + h('span', { class: 'stepper-step-label' }, step.label), + ] + ), + index < steps.value.length - 1 && h('div', { class: 'stepper-step-connector' }), + step.content && + isVertical && + h( + CCollapse, + { + class: 'stepper-step-content', + id: panelId, + role: 'tabpanel', + visible: isActive, + 'aria-hidden': !isActive, + 'aria-labelledby': stepId, + 'aria-live': 'polite', + }, + () => step.content + ), + ] + ) + }) + ), + !isVertical && + steps.value.some((s) => s.content != null) && + h( + 'div', + { class: 'stepper-content' }, + steps.value.map((step, index) => { + const isActive = !isFinished.value && index === activeStepIndex.value + const stepId = `step-${props.id || 'stepper'}-${index}` + const panelId = `panel-${props.id || 'stepper'}-${index}` + + return h( + 'div', + { + key: index, + id: panelId, + role: 'tabpanel', + 'aria-hidden': !isActive, + 'aria-labelledby': stepId, + 'aria-live': 'polite', + class: ['stepper-pane', { active: isActive, show: isActive }], + }, + step.content + ) + }) + ), + ] + ) + } + }, +}) diff --git a/packages/coreui-vue/src/components/stepper/__tests__/CBadge.spec.ts b/packages/coreui-vue/src/components/stepper/__tests__/CBadge.spec.ts new file mode 100644 index 00000000..4d132901 --- /dev/null +++ b/packages/coreui-vue/src/components/stepper/__tests__/CBadge.spec.ts @@ -0,0 +1,39 @@ +import { shallowMount } from '@vue/test-utils' +import { CBadge as Component } from '../../' + +const ComponentName = 'CBadge' +const wrapper = shallowMount(Component) +const customWrapper = shallowMount(Component, { + props: { + color: 'success', + }, + attrs: { + class: 'bazinga', + }, + slots: { + default: 'Hello World!', + }, +}) + +describe(`Loads and display ${ComponentName} component`, () => { + it('has a name', () => { + expect(Component.name).toMatch(ComponentName) + }) + it('renders correctly', () => { + expect(wrapper.element).toMatchSnapshot() + }) + it('renders correctly with slot', () => { + expect(customWrapper.element).toMatchSnapshot() + }) +}) + +describe(`Customize ${ComponentName} component`, () => { + it('has a prope class names', () => { + expect(customWrapper.classes('bazinga')).toBe(true) + expect(customWrapper.classes('badge')).toBe(true) + expect(customWrapper.classes('bg-success')).toBe(true) + }) + it('default slot contains text', () => { + expect(customWrapper.text()).toBe('Hello World!') + }) +}) diff --git a/packages/coreui-vue/src/components/stepper/__tests__/__snapshots__/CBadge.spec.ts.snap b/packages/coreui-vue/src/components/stepper/__tests__/__snapshots__/CBadge.spec.ts.snap new file mode 100644 index 00000000..249fb4fd --- /dev/null +++ b/packages/coreui-vue/src/components/stepper/__tests__/__snapshots__/CBadge.spec.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Loads and display CBadge component renders correctly 1`] = ` + +`; + +exports[`Loads and display CBadge component renders correctly with slot 1`] = ` + + Hello World! + +`; diff --git a/packages/coreui-vue/src/components/stepper/index.ts b/packages/coreui-vue/src/components/stepper/index.ts new file mode 100644 index 00000000..93b9c047 --- /dev/null +++ b/packages/coreui-vue/src/components/stepper/index.ts @@ -0,0 +1,10 @@ +import { App } from 'vue' +import { CStepper } from './CStepper' + +const CStepperPlugin = { + install: (app: App): void => { + app.component(CStepper.name as string, CStepper) + }, +} + +export { CStepper, CStepperPlugin } diff --git a/packages/coreui-vue/src/components/stepper/types.ts b/packages/coreui-vue/src/components/stepper/types.ts new file mode 100644 index 00000000..a2cc6bcf --- /dev/null +++ b/packages/coreui-vue/src/components/stepper/types.ts @@ -0,0 +1,20 @@ +import type { VNode, Ref } from 'vue' + +export interface StepperRef { + next: () => void + prev: () => void + finish: () => void + reset: () => void +} + +export interface StepperStepData { + indicator?: VNode + label: VNode + content?: VNode + formRef?: Ref // Opcjonalny ref do walidacji +} + +export type StepperStepValidationResult = { + stepNumber: number + isValid: boolean +} diff --git a/packages/docs/package.json b/packages/docs/package.json index 45028b48..10463eb4 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -9,13 +9,13 @@ "license": "MIT", "devDependencies": { "@coreui/chartjs": "^4.0.0", - "@coreui/coreui": "^5.2.0", + "@coreui/coreui": "^5.4.0", "@coreui/icons": "^3.0.1", "@coreui/icons-vue": "^2.2.0", "@coreui/utils": "^2.0.2", "@coreui/vue-chartjs": "^3.0.0", - "@docsearch/css": "^3.8.2", - "@docsearch/js": "^3.8.2", + "@docsearch/css": "^3.9.0", + "@docsearch/js": "^3.9.0", "@vuepress/bundler-vite": "2.0.0-rc.19", "@vuepress/bundler-webpack": "2.0.0-rc.19", "@vuepress/plugin-active-header-links": "2.0.0-rc.69", @@ -29,7 +29,7 @@ "@vuepress/utils": "2.0.0-rc.19", "markdown-it-anchor": "^9.2.0", "markdown-it-include": "^2.0.0", - "sass": "^1.83.1", + "sass": "^1.89.1", "vue-docgen-cli": "^4.79.0", "vuepress": "2.0.0-rc.19" } From f0ad650a7d7318a23e7eeb95494d14e69eb294d7 Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 4 Jun 2025 12:31:48 +0200 Subject: [PATCH 15/19] feat(CButton): add support for unthemed outline and ghost buttons --- .../src/components/button/CButton.ts | 2 +- packages/docs/components/button.md | 43 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/packages/coreui-vue/src/components/button/CButton.ts b/packages/coreui-vue/src/components/button/CButton.ts index 287bfd12..70f7e90d 100644 --- a/packages/coreui-vue/src/components/button/CButton.ts +++ b/packages/coreui-vue/src/components/button/CButton.ts @@ -93,9 +93,9 @@ export const CButton = defineComponent({ { class: [ 'btn', + props.variant && props.color ? `btn-${props.variant}-${props.color}` : `btn-${props.variant}`, { [`btn-${props.color}`]: props.color && !props.variant, - [`btn-${props.variant}-${props.color}`]: props.color && props.variant, [`btn-${props.size}`]: props.size, active: props.active, disabled: props.disabled, diff --git a/packages/docs/components/button.md b/packages/docs/components/button.md index 0f9a8428..fe592e77 100644 --- a/packages/docs/components/button.md +++ b/packages/docs/components/button.md @@ -63,7 +63,27 @@ If you're using `` component as `` elements that are used to trigger ## Outline buttons -If you need a button, but without the strong background colors. Set `variant="outline"` prop to remove all background colors. +### Base outline style + +The `variant="outline` property provides a neutral outline button style without any color modifiers. It’s useful as a foundation for minimal buttons without background color or strong visual emphasis. + +::: demo +Base outline button +Active state +Disabled state +::: +```vue +Base outline button +Active state +Disabled state +``` + +These Vue buttons use a transparent background, subtle border, and inherit text color from the parent context. They’re best suited for minimalist UI elements like modals, toolbars, or secondary actions. + + +### Themed outline variants + +If you need a button, but without the strong background colors, set `color` and `variant=" outline"` props to remove all background colors. ::: demo Primary @@ -86,10 +106,31 @@ If you need a button, but without the strong background colors. Set `variant="ou Dark ``` +These outline variants of our Vue.js buttons retain transparent backgrounds by default, but display a background tint on hover or focus to indicate interactivity. They’re ideal for secondary actions when you want to differentiate from the standard buttons visually. + ## Ghost buttons +### Base ghost style + +Use the `variant="ghost"` property to create ultra-minimalist buttons with no borders and a fully transparent background. These Vue buttons rely solely on text color for visibility and apply a background highlight when hovered over or in an active state. + +They’re perfect for interfaces where you want buttons to be present but visually unobtrusive—such as action buttons in modals, cards, or toolbars. + If you need a ghost variant of button, set `variant="ghost"` prop to remove all background colors. +::: demo +Base ghost button +Active state +Disabled state +::: +```vue +Base ghost button +Active state +Disabled state +``` + +To apply theme colors to Vue ghost buttons, use the `color` and `variant="ghost"` properties. By default, these variants color only the text. On hover or focus, they add a background that corresponds to the theme color. + ::: demo Primary Secondary From 5c26db6c43209bde854564f0777faf6932b199aa Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 4 Jun 2025 12:41:22 +0200 Subject: [PATCH 16/19] feat(CNav): add enclosed variants --- .../coreui-vue/src/components/nav/CNav.ts | 5 +- packages/docs/api/tabs/CTabList.api.md | 8 +- packages/docs/components/navs-tabs.md | 90 +++++++++++++++++++ 3 files changed, 97 insertions(+), 6 deletions(-) diff --git a/packages/coreui-vue/src/components/nav/CNav.ts b/packages/coreui-vue/src/components/nav/CNav.ts index 922603e9..6b5b7384 100644 --- a/packages/coreui-vue/src/components/nav/CNav.ts +++ b/packages/coreui-vue/src/components/nav/CNav.ts @@ -24,12 +24,12 @@ const CNav = defineComponent({ /** * Set the nav variant to tabs or pills. * - * @values 'pills', 'tabs', 'underline', 'underline-border' + * @values 'enclosed', 'enclosed-pills', 'pills', 'tabs', 'underline', 'underline-border' */ variant: { type: String, validator: (value: string) => { - return ['pills', 'tabs', 'underline', 'underline-border'].includes(value) + return ['enclosed', 'enclosed-pills', 'pills', 'tabs', 'underline', 'underline-border'].includes(value) }, }, }, @@ -40,6 +40,7 @@ const CNav = defineComponent({ { class: [ 'nav', + props.variant === 'enclosed-pills' && 'nav-enclosed', { [`nav-${props.layout}`]: props.layout, [`nav-${props.variant}`]: props.variant, diff --git a/packages/docs/api/tabs/CTabList.api.md b/packages/docs/api/tabs/CTabList.api.md index 68b9ca46..c12138af 100644 --- a/packages/docs/api/tabs/CTabList.api.md +++ b/packages/docs/api/tabs/CTabList.api.md @@ -8,7 +8,7 @@ import CTabList from '@coreui/vue/src/components/tabs/CTabList' #### Props -| Prop name | Description | Type | Values | Default | -| ----------- | ------------------------------------- | ------ | -------------------------------------------------------- | ------- | -| **layout** | Specify a layout type for component. | string | `'fill'`, `'justified'` | - | -| **variant** | Set the nav variant to tabs or pills. | string | `'pills'`, `'tabs'`, `'underline'`, `'underline-border'` | - | +| Prop name | Description | Type | Values | Default | +| ----------- | ------------------------------------- | ------ | ------------------------------------------------------------------------------------------ | ------- | +| **layout** | Specify a layout type for component. | string | `'fill'`, `'justified'` | - | +| **variant** | Set the nav variant to tabs or pills. | string | `'enclosed'`, `'enclosed-pills'`, `'pills'`, `'tabs'`, `'underline'`, `'underline-border'` | - | diff --git a/packages/docs/components/navs-tabs.md b/packages/docs/components/navs-tabs.md index 1452f180..9ad84051 100644 --- a/packages/docs/components/navs-tabs.md +++ b/packages/docs/components/navs-tabs.md @@ -402,6 +402,96 @@ Take that same code, but use `variant="underline-border"` instead: ``` +### Enclosed + +Use the `variant="enclosed"` class to give your navigation items a subtle border and rounded styling. + +::: demo + + + + Active + + + + Link + + + Link + + + + Disabled + + + +::: +```vue + + + + Active + + + + Link + + + Link + + + + Disabled + + + +``` + +### Enclosed pills + +Use the `variant="enclosed-pills"` to achieve a pill-style appearance for each nav item, using pill-shaped borders and smoother outlines. + +::: demo + + + + Active + + + + Link + + + Link + + + + Disabled + + + +::: +```vue + + + + Active + + + + Link + + + Link + + + + Disabled + + + +``` + ### Fill and justify Force your `.nav`'s contents to extend the full available width one of two modifier classes. To proportionately fill all available space with your `.nav-item`s, use `layout="fill"`. Notice that all horizontal space is occupied, but not every nav item has the same width. From 7826e36392c5524a5b827e33992d05c0512e09d0 Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 4 Jun 2025 12:56:23 +0200 Subject: [PATCH 17/19] feat(CTabs): add enclosed variants --- .../src/components/tabs/CTabList.ts | 5 +- packages/docs/api/nav/CNav.api.md | 10 +- packages/docs/components/tabs.md | 106 ++++++++++++++++++ 3 files changed, 114 insertions(+), 7 deletions(-) diff --git a/packages/coreui-vue/src/components/tabs/CTabList.ts b/packages/coreui-vue/src/components/tabs/CTabList.ts index 63b720f2..d73bb17d 100644 --- a/packages/coreui-vue/src/components/tabs/CTabList.ts +++ b/packages/coreui-vue/src/components/tabs/CTabList.ts @@ -18,12 +18,12 @@ const CTabList = defineComponent({ /** * Set the nav variant to tabs or pills. * - * @values 'pills', 'tabs', 'underline', 'underline-border' + * @values 'enclosed', 'enclosed-pills', 'pills', 'tabs', 'underline', 'underline-border' */ variant: { type: String, validator: (value: string) => { - return ['pills', 'tabs', 'underline', 'underline-border'].includes(value) + return ['enclosed', 'enclosed-pills', 'pills', 'tabs', 'underline', 'underline-border'].includes(value) }, }, }, @@ -72,6 +72,7 @@ const CTabList = defineComponent({ { class: [ 'nav', + props.variant === 'enclosed-pills' && 'nav-enclosed', { [`nav-${props.layout}`]: props.layout, [`nav-${props.variant}`]: props.variant, diff --git a/packages/docs/api/nav/CNav.api.md b/packages/docs/api/nav/CNav.api.md index deda7877..37c9f02c 100644 --- a/packages/docs/api/nav/CNav.api.md +++ b/packages/docs/api/nav/CNav.api.md @@ -8,8 +8,8 @@ import CNav from '@coreui/vue/src/components/nav/CNav' #### Props -| Prop name | Description | Type | Values | Default | -| ----------- | --------------------------------------------------------------------------------------- | ------ | -------------------------------------------------------- | ------- | -| **as** | Component used for the root node. Either a string to use a HTML element or a component. | string | - | 'ul' | -| **layout** | Specify a layout type for component. | string | `'fill'`, `'justified'` | - | -| **variant** | Set the nav variant to tabs or pills. | string | `'pills'`, `'tabs'`, `'underline'`, `'underline-border'` | - | +| Prop name | Description | Type | Values | Default | +| ----------- | --------------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------ | ------- | +| **as** | Component used for the root node. Either a string to use a HTML element or a component. | string | - | 'ul' | +| **layout** | Specify a layout type for component. | string | `'fill'`, `'justified'` | - | +| **variant** | Set the nav variant to tabs or pills. | string | `'enclosed'`, `'enclosed-pills'`, `'pills'`, `'tabs'`, `'underline'`, `'underline-border'` | - | diff --git a/packages/docs/components/tabs.md b/packages/docs/components/tabs.md index fcb3dd2a..33b8a72d 100644 --- a/packages/docs/components/tabs.md +++ b/packages/docs/components/tabs.md @@ -275,6 +275,112 @@ Take that same code, but use `variant="underline-border"` instead: ``` +### Enclosed + +Use the `variant="enclosed"` class to give your tab items a subtle border and rounded styling. + +::: demo + + + Home + Profile + Contact + Disabled + + + + Home tab content + + + Profile tab content + + + Contact tab content + + + Disabled tab content + + + +::: +```vue + + + Home + Profile + Contact + Disabled + + + + Home tab content + + + Profile tab content + + + Contact tab content + + + Disabled tab content + + + +``` + +### Enclosed pills + +Use the `variant="enclosed-pills"` to achieve a pill-style appearance for each tab item, using pill-shaped borders and smoother outlines. + +::: demo + + + Home + Profile + Contact + Disabled + + + + Home tab content + + + Profile tab content + + + Contact tab content + + + Disabled tab content + + + +::: +```vue + + + Home + Profile + Contact + Disabled + + + + Home tab content + + + Profile tab content + + + Contact tab content + + + Disabled tab content + + + +``` + ### Fill and justify Force your ``'s contents to extend the full available width one of two modifier classes. To proportionately fill all available space use `layout="fill"`. Notice that all horizontal space is occupied, but not every nav item has the same width. From 1b0ed7177caec29f7960b82cdd92dbc7c5b0e07b Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 4 Jun 2025 12:57:49 +0200 Subject: [PATCH 18/19] chore: clean-up --- .../src/components/stepper/CStepper.ts | 266 ------------------ .../stepper/__tests__/CBadge.spec.ts | 39 --- .../__snapshots__/CBadge.spec.ts.snap | 15 - .../src/components/stepper/index.ts | 10 - .../src/components/stepper/types.ts | 20 -- packages/docs/api/stepper/CStepper.api.md | 22 ++ 6 files changed, 22 insertions(+), 350 deletions(-) delete mode 100644 packages/coreui-vue/src/components/stepper/CStepper.ts delete mode 100644 packages/coreui-vue/src/components/stepper/__tests__/CBadge.spec.ts delete mode 100644 packages/coreui-vue/src/components/stepper/__tests__/__snapshots__/CBadge.spec.ts.snap delete mode 100644 packages/coreui-vue/src/components/stepper/index.ts delete mode 100644 packages/coreui-vue/src/components/stepper/types.ts create mode 100644 packages/docs/api/stepper/CStepper.api.md diff --git a/packages/coreui-vue/src/components/stepper/CStepper.ts b/packages/coreui-vue/src/components/stepper/CStepper.ts deleted file mode 100644 index 42df9bf4..00000000 --- a/packages/coreui-vue/src/components/stepper/CStepper.ts +++ /dev/null @@ -1,266 +0,0 @@ -// CStepper.ts -import { - defineComponent, - h, - ref, - watch, - computed, - nextTick, - onMounted, - toRefs, - shallowRef, - watchEffect, -} from 'vue' -import { CCollapse } from '../collapse' -import type { StepperStepData, StepperStepValidationResult } from './types' - -export const CStepper = defineComponent({ - name: 'CStepper', - inheritAttrs: false, - props: { - modelValue: Number, - defaultActiveStepIndex: { - type: Number, - default: 0, - }, - layout: { - type: String as () => 'horizontal' | 'vertical', - default: 'horizontal', - }, - linear: { - type: Boolean, - default: true, - }, - steps: { - type: Array as () => StepperStepData[], - required: true, - }, - stepButtonLayout: { - type: String as () => 'horizontal' | 'vertical', - default: 'horizontal', - }, - validation: { - type: Boolean, - default: true, - }, - id: String, - }, - emits: ['update:modelValue', 'finish', 'reset', 'stepChange', 'stepValidationComplete'], - setup(props, { emit, slots, attrs, expose }) { - const { modelValue, defaultActiveStepIndex, validation, steps, layout, linear } = toRefs(props) - - const activeStepIndex = ref(modelValue.value ?? defaultActiveStepIndex.value ?? 0) - const isControlled = computed(() => modelValue.value !== undefined) - const isFinished = ref(false) - const stepsRef = ref(null) - const stepButtonRefs = shallowRef<(HTMLButtonElement | null)[]>([]) - - watch(modelValue, (val) => { - if (val !== undefined) activeStepIndex.value = val - }) - - watch(activeStepIndex, (val) => { - if (isControlled.value) emit('update:modelValue', val) - }) - - const isStepValid = (index: number): boolean => { - if (!validation.value) return true - - const form = steps.value[index]?.formRef?.value - if (!form) return true - - const valid = form.checkValidity() - emit('stepValidationComplete', { stepNumber: index + 1, isValid: valid }) - if (!valid) form.reportValidity() - return valid - } - - const setActiveStep = (index: number, bypassValidation = false) => { - if (index < 0 || index >= steps.value.length || index === activeStepIndex.value) return - if (!bypassValidation && index > activeStepIndex.value && !isStepValid(activeStepIndex.value)) - return - - activeStepIndex.value = index - emit('stepChange', index + 1) - } - - const next = () => { - if (activeStepIndex.value < steps.value.length - 1) { - setActiveStep(activeStepIndex.value + 1) - } else { - finish() - } - } - - const prev = () => { - if (activeStepIndex.value > 0) { - setActiveStep(activeStepIndex.value - 1, true) - } - } - - const finish = () => { - if (activeStepIndex.value === steps.value.length - 1 && isStepValid(activeStepIndex.value)) { - isFinished.value = true - emit('finish') - } - } - - const reset = () => { - if (validation.value) { - steps.value.forEach((s) => s.formRef?.value?.reset?.()) - } - activeStepIndex.value = defaultActiveStepIndex.value - isFinished.value = false - emit('reset') - emit('stepChange', defaultActiveStepIndex.value) - nextTick(() => { - stepButtonRefs.value[defaultActiveStepIndex.value]?.focus() - }) - } - - const handleKeyDown = (event: KeyboardEvent) => { - const buttons = stepButtonRefs.value - const current = event.target as HTMLButtonElement - const index = buttons.findIndex((b) => b === current) - if (index === -1) return - - let nextIndex = index - switch (event.key) { - case 'ArrowRight': - case 'ArrowDown': - nextIndex = (index + 1) % buttons.length - break - case 'ArrowLeft': - case 'ArrowUp': - nextIndex = (index - 1 + buttons.length) % buttons.length - break - case 'Home': - nextIndex = 0 - break - case 'End': - nextIndex = buttons.length - 1 - break - default: - return - } - - event.preventDefault() - buttons[nextIndex]?.focus() - } - - expose({ next, prev, finish, reset }) - - return () => { - const isVertical = layout.value === 'vertical' - stepButtonRefs.value = [] - - return h( - 'div', - { - ...attrs, - class: ['stepper', { 'stepper-vertical': isVertical }, attrs.class], - }, - [ - h( - 'ol', - { - class: 'stepper-steps', - role: 'tablist', - 'aria-orientation': isVertical ? 'vertical' : 'horizontal', - onKeydown: handleKeyDown, - ref: stepsRef, - }, - steps.value.map((step, index) => { - const isActive = !isFinished.value && index === activeStepIndex.value - const isComplete = isFinished.value || index < activeStepIndex.value - const isDisabled = - isFinished.value || (linear.value && index > activeStepIndex.value + 1) - const stepId = `step-${props.id || 'stepper'}-${index}` - const panelId = `panel-${props.id || 'stepper'}-${index}` - - return h( - 'li', - { - key: index, - class: ['stepper-step', props.stepButtonLayout], - role: 'presentation', - }, - [ - h( - 'button', - { - type: 'button', - class: ['stepper-step-button', { active: isActive, complete: isComplete }], - disabled: isDisabled, - id: stepId, - role: 'tab', - 'aria-selected': isActive, - tabindex: isActive ? 0 : -1, - 'aria-controls': step.content ? panelId : undefined, - onClick: () => - setActiveStep(index, !linear.value || index <= activeStepIndex.value), - ref: (el) => (stepButtonRefs.value[index] = el as HTMLButtonElement), - }, - [ - h('span', { class: 'stepper-step-indicator' }, [ - isComplete - ? h('span', { class: 'stepper-step-indicator-icon' }) - : h( - 'span', - { class: 'stepper-step-indicator-text' }, - step.indicator ?? index + 1 - ), - ]), - h('span', { class: 'stepper-step-label' }, step.label), - ] - ), - index < steps.value.length - 1 && h('div', { class: 'stepper-step-connector' }), - step.content && - isVertical && - h( - CCollapse, - { - class: 'stepper-step-content', - id: panelId, - role: 'tabpanel', - visible: isActive, - 'aria-hidden': !isActive, - 'aria-labelledby': stepId, - 'aria-live': 'polite', - }, - () => step.content - ), - ] - ) - }) - ), - !isVertical && - steps.value.some((s) => s.content != null) && - h( - 'div', - { class: 'stepper-content' }, - steps.value.map((step, index) => { - const isActive = !isFinished.value && index === activeStepIndex.value - const stepId = `step-${props.id || 'stepper'}-${index}` - const panelId = `panel-${props.id || 'stepper'}-${index}` - - return h( - 'div', - { - key: index, - id: panelId, - role: 'tabpanel', - 'aria-hidden': !isActive, - 'aria-labelledby': stepId, - 'aria-live': 'polite', - class: ['stepper-pane', { active: isActive, show: isActive }], - }, - step.content - ) - }) - ), - ] - ) - } - }, -}) diff --git a/packages/coreui-vue/src/components/stepper/__tests__/CBadge.spec.ts b/packages/coreui-vue/src/components/stepper/__tests__/CBadge.spec.ts deleted file mode 100644 index 4d132901..00000000 --- a/packages/coreui-vue/src/components/stepper/__tests__/CBadge.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { shallowMount } from '@vue/test-utils' -import { CBadge as Component } from '../../' - -const ComponentName = 'CBadge' -const wrapper = shallowMount(Component) -const customWrapper = shallowMount(Component, { - props: { - color: 'success', - }, - attrs: { - class: 'bazinga', - }, - slots: { - default: 'Hello World!', - }, -}) - -describe(`Loads and display ${ComponentName} component`, () => { - it('has a name', () => { - expect(Component.name).toMatch(ComponentName) - }) - it('renders correctly', () => { - expect(wrapper.element).toMatchSnapshot() - }) - it('renders correctly with slot', () => { - expect(customWrapper.element).toMatchSnapshot() - }) -}) - -describe(`Customize ${ComponentName} component`, () => { - it('has a prope class names', () => { - expect(customWrapper.classes('bazinga')).toBe(true) - expect(customWrapper.classes('badge')).toBe(true) - expect(customWrapper.classes('bg-success')).toBe(true) - }) - it('default slot contains text', () => { - expect(customWrapper.text()).toBe('Hello World!') - }) -}) diff --git a/packages/coreui-vue/src/components/stepper/__tests__/__snapshots__/CBadge.spec.ts.snap b/packages/coreui-vue/src/components/stepper/__tests__/__snapshots__/CBadge.spec.ts.snap deleted file mode 100644 index 249fb4fd..00000000 --- a/packages/coreui-vue/src/components/stepper/__tests__/__snapshots__/CBadge.spec.ts.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Loads and display CBadge component renders correctly 1`] = ` - -`; - -exports[`Loads and display CBadge component renders correctly with slot 1`] = ` - - Hello World! - -`; diff --git a/packages/coreui-vue/src/components/stepper/index.ts b/packages/coreui-vue/src/components/stepper/index.ts deleted file mode 100644 index 93b9c047..00000000 --- a/packages/coreui-vue/src/components/stepper/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { App } from 'vue' -import { CStepper } from './CStepper' - -const CStepperPlugin = { - install: (app: App): void => { - app.component(CStepper.name as string, CStepper) - }, -} - -export { CStepper, CStepperPlugin } diff --git a/packages/coreui-vue/src/components/stepper/types.ts b/packages/coreui-vue/src/components/stepper/types.ts deleted file mode 100644 index a2cc6bcf..00000000 --- a/packages/coreui-vue/src/components/stepper/types.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { VNode, Ref } from 'vue' - -export interface StepperRef { - next: () => void - prev: () => void - finish: () => void - reset: () => void -} - -export interface StepperStepData { - indicator?: VNode - label: VNode - content?: VNode - formRef?: Ref // Opcjonalny ref do walidacji -} - -export type StepperStepValidationResult = { - stepNumber: number - isValid: boolean -} diff --git a/packages/docs/api/stepper/CStepper.api.md b/packages/docs/api/stepper/CStepper.api.md new file mode 100644 index 00000000..e13e9c9a --- /dev/null +++ b/packages/docs/api/stepper/CStepper.api.md @@ -0,0 +1,22 @@ +### CStepper + +```jsx +import { CStepper } from '@coreui/vue' +// or +import CStepper from '@coreui/vue/src/components/stepper/CStepper' +``` + +#### Props + +| Prop name | Description | Type | Values | Default | +| --------- | ----------- | ---- | ------ | ------- | + +#### Events + +| Event name | Description | Properties | +| ---------------------------- | ----------- | ---------- | +| **update:modelValue** | | +| **finish** | | +| **reset** | | +| **step-change** | | +| **step-validation-complete** | | From c54eae4e17e98c94fbbb88f3a9453cc89c8cc333 Mon Sep 17 00:00:00 2001 From: mrholek Date: Wed, 4 Jun 2025 13:11:21 +0200 Subject: [PATCH 19/19] release: v5.5.0 --- README.md | 2 +- lerna.json | 2 +- packages/coreui-vue/README.md | 2 +- packages/coreui-vue/package.json | 2 +- packages/docs/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3d4aab99..86647480 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Several quick start options are available: -- [Download the latest release](https://github.com/coreui/coreui-vue/archive/v5.4.1.zip) +- [Download the latest release](https://github.com/coreui/coreui-vue/archive/v5.5.0.zip) - Clone the repo: `git clone https://github.com/coreui/coreui-vue.git` - Install with [npm](https://www.npmjs.com/): `npm install @coreui/vue` - Install with [yarn](https://yarnpkg.com/): `yarn add @coreui/vue` diff --git a/lerna.json b/lerna.json index 6fea4400..8b1ec4d7 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "yarn", "packages": ["packages/*"], - "version": "5.4.1", + "version": "5.5.0", "$schema": "node_modules/lerna/schemas/lerna-schema.json" } diff --git a/packages/coreui-vue/README.md b/packages/coreui-vue/README.md index d422298c..a1cfd697 100644 --- a/packages/coreui-vue/README.md +++ b/packages/coreui-vue/README.md @@ -46,7 +46,7 @@ Several quick start options are available: -- [Download the latest release](https://github.com/coreui/coreui-vue/archive/v5.4.1.zip) +- [Download the latest release](https://github.com/coreui/coreui-vue/archive/v5.5.0.zip) - Clone the repo: `git clone https://github.com/coreui/coreui-vue.git` - Install with [npm](https://www.npmjs.com/): `npm install @coreui/vue` - Install with [yarn](https://yarnpkg.com/): `yarn add @coreui/vue` diff --git a/packages/coreui-vue/package.json b/packages/coreui-vue/package.json index 7cbb6585..39b08b3a 100644 --- a/packages/coreui-vue/package.json +++ b/packages/coreui-vue/package.json @@ -1,6 +1,6 @@ { "name": "@coreui/vue", - "version": "5.4.1", + "version": "5.5.0", "description": "UI Components Library for Vue.js", "keywords": [ "vue", diff --git a/packages/docs/package.json b/packages/docs/package.json index 10463eb4..e190d802 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "@coreui/vue-docs", - "version": "5.4.1", + "version": "5.5.0", "scripts": { "api": "vue-docgen -c build/docgen.config.js", "dev": "vuepress dev --clean-cache",