diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a2c0383 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.cache +coverage/ +dist/ +node_modules/ +public/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index f19fc72..f4470fa 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 creativeLabs Łukasz Holeczek +Copyright (c) 2024 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 diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..5f5e9ec --- /dev/null +++ b/jest.config.js @@ -0,0 +1,17 @@ +/** + * 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 = { + moduleNameMapper: { + '\\.(css|scss)$': '/test/styleMock.js', + }, + preset: 'ts-jest', + testEnvironment: 'jsdom', + testPathIgnorePatterns: ['dist/'], +} diff --git a/package.json b/package.json index d8b75a1..2c5a151 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@coreui/icons-react", - "version": "2.1.0", + "version": "2.3.0", "description": "Official React component for CoreUI Icons", "keywords": [ "coreui", @@ -13,48 +13,47 @@ "component", "react" ], - "homepage": "https://icons.coreui.io", + "homepage": "https://coreui.io/react/docs/components/icon/", "bugs": { - "url": "https://github.com/coreui/coreui-icons/issues" + "url": "https://github.com/coreui/coreui-icons-react/issues" }, "repository": { "type": "git", - "url": "https://github.com/coreui/coreui-icons.git" + "url": "https://github.com/coreui/coreui-icons-react.git" }, "license": "MIT", "author": "The CoreUI Team (https://github.com/orgs/coreui/people)", "main": "dist/index.js", - "module": "dist/index.es.js", - "jsnext:main": "dist/index.es.js", + "module": "dist/index.esm.js", + "jsnext:main": "dist/index.esm.js", "types": "dist/index.d.ts", "files": [ "dist/", "src/" ], "scripts": { - "build": "rollup -c --bundleConfigAsCjs", + "build": "rollup --config", "test": "jest --coverage", "test:update": "jest --coverage --updateSnapshot" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.0.1", - "@rollup/plugin-node-resolve": "^15.0.1", - "@rollup/plugin-typescript": "^11.0.0", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@types/react": "^18.0.27", - "@types/react-dom": "^18.0.6", - "classnames": "^2.3.2", - "jest": "^29.4.1", - "jest-canvas-mock": "^2.4.0", - "jest-environment-jsdom": "^29.4.1", + "@rollup/plugin-commonjs": "^26.0.3", + "@rollup/plugin-node-resolve": "^15.3.1", + "@rollup/plugin-typescript": "^11.1.6", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.1.0", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "classnames": "^2.5.1", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", "prop-types": "^15.8.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "rollup": "^3.14.0", - "rollup-plugin-import-css": "^3.0.3", - "ts-jest": "^29.0.5", - "typescript": "^4.9.5" + "react": "^18.3.1", + "react-dom": "^18.3.1", + "rollup": "^4.29.1", + "rollup-plugin-import-css": "^3.5.8", + "ts-jest": "^29.2.5", + "typescript": "^5.7.2" }, "peerDependencies": { "react": ">=17", diff --git a/rollup.config.js b/rollup.config.mjs similarity index 100% rename from rollup.config.js rename to rollup.config.mjs diff --git a/src/CIcon.css b/src/CIcon.css index 1ce713d..037a3bf 100644 --- a/src/CIcon.css +++ b/src/CIcon.css @@ -75,4 +75,17 @@ width: 0.875rem; height: 0.875rem; font-size: 0.875rem; +} + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + position: absolute!important; + width: 1px!important; + height: 1px!important; + padding: 0!important; + margin: -1px!important; + overflow: hidden!important; + clip: rect(0,0,0,0)!important; + white-space: nowrap!important; + border: 0!important; } \ No newline at end of file diff --git a/src/CIcon.tsx b/src/CIcon.tsx index 5c6cb17..166f941 100644 --- a/src/CIcon.tsx +++ b/src/CIcon.tsx @@ -3,7 +3,7 @@ import React, { HTMLAttributes, forwardRef, useState, useMemo } from 'react' import classNames from 'classnames' import './CIcon.css' -export interface CIconProps extends HTMLAttributes { +export interface CIconProps extends Omit, 'content'> { /** * A string of all className you want applied to the component. */ @@ -17,7 +17,7 @@ export interface CIconProps extends HTMLAttributes { /** * Use for replacing default CIcon component classes. Prop is overriding the 'size' prop. */ - customClassName?: string | object | string[] // eslint-disable-line @typescript-eslint/ban-types + customClassName?: string | string[] /** * Name of the icon placed in React object or SVG content. */ @@ -53,6 +53,10 @@ export interface CIconProps extends HTMLAttributes { * If defined component will be rendered using 'use' tag. */ use?: string + /** + * The viewBox attribute defines the position and dimension of an SVG viewport. + */ + viewBox?: string /** * Title tag content. */ @@ -98,20 +102,18 @@ export const CIcon = forwardRef( useMemo(() => setChange(change + 1), [_icon, JSON.stringify(_icon)]) - const iconName = useMemo( - () => - _icon && typeof _icon === 'string' && _icon.includes('-') ? toCamelCase(_icon) : _icon, - [change], - ) - const titleCode = title ? `${title}` : '' const code = useMemo(() => { + const iconName = + _icon && typeof _icon === 'string' && _icon.includes('-') ? toCamelCase(_icon) : _icon + if (Array.isArray(_icon)) { return _icon } - if (typeof _icon === 'string' && React['icons']) { - return React['icons'][iconName] + + if (typeof _icon === 'string' && (React as { [key: string]: any })['icons']) { + return (React as { [key: string]: any })[iconName as string] } }, [change]) @@ -127,8 +129,6 @@ export const CIcon = forwardRef( return rest['viewBox'] || `0 0 ${scale}` })() - // render - const _className = customClassName ? classNames(customClassName) : classNames( @@ -140,30 +140,37 @@ export const CIcon = forwardRef( className, ) - return use ? ( - - - - ) : ( - + return ( + <> + {use ? ( + + ) : ( + + )} + {title && {title}} + ) }, ) @@ -190,8 +197,9 @@ CIcon.propTypes = { '8xl', '9xl', ]), - title: PropTypes.any, - use: PropTypes.any, + title: PropTypes.string, + use: PropTypes.string, + viewBox: PropTypes.string, width: PropTypes.number, } diff --git a/src/CIconSvg.tsx b/src/CIconSvg.tsx new file mode 100644 index 0000000..b404ca7 --- /dev/null +++ b/src/CIconSvg.tsx @@ -0,0 +1,104 @@ +import React, { Children, HTMLAttributes, forwardRef } from 'react' +import PropTypes from 'prop-types' +import classNames from 'classnames' +import './CIcon.css' + +export interface CIconSvgProps extends Omit, 'content'> { + /** + * A string of all className you want applied to the component. + */ + className?: string + /** + * Use for replacing default CIcon component classes. Prop is overriding the 'size' prop. + */ + customClassName?: string | string[] + /** + * The height attribute defines the vertical length of an icon. + */ + height?: number + /** + * Size of the icon. Available sizes: 'sm', 'lg', 'xl', 'xxl', '3xl...9xl', 'custom', 'custom-size'. + */ + size?: + | 'custom' + | 'custom-size' + | 'sm' + | 'lg' + | 'xl' + | 'xxl' + | '3xl' + | '4xl' + | '5xl' + | '6xl' + | '7xl' + | '8xl' + | '9xl' + /** + * Title tag content. + */ + title?: string + /** + * The width attribute defines the horizontal length of an icon. + */ + width?: number +} + +export const CIconSvg = forwardRef( + ({ children, className, customClassName, height, size, title, width, ...rest }, ref) => { + const _className = customClassName + ? classNames(customClassName) + : classNames( + 'icon', + { + [`icon-${size}`]: size, + [`icon-custom-size`]: height || width, + }, + className, + ) + + return ( + <> + {Children.map(children, (child) => { + if (React.isValidElement(child)) { + return React.cloneElement(child as React.ReactElement, { + 'aria-hidden': true, + className: _className, + focusable: 'false', + ref: ref, + role: 'img', + ...rest, + }) + } + + return + })} + {title && {title}} + + ) + }, +) + +CIconSvg.propTypes = { + className: PropTypes.string, + customClassName: PropTypes.string, + height: PropTypes.number, + size: PropTypes.oneOf([ + 'custom', + 'custom-size', + 'sm', + 'lg', + 'xl', + 'xxl', + '3xl', + '4xl', + '5xl', + '6xl', + '7xl', + '8xl', + '9xl', + ]), + title: PropTypes.string, + width: PropTypes.number, +} + +CIconSvg.displayName = 'CIconSvg' diff --git a/src/__tests__/CIcon.spec.tsx b/src/__tests__/CIcon.spec.tsx index ee714bb..566d127 100644 --- a/src/__tests__/CIcon.spec.tsx +++ b/src/__tests__/CIcon.spec.tsx @@ -1,22 +1,14 @@ import React from 'react' import { render } from '@testing-library/react' -import '@testing-library/jest-dom/extend-expect' +import '@testing-library/jest-dom' import CIcon from './../' -// import { cifAu } from './../../../icons/js/flag/cif-au' - describe('CIcon', () => { it('renders svg with class="icon"', () => { const { container } = render() expect(container.firstChild).toHaveClass('icon') }) - // it('renders svg with icon', () => { - // const { container } = render() - // expect(container.firstChild).toContain(cifAu[1]) - // // expect(render()).toContain(cifAu) - // }) - it('renders svg with size', () => { const { container } = render() expect(container.firstChild).toHaveClass('icon-xl') @@ -32,8 +24,8 @@ describe('CIcon', () => { expect(container.firstChild).toHaveClass('icon-test') }) - // it('renders with ', () => { - // const { container } = render() - // expect(container.firstChild?.firstChild).toContain('') - // }) + it('renders svg with custom className', () => { + const { container } = render() + expect(container.firstChild).toHaveClass('icon-custom-test') + }) }) diff --git a/src/index.ts b/src/index.ts index 5ebb4bc..13835ba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,5 @@ import { CIcon } from './CIcon' +import { CIconSvg } from './CIconSvg' +export { CIcon, CIconSvg } export default CIcon diff --git a/tsconfig.json b/tsconfig.json index ed928e2..7f4d467 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,6 @@ "noImplicitThis": true, "noImplicitAny": true, "strictNullChecks": true, - "suppressImplicitAnyIndexErrors": true, "noUnusedLocals": true, "noUnusedParameters": true, "esModuleInterop": true pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy