diff --git a/docs/lib/Components/PlaceholderPage.js b/docs/lib/Components/PlaceholderPage.js new file mode 100644 index 000000000..31a602641 --- /dev/null +++ b/docs/lib/Components/PlaceholderPage.js @@ -0,0 +1,97 @@ +import React from 'react'; +import { PrismCode } from 'react-prism'; +import PageTitle from '../UI/PageTitle'; +import SectionTitle from '../UI/SectionTitle'; + +import PlaceholderExample from '../examples/Placeholder' +const PlaceholderExampleSource = require('!!raw-loader!../examples/Placeholder') + +import PlaceholderWidthExample from '../examples/PlaceholderWidth'; +const PlaceholderWidthExampleSource = require('!!raw-loader!../examples/PlaceholderWidth'); + +import PlaceholderColorExample from '../examples/PlaceholderColor'; +const PlaceholderColorExampleSource = require('!!raw-loader!../examples/PlaceholderColor'); + +import PlaceholderSizingExample from '../examples/PlaceholderSizing'; +const PlaceholderSizingExampleSource = require('!!raw-loader!../examples/PlaceholderSizing'); + +import PlaceholderAnimationExample from '../examples/PlaceholderAnimation'; +const PlaceholderAnimationExampleSource = require('!!raw-loader!../examples/PlaceholderAnimation'); + +export default class Placeholder extends React.Component { + render() { + return ( +
+ +
+ +
+
+          
+            {PlaceholderExampleSource}
+          
+        
+

Properties

+
+          
+            {`
+Placeholder.propTypes = {
+  color: PropTypes.string,
+  tag: tagPropType,
+  animation: PropTypes.oneOf(['glow', 'wave']),
+  innerRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func, PropTypes.string]),
+  className: PropTypes.string,
+  size: PropTypes.oneOf(['lg', 'sm', 'xs']),
+  widths: PropTypes.array,
+};
+
+PlaceholderButton.propTypes = {
+  size: PropTypes.string,
+  color: PropTypes.string,
+  outline: PropTypes.bool,
+  className: PropTypes.string,
+  tag: tagPropType
+}
+            `}
+          
+        
+ Width +
+ +
+
+          
+            {PlaceholderWidthExampleSource}
+          
+        
+ Animation +
+ +
+
+          
+            {PlaceholderAnimationExampleSource}
+          
+        
+ Color +
+ +
+
+          
+            {PlaceholderColorExampleSource}
+          
+        
+ Sizing +
+ +
+
+          
+            {PlaceholderSizingExampleSource}
+          
+        
+
+ ) + } +} \ No newline at end of file diff --git a/docs/lib/Components/index.js b/docs/lib/Components/index.js index c1ea17a44..8280105bf 100644 --- a/docs/lib/Components/index.js +++ b/docs/lib/Components/index.js @@ -86,6 +86,10 @@ const items = [ name: 'Navs', to: '/components/navs/' }, + { + name: 'Placeholder', + to: '/components/placeholder/' + }, { name: 'Spinners', to: '/components/spinners/' diff --git a/docs/lib/examples/Placeholder.js b/docs/lib/examples/Placeholder.js new file mode 100644 index 000000000..3e8620910 --- /dev/null +++ b/docs/lib/examples/Placeholder.js @@ -0,0 +1,22 @@ +import React from 'react'; +import { Placeholder, Card, CardTitle, CardText, CardBody, CardImg, PlaceholderButton } from 'reactstrap'; + +const Example = (props) => { + return ( + + + + + + + + {' '} + + + + + + ); +}; + +export default Example; \ No newline at end of file diff --git a/docs/lib/examples/PlaceholderAnimation.js b/docs/lib/examples/PlaceholderAnimation.js new file mode 100644 index 000000000..6b56acd91 --- /dev/null +++ b/docs/lib/examples/PlaceholderAnimation.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { Placeholder, } from 'reactstrap'; + +const Example = (props) => { + return ( +
+ + + + + + +
+ ) +} + +export default Example; \ No newline at end of file diff --git a/docs/lib/examples/PlaceholderColor.js b/docs/lib/examples/PlaceholderColor.js new file mode 100644 index 000000000..121fa1940 --- /dev/null +++ b/docs/lib/examples/PlaceholderColor.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { Placeholder, } from 'reactstrap'; + +const Example = (props) => { + return ( + <> + + + + + + + + + + + ) +} + +export default Example; \ No newline at end of file diff --git a/docs/lib/examples/PlaceholderSizing.js b/docs/lib/examples/PlaceholderSizing.js new file mode 100644 index 000000000..1db96526b --- /dev/null +++ b/docs/lib/examples/PlaceholderSizing.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { Placeholder, } from 'reactstrap'; + +const Example = (props) => { + return ( +
+ + + + +
+ ) +} + +export default Example; \ No newline at end of file diff --git a/docs/lib/examples/PlaceholderWidth.js b/docs/lib/examples/PlaceholderWidth.js new file mode 100644 index 000000000..3b52b1514 --- /dev/null +++ b/docs/lib/examples/PlaceholderWidth.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { Placeholder, } from 'reactstrap'; + +const Example = (props) => { + return ( +
+ + +
+ ) +} + +export default Example; \ No newline at end of file diff --git a/docs/lib/routes.js b/docs/lib/routes.js index 145bf3a53..7fcd4734e 100644 --- a/docs/lib/routes.js +++ b/docs/lib/routes.js @@ -31,6 +31,7 @@ import CarouselPage from './Components/CarouselPage'; import ListGroupPage from './Components/ListGroupPage'; import ListPage from './Components/ListPage'; import SpinnersPage from './Components/SpinnersPage'; +import PlaceholderPage from './Components/PlaceholderPage'; import ClearfixPage from './Utilities/ClearfixPage'; import ColorsPage from './Utilities/ColorsPage'; import NotFound from './NotFound'; @@ -72,6 +73,7 @@ const routes = ( + diff --git a/package.json b/package.json index c7a8bfc21..23c9b8e98 100644 --- a/package.json +++ b/package.json @@ -282,7 +282,7 @@ "@types/react": "^16.9.51", "babel-eslint": "^9.0.0", "babel-loader": "^8.2.2", - "bootstrap": "^5.0.0-beta2", + "bootstrap": "^5.1.0", "clean-webpack-plugin": "^4.0.0", "conventional-changelog-cli": "^2.0.21", "conventional-recommended-bump": "^4.1.1", diff --git a/src/Col.js b/src/Col.js index 9e3090cc0..f2a95c17b 100644 --- a/src/Col.js +++ b/src/Col.js @@ -45,18 +45,12 @@ const getColumnSizeClass = (isXs, colWidth, colSize) => { return isXs ? `col-${colSize}` : `col-${colWidth}-${colSize}`; }; -const Col = (props) => { - const { - className, - cssModule, - widths, - tag: Tag, - ...attributes - } = props; - const colClasses = []; +export const getColumnClasses = (attributes, cssModule, widths=colWidths) => { + const colClasses = []; + widths.forEach((colWidth, i) => { - let columnProp = props[colWidth]; + let columnProp = attributes[colWidth]; delete attributes[colWidth]; @@ -81,6 +75,24 @@ const Col = (props) => { } }); + return { + colClasses, + attributes + } +} + + +const Col = (props) => { + const { + className, + cssModule, + widths, + tag: Tag, + ...attributes + } = props; + + let { attributes : modifiedAttributes, colClasses } = getColumnClasses(attributes, cssModule, widths) + if (!colClasses.length) { colClasses.push('col'); } @@ -91,7 +103,7 @@ const Col = (props) => { ), cssModule); return ( - + ); }; diff --git a/src/Placeholder.js b/src/Placeholder.js new file mode 100644 index 000000000..630658fe7 --- /dev/null +++ b/src/Placeholder.js @@ -0,0 +1,55 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { mapToCssModules, tagPropType } from './utils'; +import { getColumnClasses } from './Col'; + +const propTypes = { + color: PropTypes.string, + tag: tagPropType, + animation: PropTypes.oneOf(['glow', 'wave']), + innerRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func, PropTypes.string]), + className: PropTypes.string, + cssModule: PropTypes.object, + size: PropTypes.oneOf(['lg', 'sm', 'xs']), + widths: PropTypes.array, +}; + +const defaultProps = { + tag: 'span' +}; + +const Placeholder = (props) => { + let { + className, + cssModule, + color, + innerRef, + tag: Tag, + animation, + size, + widths, + ...attributes + } = props; + + let { attributes: modifiedAttributes, colClasses } = getColumnClasses(attributes, cssModule) + + const classes = mapToCssModules(classNames( + className, + colClasses, + 'placeholder' + (animation ? '-'+animation : ''), + size ? 'placeholder-'+ size : false, + color ? 'bg-'+color : false + ), cssModule); + + + + return ( + + ); +}; + +Placeholder.propTypes = propTypes; +Placeholder.defaultProps = defaultProps; + +export default Placeholder; \ No newline at end of file diff --git a/src/PlaceholderButton.js b/src/PlaceholderButton.js new file mode 100644 index 000000000..e87a5110e --- /dev/null +++ b/src/PlaceholderButton.js @@ -0,0 +1,48 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { mapToCssModules, tagPropType } from './utils'; +import Button from "./Button"; +import { getColumnClasses } from './Col'; + +const propTypes = { + size: PropTypes.string, + color: PropTypes.string, + outline: PropTypes.bool, + className: PropTypes.string, + tag: tagPropType +} + +const defaultProps = { + color: 'secondary', + tag: Button +} + +const PlaceholderButton = (props) => { + let { + size, + color, + outline, + cssModule, + className, + tag: Tag, + ...attributes + } = props; + + let { attributes: modifiedAttributes, colClasses } = getColumnClasses(attributes, cssModule) + + const classes = mapToCssModules(classNames( + "placeholder", + className, + colClasses + ), cssModule); + + return ( + + ) +} + +PlaceholderButton.propTypes = propTypes; +PlaceholderButton.defaultProps = defaultProps; + +export default PlaceholderButton \ No newline at end of file diff --git a/src/__tests__/Placeholder.spec.js b/src/__tests__/Placeholder.spec.js new file mode 100644 index 000000000..2ee99e6e4 --- /dev/null +++ b/src/__tests__/Placeholder.spec.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { shallow } from 'enzyme' +import { Placeholder } from '../'; + +describe('Placeholder', () => { + it('should render with "placeholder" class', () => { + const wrapper = shallow() + expect(wrapper.hasClass('placeholder')).toBe(true); + }) + + it('should render column size', () => { + const wrapper = shallow(); + expect(wrapper.hasClass('col-7')).toBe(true); + }) + + it('should render animation', () => { + const wrapper = shallow(); + expect(wrapper.hasClass('placeholder-glow')).toBe(true); + }) + + it('should render color', () => { + const wrapper = shallow(); + expect(wrapper.hasClass('bg-primary')).toBe(true); + }) + + it('should render size', () => { + const wrapper = shallow(); + expect(wrapper.hasClass('placeholder-lg')).toBe(true); + }) +}) diff --git a/src/__tests__/PlaceholderButton.spec.js b/src/__tests__/PlaceholderButton.spec.js new file mode 100644 index 000000000..34fd74275 --- /dev/null +++ b/src/__tests__/PlaceholderButton.spec.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { PlaceholderButton } from '../' + +describe('PlaceholderButton', () => { + it('should render a placeholder', () => { + const wrapper = shallow(); + expect(wrapper.hasClass('placeholder')).toBe(true); + }) + + it('should render size', () => { + const wrapper = shallow(); + expect(wrapper.hasClass('col-6')).toBe(true); + }) +}) \ No newline at end of file diff --git a/src/index.js b/src/index.js index 6d5d1657e..00fb189f7 100644 --- a/src/index.js +++ b/src/index.js @@ -91,5 +91,7 @@ export UncontrolledCollapse from './UncontrolledCollapse'; export UncontrolledDropdown from './UncontrolledDropdown'; export UncontrolledTooltip from './UncontrolledTooltip'; export Spinner from './Spinner'; +export Placeholder from './Placeholder'; +export PlaceholderButton from "./PlaceholderButton" export * as Util from './utils'; export * as Polyfill from './polyfill' diff --git a/yarn.lock b/yarn.lock index 0c449e7d2..c3345162f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2995,10 +2995,10 @@ boolbase@^1.0.0, boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= -bootstrap@^5.0.0-beta2: - version "5.0.0-beta2" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.0.0-beta2.tgz#ab1504a12807fa58e5e41408e35fcea42461e84b" - integrity sha512-e+uPbPHqTQWKyCX435uVlOmgH9tUt0xtjvyOC7knhKgOS643BrQKuTo+KecGpPV7qlmOyZgCfaM4xxPWtDEN/g== +bootstrap@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.0.tgz#543ef8f44f4b9af67b0230f19508542fec38ef55" + integrity sha512-bs74WNI9BgBo3cEovmdMHikSKoXnDgA6VQjJ7TyTotU6L7d41ZyCEEelPwkYEzsG/Zjv3ie9IE3EMAje0W9Xew== brace-expansion@^1.1.7: version "1.1.11"