From 9f310bb700dee6f30dab3748de333a605127d0fc Mon Sep 17 00:00:00 2001 From: mrholek Date: Tue, 6 May 2025 13:45:48 +0200 Subject: [PATCH 1/9] 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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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",