From 0b7cbd8e0bb42be7721d2e960385237406e4d961 Mon Sep 17 00:00:00 2001 From: mrholek Date: Mon, 19 May 2025 15:41:26 +0200 Subject: [PATCH 01/13] feat(CButton): add support for unthemed outline and ghost buttons --- packages/coreui-react/package.json | 2 +- .../src/components/button/CButton.tsx | 8 ++--- .../examples/ButtonGhostBaseClassExample.tsx | 12 ++++++++ .../ButtonOutlineBaseClassExample.tsx | 12 ++++++++ .../docs/content/components/button/index.mdx | 30 +++++++++++++++---- packages/docs/package.json | 2 +- 6 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 packages/docs/content/components/button/examples/ButtonGhostBaseClassExample.tsx create mode 100644 packages/docs/content/components/button/examples/ButtonOutlineBaseClassExample.tsx diff --git a/packages/coreui-react/package.json b/packages/coreui-react/package.json index 7ab67b3c..8a5d6c8a 100644 --- a/packages/coreui-react/package.json +++ b/packages/coreui-react/package.json @@ -41,7 +41,7 @@ "test:update": "jest --coverage --updateSnapshot" }, "dependencies": { - "@coreui/coreui": "^5.3.2", + "@coreui/coreui": "^5.4.0", "@popperjs/core": "^2.11.8", "prop-types": "^15.8.1" }, diff --git a/packages/coreui-react/src/components/button/CButton.tsx b/packages/coreui-react/src/components/button/CButton.tsx index f8f5e17a..a12115d5 100644 --- a/packages/coreui-react/src/components/button/CButton.tsx +++ b/packages/coreui-react/src/components/button/CButton.tsx @@ -66,7 +66,7 @@ export const CButton: PolymorphicRefForwardingComponent<'button', CButtonProps> >( ( { children, as = 'button', className, color, shape, size, type = 'button', variant, ...rest }, - ref, + ref ) => { return ( {...(!rest.href && { type: type })} className={classNames( 'btn', + variant && color ? `btn-${variant}-${color}` : `btn-${variant}`, { [`btn-${color}`]: color && !variant, - [`btn-${variant}-${color}`]: color && variant, [`btn-${size}`]: size, }, shape, - className, + className )} {...rest} ref={ref} @@ -88,7 +88,7 @@ export const CButton: PolymorphicRefForwardingComponent<'button', CButtonProps> {children} ) - }, + } ) CButton.propTypes = { diff --git a/packages/docs/content/components/button/examples/ButtonGhostBaseClassExample.tsx b/packages/docs/content/components/button/examples/ButtonGhostBaseClassExample.tsx new file mode 100644 index 00000000..d99be5d5 --- /dev/null +++ b/packages/docs/content/components/button/examples/ButtonGhostBaseClassExample.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import { CButton } from '@coreui/react' + +export const ButtonGhostBaseClassExample = () => { + return ( + <> + Base ghost button + Active state + Disabled state + + ) +} diff --git a/packages/docs/content/components/button/examples/ButtonOutlineBaseClassExample.tsx b/packages/docs/content/components/button/examples/ButtonOutlineBaseClassExample.tsx new file mode 100644 index 00000000..2c5de0e3 --- /dev/null +++ b/packages/docs/content/components/button/examples/ButtonOutlineBaseClassExample.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import { CButton } from '@coreui/react' + +export const ButtonOutlineBaseClassExample = () => { + return ( + <> + Base outline button + Active state + Disabled state + + ) +} diff --git a/packages/docs/content/components/button/index.mdx b/packages/docs/content/components/button/index.mdx index 4d615ebb..87cb6205 100644 --- a/packages/docs/content/components/button/index.mdx +++ b/packages/docs/content/components/button/index.mdx @@ -28,21 +28,41 @@ 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. -## Ghost buttons + -If you need a ghost variant of react button, set `variant="ghost"` prop to remove all background colors. +These React 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. + + + +These outline variants of our React.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. Some of the button styles use a relatively light foreground color, and should only be used on a dark background in order to have sufficient contrast. +## Ghost buttons + +### Base ghost style + +Use the `variant="ghost"` property to create ultra-minimalist buttons with no borders and a fully transparent background. These React 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. + + + +To apply theme colors to React 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. + + + ## Sizes Larger or smaller react buttons? Add `size="lg"` or `size="sm"` for additional sizes. diff --git a/packages/docs/package.json b/packages/docs/package.json index ce095008..7cd2d1b3 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@coreui/chartjs": "^4.1.0", - "@coreui/coreui": "^5.3.2", + "@coreui/coreui": "^5.4.0", "@coreui/icons": "^3.0.1", "@coreui/icons-react": "^2.3.0", "@coreui/react-chartjs": "^3.0.0", From 1ad29c6de05fd9cf3be61514614d4e67b0983594 Mon Sep 17 00:00:00 2001 From: mrholek Date: Mon, 19 May 2025 15:56:35 +0200 Subject: [PATCH 02/13] feat(CNav): add enclosed variants --- .../coreui-react/src/components/nav/CNav.tsx | 14 ++++++++++--- .../navs-tabs/examples/NavEnclosedExample.tsx | 21 +++++++++++++++++++ .../examples/NavEnclosedPillsExample.tsx | 21 +++++++++++++++++++ .../content/components/navs-tabs/index.mdx | 13 ++++++++++++ 4 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 packages/docs/content/components/navs-tabs/examples/NavEnclosedExample.tsx create mode 100644 packages/docs/content/components/navs-tabs/examples/NavEnclosedPillsExample.tsx diff --git a/packages/coreui-react/src/components/nav/CNav.tsx b/packages/coreui-react/src/components/nav/CNav.tsx index 233994af..f056fbf7 100644 --- a/packages/coreui-react/src/components/nav/CNav.tsx +++ b/packages/coreui-react/src/components/nav/CNav.tsx @@ -21,7 +21,7 @@ export interface CNavProps /** * Set the nav variant to tabs or pills. */ - variant?: 'pills' | 'tabs' | 'underline' | 'underline-border' + variant?: 'enclosed' | 'enclosed-pills' | 'pills' | 'tabs' | 'underline' | 'underline-border' } export const CNav: PolymorphicRefForwardingComponent<'ul', CNavProps> = forwardRef< @@ -32,11 +32,12 @@ export const CNav: PolymorphicRefForwardingComponent<'ul', CNavProps> = forwardR { + return ( + + + Active + + + Link + + + Link + + + Disabled + + + ) +} diff --git a/packages/docs/content/components/navs-tabs/examples/NavEnclosedPillsExample.tsx b/packages/docs/content/components/navs-tabs/examples/NavEnclosedPillsExample.tsx new file mode 100644 index 00000000..e49457f8 --- /dev/null +++ b/packages/docs/content/components/navs-tabs/examples/NavEnclosedPillsExample.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import { CNav, CNavItem, CNavLink } from '@coreui/react' + +export const NavEnclosedPillsExample = () => { + return ( + + + Active + + + Link + + + Link + + + Disabled + + + ) +} diff --git a/packages/docs/content/components/navs-tabs/index.mdx b/packages/docs/content/components/navs-tabs/index.mdx index 5b07eb17..439f05eb 100644 --- a/packages/docs/content/components/navs-tabs/index.mdx +++ b/packages/docs/content/components/navs-tabs/index.mdx @@ -64,6 +64,19 @@ 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. + + + +### Enclosed pills + +Use the `variant="enclosed-pills"` to achieve a pill-style appearance for each nav item, using pill-shaped borders and smoother outlines. + + + + ### Fill and justify Force your ``'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 bee8617ecbe3c2f6bb9f54bb474feb512ac74e7f Mon Sep 17 00:00:00 2001 From: mrholek Date: Mon, 19 May 2025 16:10:46 +0200 Subject: [PATCH 03/13] feat(CTabs): add enclosed variants --- .../src/components/tabs/CTabList.tsx | 20 ++++++++---- .../tabs/examples/TabsEnclosedExample.tsx | 31 +++++++++++++++++++ .../examples/TabsEnclosedPillsExample.tsx | 31 +++++++++++++++++++ .../docs/content/components/tabs/index.mdx | 28 ++++++++++++----- 4 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 packages/docs/content/components/tabs/examples/TabsEnclosedExample.tsx create mode 100644 packages/docs/content/components/tabs/examples/TabsEnclosedPillsExample.tsx diff --git a/packages/coreui-react/src/components/tabs/CTabList.tsx b/packages/coreui-react/src/components/tabs/CTabList.tsx index 7349a364..ee7b9fe5 100644 --- a/packages/coreui-react/src/components/tabs/CTabList.tsx +++ b/packages/coreui-react/src/components/tabs/CTabList.tsx @@ -17,7 +17,7 @@ export interface CTabListProps extends HTMLAttributes { /** * Set the nav variant to tabs or pills. */ - variant?: 'pills' | 'tabs' | 'underline' | 'underline-border' + variant?: 'enclosed' | 'enclosed-pills' | 'pills' | 'tabs' | 'underline' | 'underline-border' } export const CTabList = forwardRef( @@ -39,7 +39,7 @@ export const CTabList = forwardRef( const target = event.target as HTMLElement // eslint-disable-next-line unicorn/prefer-spread const items: HTMLElement[] = Array.from( - tabListRef.current.querySelectorAll('.nav-link:not(.disabled):not(:disabled)'), + tabListRef.current.querySelectorAll('.nav-link:not(.disabled):not(:disabled)') ) let nextActiveElement @@ -51,7 +51,7 @@ export const CTabList = forwardRef( items, target, event.key === 'ArrowDown' || event.key === 'ArrowRight', - true, + true ) } @@ -65,11 +65,12 @@ export const CTabList = forwardRef(
( {children}
) - }, + } ) CTabList.propTypes = { children: PropTypes.node, className: PropTypes.string, layout: PropTypes.oneOf(['fill', 'justified']), - variant: PropTypes.oneOf(['pills', 'tabs', 'underline', 'underline-border']), + variant: PropTypes.oneOf([ + 'enclosed', + 'enclosed-pills', + 'pills', + 'tabs', + 'underline', + 'underline-border', + ]), } CTabList.displayName = 'CTabList' diff --git a/packages/docs/content/components/tabs/examples/TabsEnclosedExample.tsx b/packages/docs/content/components/tabs/examples/TabsEnclosedExample.tsx new file mode 100644 index 00000000..0c7b4a18 --- /dev/null +++ b/packages/docs/content/components/tabs/examples/TabsEnclosedExample.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import { CTab, CTabContent, CTabList, CTabPanel, CTabs } from '@coreui/react' + +export const TabsEnclosedExample = () => { + return ( + + + Home + Profile + Contact + + Disabled + + + + + Home tab content + + + Profile tab content + + + Contact tab content + + + Disabled tab content + + + + ) +} diff --git a/packages/docs/content/components/tabs/examples/TabsEnclosedPillsExample.tsx b/packages/docs/content/components/tabs/examples/TabsEnclosedPillsExample.tsx new file mode 100644 index 00000000..8fc0d82b --- /dev/null +++ b/packages/docs/content/components/tabs/examples/TabsEnclosedPillsExample.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import { CTab, CTabContent, CTabList, CTabPanel, CTabs } from '@coreui/react' + +export const TabsEnclosedPillsExample = () => { + return ( + + + Home + Profile + Contact + + Disabled + + + + + Home tab content + + + Profile tab content + + + Contact tab content + + + Disabled tab content + + + + ) +} diff --git a/packages/docs/content/components/tabs/index.mdx b/packages/docs/content/components/tabs/index.mdx index 00e61733..c493eb5d 100644 --- a/packages/docs/content/components/tabs/index.mdx +++ b/packages/docs/content/components/tabs/index.mdx @@ -10,7 +10,7 @@ since: 5.1.0 The basic React tabs example uses the `variant="tabs"` props to generate a tabbed interface. - + ## Available styles @@ -20,35 +20,47 @@ Change the style of ``'s component with modifiers and utilities. Mix and If you don’t provide the `variant` prop, the component will default to a basic style. - + ### Pills Take that same code, but use `variant="pills"` instead: - + ### Underline Take that same code, but use `variant="underline"` instead: - + ### Underline border 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. + + + +### Enclosed pills + +Use the `variant="enclosed-pills"` to achieve a pill-style appearance for each nav item, using pill-shaped borders and smoother outlines. + + ### 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. - + For equal-width elements, use `layout="justified"`. All horizontal space will be occupied by nav links, but unlike the `layout="fill"` above, every nav item will be the same width. - + Sure! Here's a polished, production-ready **documentation section** (Markdown-style) explaining the **controlled usage** of the `` component, with a clear example: @@ -68,7 +80,7 @@ This is useful when you need to synchronize the tab state with your application > 💡 If you prefer the tabs to manage their own state, use `defaultActiveItemKey` instead. - + ## Accessibility From 3b37bd9fb19c7d087f7b2f9a8a276b3ce9b369d6 Mon Sep 17 00:00:00 2001 From: mrholek Date: Mon, 19 May 2025 17:09:23 +0200 Subject: [PATCH 04/13] chore: update dependencies and devDependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @types/react ^19.1.2 → ^19.1.4 @types/react-dom ^19.1.2 → ^19.1.5 @typescript-eslint/parser ^8.31.1 → ^8.32.1 eslint ^9.25.1 → ^9.27.0 eslint-config-prettier ^10.1.2 → ^10.1.5 eslint-plugin-prettier ^5.2.6 → ^5.4.0 eslint-plugin-unicorn ^59.0.0 → ^59.0.1 globals ^16.0.0 → ^16.1.0 rollup ^4.40.1 → ^4.41.0 sass ^1.87.0 → ^1.89.0 ts-jest ^29.3.2 → ^29.3.4 typescript-eslint ^8.31.1 → ^8.32.1 --- package.json | 14 +++++++------- packages/coreui-react/package.json | 8 ++++---- packages/docs/package.json | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 46a8d37c..e51bf9e0 100644 --- a/package.json +++ b/package.json @@ -22,18 +22,18 @@ "test:update": "npm-run-all charts:test:update icons:test:update lib:test:update" }, "devDependencies": { - "@typescript-eslint/parser": "^8.31.1", - "eslint": "^9.25.1", - "eslint-config-prettier": "^10.1.2", - "eslint-plugin-prettier": "^5.2.6", + "@typescript-eslint/parser": "^8.32.1", + "eslint": "^9.27.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.4.0", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-unicorn": "^59.0.0", - "globals": "^16.0.0", + "eslint-plugin-unicorn": "^59.0.1", + "globals": "^16.1.0", "lerna": "^8.2.2", "npm-run-all": "^4.1.5", "prettier": "^3.5.3", - "typescript-eslint": "^8.31.1" + "typescript-eslint": "^8.32.1" }, "overrides": { "gatsby-remark-external-links": { diff --git a/packages/coreui-react/package.json b/packages/coreui-react/package.json index 8a5d6c8a..27392080 100644 --- a/packages/coreui-react/package.json +++ b/packages/coreui-react/package.json @@ -54,8 +54,8 @@ "@testing-library/react": "^16.3.0", "@types/jest": "^29.5.14", "@types/prop-types": "15.7.14", - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.2", + "@types/react": "^19.1.4", + "@types/react-dom": "^19.1.5", "@types/react-transition-group": "^4.4.12", "classnames": "^2.5.1", "cross-env": "^7.0.3", @@ -64,8 +64,8 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-transition-group": "^4.4.5", - "rollup": "^4.40.1", - "ts-jest": "^29.3.2", + "rollup": "^4.41.0", + "ts-jest": "^29.3.4", "tslib": "^2.8.1", "typescript": "^5.8.3" }, diff --git a/packages/docs/package.json b/packages/docs/package.json index 7cd2d1b3..42519753 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -58,7 +58,7 @@ "react-imask": "^7.6.1", "react-markdown": "^10.1.0", "rimraf": "^6.0.1", - "sass": "^1.87.0", + "sass": "^1.89.0", "showdown": "^2.1.0" }, "devDependencies": { From 932d00fbdf898c450d8c091ce857a407f933b25e Mon Sep 17 00:00:00 2001 From: mrholek Date: Mon, 19 May 2025 17:21:06 +0200 Subject: [PATCH 05/13] release: v5.7.0 --- README.md | 2 +- lerna.json | 2 +- packages/coreui-react/README.md | 2 +- packages/coreui-react/package.json | 2 +- packages/docs/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 69727eff..467a62fb 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-react/archive/v5.6.0.zip) +- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.7.0.zip) - Clone the repo: `git clone https://github.com/coreui/coreui-react.git` - Install with [npm](https://www.npmjs.com/): `npm install @coreui/react` - Install with [yarn](https://yarnpkg.com/): `yarn add @coreui/react` diff --git a/lerna.json b/lerna.json index a4d781c9..e456a603 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "yarn", "packages": ["packages/*"], - "version": "5.6.0", + "version": "5.7.0", "$schema": "node_modules/lerna/schemas/lerna-schema.json" } diff --git a/packages/coreui-react/README.md b/packages/coreui-react/README.md index 83407ad9..c98015a2 100644 --- a/packages/coreui-react/README.md +++ b/packages/coreui-react/README.md @@ -46,7 +46,7 @@ Several quick start options are available: -- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.6.0.zip) +- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.7.0.zip) - Clone the repo: `git clone https://github.com/coreui/coreui-react.git` - Install with [npm](https://www.npmjs.com/): `npm install @coreui/react` - Install with [yarn](https://yarnpkg.com/): `yarn add @coreui/react` diff --git a/packages/coreui-react/package.json b/packages/coreui-react/package.json index 27392080..6952b2c9 100644 --- a/packages/coreui-react/package.json +++ b/packages/coreui-react/package.json @@ -1,6 +1,6 @@ { "name": "@coreui/react", - "version": "5.6.0", + "version": "5.7.0", "description": "UI Components Library for React.js", "keywords": [ "react", diff --git a/packages/docs/package.json b/packages/docs/package.json index 42519753..c7bc49c3 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "@coreui/react-docs", - "version": "5.6.0", + "version": "5.7.0", "private": true, "description": "", "homepage": "https://coreui.io/react/", From c7273968e926a4a47ba96f968e866ef0ec951334 Mon Sep 17 00:00:00 2001 From: mrholek Date: Thu, 29 May 2025 23:49:08 +0200 Subject: [PATCH 06/13] refactor(CButton): improve variants handling --- packages/coreui-react/src/components/button/CButton.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/coreui-react/src/components/button/CButton.tsx b/packages/coreui-react/src/components/button/CButton.tsx index a12115d5..cbb003d7 100644 --- a/packages/coreui-react/src/components/button/CButton.tsx +++ b/packages/coreui-react/src/components/button/CButton.tsx @@ -74,9 +74,10 @@ export const CButton: PolymorphicRefForwardingComponent<'button', CButtonProps> {...(!rest.href && { type: type })} className={classNames( 'btn', - variant && color ? `btn-${variant}-${color}` : `btn-${variant}`, { - [`btn-${color}`]: color && !variant, + [`btn-${variant}-${color}`]: variant && color, + [`btn-${variant}`]: variant && !color, + [`btn-${color}`]: !variant && color, [`btn-${size}`]: size, }, shape, From 38fc15aee8dd508897139954406dbccce089c808 Mon Sep 17 00:00:00 2001 From: mrholek Date: Sun, 8 Jun 2025 21:03:03 +0200 Subject: [PATCH 07/13] docs: update content --- .../docs/content/forms/checkbox/bootstrap.mdx | 68 ++++++++++--------- .../docs/content/forms/checkbox/index.mdx | 68 +++++++++---------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/packages/docs/content/forms/checkbox/bootstrap.mdx b/packages/docs/content/forms/checkbox/bootstrap.mdx index 185c6753..842bb911 100644 --- a/packages/docs/content/forms/checkbox/bootstrap.mdx +++ b/packages/docs/content/forms/checkbox/bootstrap.mdx @@ -1,69 +1,71 @@ --- -title: React Checkbox Components -name: Checkbox -description: Create consistent cross-browser and cross-device checkboxes with our React checkbox components. +title: React Bootstrap Checkbox Component +name: Checkbox with Bootstrap Styling +description: Learn how to build accessible and consistent Bootstrap-style checkboxes in React using CoreUI components. route: /forms/checkbox/ -other_frameworks: checkbox +bootstrap_component: true --- -## Approach +## How to use React Bootstrap Checkbox component -Browser default checkboxes and radios are replaced with the help of ``. Checkboxes are for selecting one or several options in a list. +Use CoreUI’s `` to create cross-browser, accessible, and Bootstrap-styled checkboxes in React. Checkboxes are ideal for selecting one or more options from a list and can be styled, stacked, or grouped using layout utilities. -## Checkboxes +### Basic example - +Use the `` component to render a standard Bootstrap-style checkbox. -### Indeterminate + -Checkboxes can utilize the `:indeterminate` pseudo-class when manually set via `indeterminate` property. +### Indeterminate state - +Set the `indeterminate` property to render a checkbox in an indeterminate state, commonly used to indicate partial selections. -### Disabled + -Add the `disabled` attribute and the associated `
- {children} - - ) - } + if (custom && React.isValidElement(children)) { + return ( + <> + {React.cloneElement(children as React.ReactElement, { + 'aria-expanded': visible, + ...(!rest.disabled && { ...triggers }), + ref: dropdownToggleRef, + })} + + ) + } + if (variant === 'nav-item' && navLink) { return ( - + {children} - {split && Toggle Dropdown} - + ) } - return + return ( + + {children} + {split && Toggle Dropdown} + + ) } CDropdownToggle.propTypes = { From 5688b6132a0b22dd2b08899f6a71a1414b229c69 Mon Sep 17 00:00:00 2001 From: mrholek Date: Sat, 12 Jul 2025 16:32:53 +0200 Subject: [PATCH 10/13] refactor(CDropdown): optimize menu visibility toggling --- .../src/components/dropdown/CDropdown.tsx | 76 ++++++++++++------- .../components/dropdown/CDropdownContext.ts | 3 +- .../components/dropdown/CDropdownToggle.tsx | 14 +++- 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/packages/coreui-react/src/components/dropdown/CDropdown.tsx b/packages/coreui-react/src/components/dropdown/CDropdown.tsx index bcd9f14d..2d8a7bbd 100644 --- a/packages/coreui-react/src/components/dropdown/CDropdown.tsx +++ b/packages/coreui-react/src/components/dropdown/CDropdown.tsx @@ -214,19 +214,6 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps> const allowPopperUse = popper && typeof alignment !== 'object' const Component = variant === 'nav-item' ? 'li' : as - const contextValues = { - alignment, - container, - dark, - dropdownMenuRef, - dropdownToggleRef, - popper: allowPopperUse, - portal, - variant, - visible: _visible, - setVisible, - } - const computedPopperConfig: Partial = useMemo(() => { const defaultPopperConfig = { modifiers: [ @@ -247,14 +234,28 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps> }, [offset, placement, direction, alignment, popperConfig]) useEffect(() => { - setVisible(visible) + if (visible) { + handleShow() + } else { + handleHide() + } }, [visible]) useEffect(() => { const toggleElement = dropdownToggleElement const menuElement = dropdownMenuRef.current + if (allowPopperUse && menuElement && toggleElement && _visible) { + initPopper(toggleElement, menuElement, computedPopperConfig) + } + }, [dropdownToggleElement]) + + const handleShow = () => { + const toggleElement = dropdownToggleElement + const menuElement = dropdownMenuRef.current + + if (toggleElement && menuElement) { + setVisible(true) - if (_visible && toggleElement && menuElement) { if (allowPopperUse) { initPopper(toggleElement, menuElement, computedPopperConfig) } @@ -268,21 +269,26 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps> onShow?.() } + } - return () => { - if (allowPopperUse) { - destroyPopper() - } - - toggleElement?.removeEventListener('keydown', handleKeydown) - menuElement?.removeEventListener('keydown', handleKeydown) + const handleHide = () => { + setVisible(false) - window.removeEventListener('mouseup', handleMouseUp) - window.removeEventListener('keyup', handleKeyup) + const toggleElement = dropdownToggleElement + const menuElement = dropdownMenuRef.current - onHide?.() + if (allowPopperUse) { + destroyPopper() } - }, [dropdownToggleElement, _visible]) + + toggleElement?.removeEventListener('keydown', handleKeydown) + menuElement?.removeEventListener('keydown', handleKeydown) + + window.removeEventListener('mouseup', handleMouseUp) + window.removeEventListener('keyup', handleKeyup) + + onHide?.() + } const handleKeydown = (event: KeyboardEvent) => { if ( @@ -305,7 +311,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps> } if (event.key === 'Escape') { - setVisible(false) + handleHide() } } @@ -323,11 +329,25 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps> (autoClose === 'inside' && dropdownMenuRef.current.contains(event.target as HTMLElement)) || (autoClose === 'outside' && !dropdownMenuRef.current.contains(event.target as HTMLElement)) ) { - setTimeout(() => setVisible(false), 1) + setTimeout(() => handleHide(), 1) return } } + const contextValues = { + alignment, + container, + dark, + dropdownMenuRef, + dropdownToggleRef, + handleHide, + handleShow, + popper: allowPopperUse, + portal, + variant, + visible: _visible, + } + return ( {variant === 'input-group' ? ( diff --git a/packages/coreui-react/src/components/dropdown/CDropdownContext.ts b/packages/coreui-react/src/components/dropdown/CDropdownContext.ts index 53ab1151..d46b69d2 100644 --- a/packages/coreui-react/src/components/dropdown/CDropdownContext.ts +++ b/packages/coreui-react/src/components/dropdown/CDropdownContext.ts @@ -7,7 +7,8 @@ export interface CDropdownContextProps { dark?: boolean dropdownMenuRef: RefObject dropdownToggleRef: (node: HTMLElement | null) => void - setVisible: React.Dispatch> + handleHide?: () => void + handleShow?: () => void popper?: boolean portal?: boolean variant?: 'btn-group' | 'dropdown' | 'input-group' | 'nav-item' diff --git a/packages/coreui-react/src/components/dropdown/CDropdownToggle.tsx b/packages/coreui-react/src/components/dropdown/CDropdownToggle.tsx index 29434d7e..def263e5 100644 --- a/packages/coreui-react/src/components/dropdown/CDropdownToggle.tsx +++ b/packages/coreui-react/src/components/dropdown/CDropdownToggle.tsx @@ -45,18 +45,24 @@ export const CDropdownToggle: FC = ({ trigger = 'click', ...rest }) => { - const { dropdownToggleRef, variant, visible, setVisible } = useContext(CDropdownContext) + const { dropdownToggleRef, handleHide, handleShow, variant, visible } = + useContext(CDropdownContext) const triggers = { ...((trigger === 'click' || trigger.includes('click')) && { onClick: (event: React.MouseEvent) => { event.preventDefault() - setVisible(!visible) + + if (visible) { + handleHide?.() + } else { + handleShow?.() + } }, }), ...((trigger === 'focus' || trigger.includes('focus')) && { - onFocus: () => setVisible(true), - onBlur: () => setVisible(false), + onFocus: () => handleShow?.(), + onBlur: () => handleHide?.(), }), } From a6d3bb53f4a971a7ace608fd29f27ef3791a216c Mon Sep 17 00:00:00 2001 From: mrholek Date: Sat, 12 Jul 2025 16:40:59 +0200 Subject: [PATCH 11/13] chore: update dependencies and devDependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @coreui/coreui ^5.4.0 → ^5.4.1 @rollup/plugin-commonjs ^28.0.3 → ^28.0.6 @rollup/plugin-typescript ^12.1.2 → ^12.1.4 @types/prop-types 15.7.14 → 15.7.15 @types/react ^19.1.4 → ^19.1.8 @types/react-dom ^19.1.5 → ^19.1.6 @typescript-eslint/parser ^8.32.1 → ^8.36.0 eslint ^9.27.0 → ^9.31.0 eslint-plugin-prettier ^5.4.0 → ^5.5.1 gatsby ^5.14.3 → ^5.14.5 globals ^16.1.0 → ^16.3.0 lerna ^8.2.2 → ^8.2.3 prettier ^3.5.3 → ^3.6.2 react-docgen-typescript ^2.2.2 → ^2.4.0 rollup ^4.41.0 → ^4.45.0 sass ^1.89.0 → ^1.89.2 ts-jest ^29.3.4 → ^29.4.0 typescript-eslint ^8.32.1 → ^8.36.0 --- package.json | 14 +++++++------- packages/coreui-react/package.json | 16 ++++++++-------- packages/docs/package.json | 8 ++++---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index e51bf9e0..b7e32b5f 100644 --- a/package.json +++ b/package.json @@ -22,18 +22,18 @@ "test:update": "npm-run-all charts:test:update icons:test:update lib:test:update" }, "devDependencies": { - "@typescript-eslint/parser": "^8.32.1", - "eslint": "^9.27.0", + "@typescript-eslint/parser": "^8.36.0", + "eslint": "^9.31.0", "eslint-config-prettier": "^10.1.5", - "eslint-plugin-prettier": "^5.4.0", + "eslint-plugin-prettier": "^5.5.1", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-unicorn": "^59.0.1", - "globals": "^16.1.0", - "lerna": "^8.2.2", + "globals": "^16.3.0", + "lerna": "^8.2.3", "npm-run-all": "^4.1.5", - "prettier": "^3.5.3", - "typescript-eslint": "^8.32.1" + "prettier": "^3.6.2", + "typescript-eslint": "^8.36.0" }, "overrides": { "gatsby-remark-external-links": { diff --git a/packages/coreui-react/package.json b/packages/coreui-react/package.json index 6952b2c9..a052955f 100644 --- a/packages/coreui-react/package.json +++ b/packages/coreui-react/package.json @@ -41,21 +41,21 @@ "test:update": "jest --coverage --updateSnapshot" }, "dependencies": { - "@coreui/coreui": "^5.4.0", + "@coreui/coreui": "^5.4.1", "@popperjs/core": "^2.11.8", "prop-types": "^15.8.1" }, "devDependencies": { - "@rollup/plugin-commonjs": "^28.0.3", + "@rollup/plugin-commonjs": "^28.0.6", "@rollup/plugin-node-resolve": "^16.0.1", - "@rollup/plugin-typescript": "^12.1.2", + "@rollup/plugin-typescript": "^12.1.4", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@types/jest": "^29.5.14", - "@types/prop-types": "15.7.14", - "@types/react": "^19.1.4", - "@types/react-dom": "^19.1.5", + "@types/prop-types": "15.7.15", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", "@types/react-transition-group": "^4.4.12", "classnames": "^2.5.1", "cross-env": "^7.0.3", @@ -64,8 +64,8 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-transition-group": "^4.4.5", - "rollup": "^4.41.0", - "ts-jest": "^29.3.4", + "rollup": "^4.45.0", + "ts-jest": "^29.4.0", "tslib": "^2.8.1", "typescript": "^5.8.3" }, diff --git a/packages/docs/package.json b/packages/docs/package.json index c7bc49c3..2bb6d91c 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@coreui/chartjs": "^4.1.0", - "@coreui/coreui": "^5.4.0", + "@coreui/coreui": "^5.4.1", "@coreui/icons": "^3.0.1", "@coreui/icons-react": "^2.3.0", "@coreui/react-chartjs": "^3.0.0", @@ -35,7 +35,7 @@ "@mdx-js/mdx": "^3.1.0", "@mdx-js/react": "^3.1.0", "@stackblitz/sdk": "^1.11.0", - "gatsby": "^5.14.3", + "gatsby": "^5.14.5", "gatsby-plugin-google-tagmanager": "^5.14.0", "gatsby-plugin-image": "^3.14.0", "gatsby-plugin-manifest": "^5.14.0", @@ -53,12 +53,12 @@ "prismjs": "^1.30.0", "prop-types": "^15.8.1", "react": "^18.3.1", - "react-docgen-typescript": "^2.2.2", + "react-docgen-typescript": "^2.4.0", "react-dom": "^18.3.1", "react-imask": "^7.6.1", "react-markdown": "^10.1.0", "rimraf": "^6.0.1", - "sass": "^1.89.0", + "sass": "^1.89.2", "showdown": "^2.1.0" }, "devDependencies": { From 1969a64986f55e47bb2f156ffaac0c282e1a4b2d Mon Sep 17 00:00:00 2001 From: mrholek Date: Sun, 13 Jul 2025 12:33:53 +0200 Subject: [PATCH 12/13] release: v5.7.1 --- README.md | 2 +- lerna.json | 2 +- packages/coreui-react/README.md | 2 +- packages/coreui-react/package.json | 2 +- packages/docs/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 467a62fb..96d149a2 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-react/archive/v5.7.0.zip) +- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.7.1.zip) - Clone the repo: `git clone https://github.com/coreui/coreui-react.git` - Install with [npm](https://www.npmjs.com/): `npm install @coreui/react` - Install with [yarn](https://yarnpkg.com/): `yarn add @coreui/react` diff --git a/lerna.json b/lerna.json index e456a603..d86538ff 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "yarn", "packages": ["packages/*"], - "version": "5.7.0", + "version": "5.7.1", "$schema": "node_modules/lerna/schemas/lerna-schema.json" } diff --git a/packages/coreui-react/README.md b/packages/coreui-react/README.md index c98015a2..190eafc0 100644 --- a/packages/coreui-react/README.md +++ b/packages/coreui-react/README.md @@ -46,7 +46,7 @@ Several quick start options are available: -- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.7.0.zip) +- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.7.1.zip) - Clone the repo: `git clone https://github.com/coreui/coreui-react.git` - Install with [npm](https://www.npmjs.com/): `npm install @coreui/react` - Install with [yarn](https://yarnpkg.com/): `yarn add @coreui/react` diff --git a/packages/coreui-react/package.json b/packages/coreui-react/package.json index a052955f..4e62fee7 100644 --- a/packages/coreui-react/package.json +++ b/packages/coreui-react/package.json @@ -1,6 +1,6 @@ { "name": "@coreui/react", - "version": "5.7.0", + "version": "5.7.1", "description": "UI Components Library for React.js", "keywords": [ "react", diff --git a/packages/docs/package.json b/packages/docs/package.json index 2bb6d91c..7055ba02 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "@coreui/react-docs", - "version": "5.7.0", + "version": "5.7.1", "private": true, "description": "", "homepage": "https://coreui.io/react/", From 44a6c9889e5ee5156e6d6bdb28e4670c15d1f3f5 Mon Sep 17 00:00:00 2001 From: mrholek Date: Sun, 13 Jul 2025 17:38:36 +0200 Subject: [PATCH 13/13] docs: update schema markup --- packages/docs/src/components/Seo.tsx | 139 ++++++++++++++++++---- packages/docs/src/templates/MdxLayout.tsx | 3 +- 2 files changed, 121 insertions(+), 21 deletions(-) diff --git a/packages/docs/src/components/Seo.tsx b/packages/docs/src/components/Seo.tsx index 26cd82d0..cbb99f62 100644 --- a/packages/docs/src/components/Seo.tsx +++ b/packages/docs/src/components/Seo.tsx @@ -8,9 +8,10 @@ interface SEOProps { name?: string image?: string article?: string + pro?: boolean } -const SEO = ({ title, description, name, image, article }: SEOProps) => { +const SEO = ({ title, description, name, image, article, pro }: SEOProps) => { const { pathname } = useLocation() const { site } = useStaticQuery(query) @@ -35,6 +36,122 @@ const SEO = ({ title, description, name, image, article }: SEOProps) => { const formattedTitle = title ? titleTemplate.replace('%s', title) : 'My Gatsby Site' + const humanize = (text: string): string => { + return text + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' ') + } + + const breadcrumbList = (startIndex = 1) => { + return seo.url + .replace('docs//', 'docs/') + .replace(siteUrl, '') + .split('/') + .filter(Boolean) + .map((item, index) => ({ + '@type': 'ListItem', + position: index + startIndex, + name: humanize(item), + item: `${siteUrl}${item}`, + })) + } + + const getDynamicDescription = (pathname: string, name?: string): string => { + if (pathname.includes('/components/') && pathname.includes('api')) { + return `Complete guide to CoreUI React ${name} API documentation. Learn how to use the CoreUI React ${name} component, its properties, methods, and events.` + } + + if (pathname.includes('/components/') && pathname.includes('bootstrap')) { + return `Complete guide to CoreUI React ${name} usage with Bootstrap 5. Learn how to use the CoreUI React ${name} component with Bootstrap 5, including its properties, methods, and events.` + } + + if (pathname.includes('/components/') && pathname.includes('styling')) { + return `Complete guide to CoreUI React ${name} component styling. Learn how to customize the CoreUI React ${name} component styles, themes, and appearance.` + } + + if (pathname.includes('/components/')) { + return `Complete guide to CoreUI React ${name} components and implementation. Learn how to use the CoreUI React ${name} component in your React.js application.` + } + + if (pathname.includes('/customize/')) { + return `Complete guide to CoreUI React customization and theming. Learn how to customize CoreUI React components, styles, and themes to fit your project's needs.` + } + + if (pathname.includes('/forms/')) { + return `Complete guide to CoreUI React ${name} components and implementation.` + } + + if (pathname.includes('/layouts/')) { + return `Complete guide to CoreUI React ${name} implementation.` + } + + if (pathname.includes('/templates/')) { + return 'Complete guide to CoreUI React Templates. Learn how to download, install, customize, and use CoreUI React templates.' + } + + if (pathname.includes('/migration/')) { + return 'Complete guide to CoreUI React migration. Track and review changes to the CoreUI for React.js components to help you migrate to the latest version.' + } + + return 'Complete guide to CoreUI for React.js components and implementation.' + } + + const schema = [ + { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: [ + { + '@type': 'ListItem', + position: 1, + name: 'CoreUI', + item: 'https://coreui.io', + }, + { + '@type': 'ListItem', + position: 2, + name: 'React', + item: 'https://coreui.io/react/', + }, + { + '@type': 'ListItem', + position: 3, + name: 'Documentation', + item: siteUrl, + }, + ...breadcrumbList(4), + ], + }, + { + '@context': 'https://schema.org', + '@type': 'TechArticle', + headline: `${seo.title} documentation`, + description: getDynamicDescription(seo.url, name,), + author: { + '@type': 'Organization', + name: 'CoreUI Team', + sameAs: 'https://github.com/coreui/', + }, + publisher: { + '@type': 'Organization', + name: 'CoreUI', + logo: { + '@type': 'ImageObject', + url: 'https://coreui.io/images/brand/coreui-logo.svg', + }, + }, + datePublished: '2021-01-13', + dateModified: new Date().toISOString().split('T')[0], + mainEntityOfPage: { + '@type': 'WebPage', + '@id': seo.url.replace('docs//', 'docs/'), + }, + version: pro ? '5.17.1' : '5.7.1', + proficiencyLevel: 'Beginner', + }, + ] + return ( <> {formattedTitle} @@ -50,25 +167,7 @@ const SEO = ({ title, description, name, image, article }: SEOProps) => { {seo.title && } {seo.description && } {seo.image && } - {seo.name && ( - - )} + {seo.name && } ) } diff --git a/packages/docs/src/templates/MdxLayout.tsx b/packages/docs/src/templates/MdxLayout.tsx index 00aa6f11..4fddc174 100644 --- a/packages/docs/src/templates/MdxLayout.tsx +++ b/packages/docs/src/templates/MdxLayout.tsx @@ -98,11 +98,12 @@ export const Head = ({ pageContext }: { pageContext: PageContextType }) => { const title = frontmatter?.title || '' const description = frontmatter?.description || '' const name = frontmatter?.name || '' + const pro = frontmatter?.pro_component || false return ( <> - + ) }