├── src ├── components │ ├── table │ │ ├── TableRow.jsx │ │ ├── TableBody.jsx │ │ ├── TableCell.jsx │ │ ├── TableHead.jsx │ │ └── TableHeaderCell.jsx │ ├── slider │ │ ├── Slider.module.css │ │ └── Slider.jsx │ ├── spacer │ │ └── Spacer.jsx │ ├── radio-group │ │ ├── RadioGroup.module.css │ │ └── RadioGroup.jsx │ ├── tooltip │ │ └── Tooltip.module.css │ ├── list │ │ ├── List.jsx │ │ ├── ListItem.jsx │ │ ├── ListItemGroup.jsx │ │ └── List.module.css │ ├── switch │ │ ├── Switch.jsx │ │ └── Switch.module.css │ ├── typography │ │ ├── types │ │ │ ├── H1.jsx │ │ │ ├── H2.jsx │ │ │ ├── H3.jsx │ │ │ ├── H4.jsx │ │ │ ├── H5.jsx │ │ │ ├── H6.jsx │ │ │ ├── Body1.jsx │ │ │ ├── Body2.jsx │ │ │ ├── Caption.jsx │ │ │ ├── Overline.jsx │ │ │ ├── Subtitle1.jsx │ │ │ └── Subtitle2.jsx │ │ ├── Typography.jsx │ │ └── Typography.module.css │ ├── parallax │ │ └── Parallax.module.css │ ├── button-icon │ │ └── IconButton.jsx │ ├── button-fab │ │ ├── Fab.module.css │ │ └── Fab.jsx │ ├── dialog │ │ ├── Dialog.module.css │ │ └── Dialog.jsx │ ├── radio │ │ ├── Radio.jsx │ │ └── Radio.module.css │ ├── checkbox │ │ └── Checkbox.jsx │ ├── tab │ │ ├── TabItem.jsx │ │ ├── Tab.jsx │ │ └── Tab.module.css │ ├── avatar │ │ └── Avatar.module.css │ ├── carousel │ │ ├── CarouselItem.jsx │ │ └── Carousel.module.css │ ├── form │ │ └── Form.jsx │ ├── divider │ │ ├── Divider.jsx │ │ └── Divider.module.css │ ├── card │ │ ├── CardAction.jsx │ │ ├── CardContent.jsx │ │ ├── CardMedia.jsx │ │ ├── Card.jsx │ │ └── CardHeader.jsx │ ├── input │ │ └── Textarea.jsx │ ├── button-toggle │ │ └── ToggleButton.jsx │ ├── styles.css │ ├── alert │ │ └── Alert.module.css │ ├── badge │ │ └── Badge.module.css │ ├── button │ │ └── Button.jsx │ ├── button-toggle-group │ │ └── ToggleButtonGroup.jsx │ └── progress │ │ └── ProgressLinear.jsx ├── .eslintrc ├── assets │ ├── index.js │ └── types.js ├── util │ ├── index.js │ ├── common.js │ ├── react-helpers.js │ └── dom-helpers.js ├── hocs │ ├── index.js │ ├── withImage.jsx │ ├── withClickOutside.jsx │ └── withResize.jsx ├── transitions │ ├── index.js │ ├── Fade.jsx │ ├── Grow.jsx │ ├── TransitionWrapper.jsx │ ├── Slide.jsx │ └── SlideCarousel.jsx ├── index.js └── index.test.js ├── .travis.yml ├── .eslintignore ├── example ├── src │ ├── react-app-env.d.ts │ ├── docs │ │ ├── code │ │ │ ├── typography-code.js │ │ │ ├── parallax-code.js │ │ │ ├── index.js │ │ │ ├── divider-code.js │ │ │ ├── progress-code.js │ │ │ ├── carousel-code.js │ │ │ ├── avatar-code.js │ │ │ ├── selection-control-code.js │ │ │ ├── table-code.js │ │ │ └── card-code.js │ │ ├── index.js │ │ ├── api │ │ │ ├── divider-api.js │ │ │ ├── index.js │ │ │ ├── dialog-api.js │ │ │ ├── parallax-api.js │ │ │ ├── tooltip-api.js │ │ │ ├── avatar-api.js │ │ │ ├── table-api.js │ │ │ ├── alert-api.js │ │ │ ├── tab-api.js │ │ │ ├── carousel-api.js │ │ │ ├── progress-api.js │ │ │ ├── chip-api.js │ │ │ └── badge-api.js │ │ └── common.js │ ├── examples │ │ └── index.js │ ├── pages │ │ ├── Test.tsx │ │ ├── Test.jsx │ │ ├── Example.jsx │ │ ├── SnackbarView.jsx │ │ ├── MenuView.jsx │ │ ├── SelectView.jsx │ │ ├── FormView.jsx │ │ ├── PaginationView.jsx │ │ ├── ExpansionPanelView.jsx │ │ ├── SliderView.jsx │ │ ├── DividerView.jsx │ │ ├── TextareaView.jsx │ │ ├── DialogView.jsx │ │ ├── index.js │ │ ├── TypographyView.jsx │ │ ├── TooltipView.jsx │ │ ├── SwitchView.jsx │ │ ├── CheckboxView.jsx │ │ └── IconButtonView.jsx │ ├── App.test.js │ ├── App.js │ ├── index.js │ └── containers │ │ ├── RightBar.jsx │ │ ├── DocCard.jsx │ │ ├── Topbar.jsx │ │ ├── CodeBlock.jsx │ │ ├── ApiCard.jsx │ │ └── Sidebar.jsx ├── public │ ├── ads.txt │ ├── favicon.ico │ ├── images │ │ ├── beaches-2.jpg │ │ └── dessert-night.jpg │ ├── manifest.json │ └── 404.html ├── README.md ├── tsconfig.json ├── package.json ├── 404.html └── debug.log ├── .editorconfig ├── .prettierrc ├── .gitignore ├── tsconfig.json ├── .eslintrc ├── LICENSE ├── package.json └── README.md /src/components/table/TableRow.jsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/table/TableBody.jsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/table/TableCell.jsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/table/TableHead.jsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/slider/Slider.module.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/table/TableHeaderCell.jsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12 4 | - 10 5 | -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | node_modules/ 4 | .snapshots/ 5 | *.min.js -------------------------------------------------------------------------------- /example/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /example/public/ads.txt: -------------------------------------------------------------------------------- 1 | google.com, pub-9381121077394867, DIRECT, f08c47fec0942fa0 -------------------------------------------------------------------------------- /src/assets/index.js: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | export * from './prop-types' 3 | -------------------------------------------------------------------------------- /example/src/docs/code/typography-code.js: -------------------------------------------------------------------------------- 1 | export const typography = () =>{ 2 | return `DocCard` 3 | } -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-neumorphism/HEAD/example/public/favicon.ico -------------------------------------------------------------------------------- /example/src/docs/index.js: -------------------------------------------------------------------------------- 1 | export * from './common' 2 | export * from './api/' 3 | export * from './code/' 4 | -------------------------------------------------------------------------------- /src/util/index.js: -------------------------------------------------------------------------------- 1 | export * from './common' 2 | export * from './dom-helpers' 3 | export * from './react-helpers' 4 | -------------------------------------------------------------------------------- /example/public/images/beaches-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-neumorphism/HEAD/example/public/images/beaches-2.jpg -------------------------------------------------------------------------------- /example/public/images/dessert-night.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-neumorphism/HEAD/example/public/images/dessert-night.jpg -------------------------------------------------------------------------------- /example/src/examples/index.js: -------------------------------------------------------------------------------- 1 | 2 | export { default as ClockApp } from './ClockApp.jsx' 3 | export { default as FitnessApp } from './FitnessApp.jsx' -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /src/hocs/index.js: -------------------------------------------------------------------------------- 1 | export { default as withImage } from './withImage.jsx' 2 | export { default as withResize } from './withResize.jsx' 3 | export { default as withClickOutside } from './withClickOutside.jsx' 4 | -------------------------------------------------------------------------------- /src/components/slider/Slider.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | class Slider extends React.Component { 4 | render() { 5 | return
Slider
6 | } 7 | } 8 | 9 | export default Slider 10 | -------------------------------------------------------------------------------- /example/src/docs/code/parallax-code.js: -------------------------------------------------------------------------------- 1 | export const simpleParallax = (dark, props) => { 2 | const p = props ? props + ' ' : '' 3 | return `` 4 | } 5 | -------------------------------------------------------------------------------- /src/transitions/index.js: -------------------------------------------------------------------------------- 1 | export { default as Fade } from './Fade' 2 | export { default as Grow } from './Grow' 3 | export { default as Slide } from './Slide' 4 | export { default as SlideCarousel } from './SlideCarousel' 5 | -------------------------------------------------------------------------------- /example/src/pages/Test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Dialog } from 'ui-neumorphism'; 4 | 5 | export class Abc extends React.Component { 6 | render() { 7 | return
8 | } 9 | } -------------------------------------------------------------------------------- /src/components/spacer/Spacer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | class Spacer extends React.Component { 4 | render() { 5 | return
6 | } 7 | } 8 | 9 | export default Spacer 10 | -------------------------------------------------------------------------------- /example/src/pages/Test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { TextArea } from 'ui-neumorphism' 4 | 5 | export class Abc extends React.Component { 6 | render() { 7 | return 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": true, 4 | "semi": false, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "jsxBracketSameLine": false, 8 | "arrowParens": "always", 9 | "trailingComma": "none" 10 | } 11 | -------------------------------------------------------------------------------- /src/components/radio-group/RadioGroup.module.css: -------------------------------------------------------------------------------- 1 | .nu-radio-group { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: flex-start; 5 | justify-content: center; 6 | } 7 | 8 | .nu-radio-group--vertical { 9 | flex-direction: column; 10 | } 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This example was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | It is linked to the ui-neumorphism package in the parent directory for development purposes. 4 | 5 | You can run `npm install` and then `npm start` to test your package. 6 | -------------------------------------------------------------------------------- /example/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div') 7 | ReactDOM.render(, div) 8 | ReactDOM.unmountComponentAtNode(div) 9 | }) 10 | -------------------------------------------------------------------------------- /src/components/tooltip/Tooltip.module.css: -------------------------------------------------------------------------------- 1 | .nu-tooltip { 2 | z-index: 10; 3 | width: auto; 4 | font-size: 14px; 5 | padding: 8px 16px; 6 | position: absolute; 7 | pointer-events: none; 8 | display: inline-block; 9 | transform-origin: center; 10 | transition: opacity 0.2s ease-in-out; 11 | } 12 | -------------------------------------------------------------------------------- /example/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import MainContainer from './containers/MainContainer.jsx' 4 | 5 | console.log('%cUI-Neumorphism', 'color: #2979FF;font-size:60px;') 6 | console.log('If you like it, consider giving a ⭐ on github! 😄') 7 | 8 | const App = () => { 9 | return 10 | } 11 | 12 | export default App 13 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import './index.css' 2 | 3 | import React from 'react' 4 | import ReactDOM from 'react-dom' 5 | import App from './App' 6 | import { BrowserRouter as Router } from 'react-router-dom'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById('root') 13 | ) 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # See https://help.github.com/ignore-files/ for more about ignoring files. 3 | 4 | # dependencies 5 | node_modules 6 | 7 | # builds 8 | build 9 | dist 10 | .rpt2_cache 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "ui-neumorphism", 3 | "name": "ui-neumorphism", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /example/src/docs/code/index.js: -------------------------------------------------------------------------------- 1 | export * from './card-code' 2 | export * from './table-code' 3 | export * from './alert-code' 4 | export * from './badge-code' 5 | export * from './avatar-code' 6 | export * from './button-code' 7 | export * from './divider-code' 8 | export * from './carousel-code' 9 | export * from './progress-code' 10 | export * from './parallax-code' 11 | export * from './typography-code' 12 | export * from './selection-control-code' 13 | -------------------------------------------------------------------------------- /example/src/docs/code/divider-code.js: -------------------------------------------------------------------------------- 1 | export const divider = (dark) => { 2 | const darkProp = dark ? ' dark' : '' 3 | return ` 4 | Default 5 |
6 | 7 | Dense 8 |
9 | 10 | Elevated 11 |
12 | 13 | Dense & Elevated` 14 | } 15 | -------------------------------------------------------------------------------- /src/components/list/List.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { DEFAULT_PROPS, DEFAULT_PROPS_TYPE } from '../../assets/index' 4 | // import { callCallback } from '../../util' 5 | 6 | class List extends React.Component { 7 | static displayName = 'NuList' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = DEFAULT_PROPS_TYPE 12 | 13 | render() { 14 | return
list
15 | } 16 | } 17 | 18 | export default List 19 | -------------------------------------------------------------------------------- /example/src/docs/api/divider-api.js: -------------------------------------------------------------------------------- 1 | import { createApiDoc, defaultApiDoc } from '../index.js' 2 | 3 | export const dividerApi = (dark) => { 4 | return [ 5 | ...defaultApiDoc(dark), 6 | createApiDoc( 7 | dark, 8 | 'dense', 9 | 'Boolean', 10 | 'false', 11 | 'Reduces height of the divider.' 12 | ), 13 | createApiDoc( 14 | dark, 15 | 'elevated', 16 | 'Boolean', 17 | 'false', 18 | 'Gives an elevation for alternate style.' 19 | ) 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/components/switch/Switch.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { SelectionControl } from '../../index' 4 | 5 | import { DEFAULT_PROPS, SELECTION_CONTROL_PROP_TYPES } from '../../assets/index' 6 | class Switch extends React.Component { 7 | static displayName = 'NuSwitch' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = SELECTION_CONTROL_PROP_TYPES 12 | 13 | render() { 14 | return 15 | } 16 | } 17 | 18 | export default Switch 19 | -------------------------------------------------------------------------------- /example/src/docs/api/index.js: -------------------------------------------------------------------------------- 1 | export * from './tab-api' 2 | export * from './chip-api' 3 | export * from './card-api' 4 | export * from './input-api' 5 | export * from './table-api' 6 | export * from './alert-api' 7 | export * from './badge-api' 8 | export * from './dialog-api' 9 | export * from './button-api' 10 | export * from './avatar-api' 11 | export * from './divider-api' 12 | export * from './tooltip-api' 13 | export * from './carousel-api' 14 | export * from './progress-api' 15 | export * from './parallax-api' 16 | export * from './selection-control-api' 17 | -------------------------------------------------------------------------------- /src/components/typography/types/H1.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class H1 extends React.Component { 7 | static displayName = 'NuH1' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default H1 23 | -------------------------------------------------------------------------------- /src/components/typography/types/H2.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class H2 extends React.Component { 7 | static displayName = 'NuH2' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default H2 23 | -------------------------------------------------------------------------------- /src/components/typography/types/H3.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class H3 extends React.Component { 7 | static displayName = 'NuH3' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default H3 23 | -------------------------------------------------------------------------------- /src/components/typography/types/H4.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class H4 extends React.Component { 7 | static displayName = 'NuH4' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default H4 23 | -------------------------------------------------------------------------------- /src/components/typography/types/H5.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class H5 extends React.Component { 7 | static displayName = 'NuH5' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default H5 23 | -------------------------------------------------------------------------------- /src/components/typography/types/H6.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class H6 extends React.Component { 7 | static displayName = 'NuH6' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default H6 23 | -------------------------------------------------------------------------------- /src/components/parallax/Parallax.module.css: -------------------------------------------------------------------------------- 1 | .nu-parallax { 2 | position: relative; 3 | overflow: hidden; 4 | width: inherit; 5 | z-index: 1; 6 | } 7 | 8 | .nu-parallax--img-container { 9 | position: absolute; 10 | top: 0; 11 | left: 0; 12 | right: 0; 13 | bottom: 0; 14 | z-index: 2; 15 | contain: strict; 16 | } 17 | 18 | .nu-parallax--img { 19 | position: absolute; 20 | bottom: 0; 21 | left: 50%; 22 | z-index: 2; 23 | min-width: 100%; 24 | min-height: 100%; 25 | will-change: transform; 26 | transition: opacity 0.3s cubic-bezier(.25,.8,.5,1); 27 | } 28 | -------------------------------------------------------------------------------- /src/components/typography/types/Body1.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class Body1 extends React.Component { 7 | static displayName = 'NuBody1' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default Body1 23 | -------------------------------------------------------------------------------- /src/components/typography/types/Body2.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class Body2 extends React.Component { 7 | static displayName = 'NuBody2' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default Body2 23 | -------------------------------------------------------------------------------- /src/components/typography/types/Caption.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class Caption extends React.Component { 7 | static displayName = 'NuCaption' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default Caption 23 | -------------------------------------------------------------------------------- /src/components/typography/types/Overline.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class Overline extends React.Component { 7 | static displayName = 'NuOverline' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default Overline 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "noEmit": true, 20 | "jsx": "react" 21 | }, 22 | "include": [ 23 | "src" 24 | ] 25 | } -------------------------------------------------------------------------------- /src/components/typography/types/Subtitle1.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class Subtitle1 extends React.Component { 7 | static displayName = 'NuSubtitle1' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default Subtitle1 23 | -------------------------------------------------------------------------------- /src/components/typography/types/Subtitle2.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Typography } from '../../index' 4 | import { DEFAULT_PROPS, TYPOGRAPHY_PROP_TYPES } from '../../../assets/index' 5 | 6 | class Subtitle2 extends React.Component { 7 | static displayName = 'NuSubtitle2' 8 | 9 | static defaultProps = DEFAULT_PROPS 10 | 11 | static propTypes = TYPOGRAPHY_PROP_TYPES 12 | 13 | render() { 14 | return ( 15 | 16 | {this.props.children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default Subtitle2 23 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "noEmit": true, 20 | "jsx": "react" 21 | }, 22 | "include": [ 23 | "src" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /example/src/docs/api/dialog-api.js: -------------------------------------------------------------------------------- 1 | import { createApiDoc, defaultApiDoc, cssDimensionsApi } from '../index.js' 2 | 3 | export const dialogApi = (dark) => { 4 | return [ 5 | ...defaultApiDoc(dark), 6 | ...cssDimensionsApi(dark, 'dialog'), 7 | createApiDoc( 8 | dark, 9 | 'visible', 10 | 'Boolean', 11 | 'false', 12 | 'Controls whether the dialog is visible or hidden.' 13 | ), 14 | createApiDoc( 15 | dark, 16 | 'persistent', 17 | 'Boolean', 18 | 'false', 19 | 'Clicking outside of the children will not call the onClose callback.' 20 | ) 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react" 6 | ], 7 | "env": { 8 | "node": true 9 | }, 10 | "parserOptions": { 11 | "ecmaVersion": 2020, 12 | "ecmaFeatures": { 13 | "legacyDecorators": true, 14 | "jsx": true 15 | } 16 | }, 17 | "settings": { 18 | "react": { 19 | "version": "16" 20 | } 21 | }, 22 | "rules": { 23 | "space-before-function-paren": 0, 24 | "react/prop-types": 0, 25 | "react/jsx-handler-names": 0, 26 | "react/jsx-fragments": 0, 27 | "react/no-unused-prop-types": 0, 28 | "import/export": 0 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example/src/containers/RightBar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, Subtitle1, Caption } from 'ui-neumorphism' 4 | 5 | class RightBar extends React.Component { 6 | render() { 7 | const { dark } = this.props 8 | return ( 9 | 10 | Contents 11 | 12 | Component 13 | 14 | 15 | API 16 | 17 | 18 | ) 19 | } 20 | } 21 | 22 | export default RightBar 23 | -------------------------------------------------------------------------------- /src/components/button-icon/IconButton.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Button } from '../index' 4 | 5 | import { BUTTON_PROP_TYPES, DEFAULT_PROPS } from '../../assets/index' 6 | class IconButton extends React.Component { 7 | static displayName = 'NuIconButton' 8 | 9 | static defaultProps = { 10 | text: true, 11 | ...DEFAULT_PROPS 12 | } 13 | 14 | static propTypes = BUTTON_PROP_TYPES 15 | 16 | render() { 17 | const { children, ...otherProps } = this.props 18 | return ( 19 | 22 | ) 23 | } 24 | } 25 | 26 | export default IconButton 27 | -------------------------------------------------------------------------------- /src/components/button-fab/Fab.module.css: -------------------------------------------------------------------------------- 1 | .nu-fab { 2 | display: inline-flex; 3 | } 4 | 5 | .nu-fab.nu-fab--animation { 6 | transform-origin: center center; 7 | animation: fab-animate 350ms ease-in-out 1; 8 | } 9 | 10 | .nu-fab--fixed { 11 | position: fixed; 12 | } 13 | 14 | .nu-fab--absolute { 15 | position: absolute; 16 | } 17 | 18 | .nu-fab.nu-fab--top { 19 | top: 16px; 20 | } 21 | 22 | .nu-fab.nu-fab--right { 23 | right: 16px; 24 | } 25 | 26 | .nu-fab.nu-fab--bottom { 27 | bottom: 16px; 28 | } 29 | 30 | .nu-fab.nu-fab--left { 31 | left: 16px; 32 | } 33 | 34 | @keyframes fab-animate { 35 | 0% { 36 | transform: scale(1) 37 | } 38 | 39 | 50% { 40 | transform: scale(0) 41 | } 42 | 43 | 100% { 44 | transform: scale(1) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/components/dialog/Dialog.module.css: -------------------------------------------------------------------------------- 1 | .nu-dialog { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | outline: 0; 6 | width: 100%; 7 | height: 100%; 8 | z-index: 1050; 9 | display: flex; 10 | overflow: hidden; 11 | align-items: center; 12 | justify-content: center; 13 | color: var(--text-color); 14 | } 15 | 16 | .nu-dialog.nu-dialog--light { 17 | --bg-color: var(--light-bg); 18 | --text-color: var(--g-text-color-light); 19 | } 20 | 21 | .nu-dialog.nu-dialog--dark { 22 | --bg-color: var(--dark-bg); 23 | --text-color: var(--g-text-color-dark); 24 | --border-color: var(--dark-bg-light-shadow); 25 | } 26 | 27 | .nu-dialog-overlay { 28 | width: 100%; 29 | height: 100%; 30 | opacity: 0.96; 31 | background: var(--bg-color); 32 | } 33 | 34 | .nu-dialog-content { 35 | position: absolute; 36 | } 37 | -------------------------------------------------------------------------------- /src/components/radio/Radio.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { SelectionControl } from '../../index' 4 | 5 | import { callCallback } from '../../util' 6 | import { DEFAULT_PROPS, SELECTION_CONTROL_PROP_TYPES } from '../../assets/index' 7 | class Radio extends React.Component { 8 | static displayName = 'NuRadio' 9 | 10 | static defaultProps = DEFAULT_PROPS 11 | 12 | static propTypes = SELECTION_CONTROL_PROP_TYPES 13 | 14 | handleChange({ event, id, checked }) { 15 | const { value, onChange } = this.props 16 | callCallback(onChange, { event, id, checked, value }) 17 | } 18 | 19 | render() { 20 | return ( 21 | this.handleChange(e)} 25 | /> 26 | ) 27 | } 28 | } 29 | 30 | export default Radio 31 | -------------------------------------------------------------------------------- /src/components/checkbox/Checkbox.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { SelectionControl } from '../../index' 4 | 5 | import { DEFAULT_PROPS, SELECTION_CONTROL_PROP_TYPES } from '../../assets/index' 6 | import { callCallback } from '../../util' 7 | 8 | class Checkbox extends React.Component { 9 | static displayName = 'NuCheckbox' 10 | 11 | static defaultProps = DEFAULT_PROPS 12 | 13 | static propTypes = SELECTION_CONTROL_PROP_TYPES 14 | 15 | handleChange({ event, id, checked }) { 16 | const { onChange } = this.props 17 | callCallback(onChange, { event, id, value: checked }) 18 | } 19 | 20 | render() { 21 | return ( 22 | this.handleChange(e)} 26 | /> 27 | ) 28 | } 29 | } 30 | 31 | export default Checkbox 32 | -------------------------------------------------------------------------------- /example/src/pages/Example.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, H3, Divider } from 'ui-neumorphism' 4 | import { FitnessApp, ClockApp } from '../examples/' 5 | 6 | class Example extends React.Component { 7 | render() { 8 | const { dark } = this.props 9 | return ( 10 | 11 | 12 |

13 | FITNESS APP 14 |

15 | 16 |
17 | 18 | 19 |

20 | CLOCK APP 21 |

22 | 23 |
24 |
25 | ) 26 | } 27 | } 28 | 29 | export default Example 30 | -------------------------------------------------------------------------------- /src/components/tab/TabItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | // import { Button } from '../../index' 4 | 5 | import styles from './Tab.module.css' 6 | 7 | import { DEFAULT_PROPS, DEFAULT_PROPS_TYPE } from '../../assets/index' 8 | import { getModuleClasses } from '../../util' 9 | 10 | class TabItem extends React.Component { 11 | static displayName = 'NuTabItem' 12 | 13 | static defaultProps = DEFAULT_PROPS 14 | 15 | static propTypes = DEFAULT_PROPS_TYPE 16 | 17 | getClasses(elem) { 18 | return getModuleClasses(styles, elem) 19 | } 20 | 21 | render() { 22 | const { style, className, children } = this.props 23 | return ( 24 |
28 | {children} 29 |
30 | ) 31 | } 32 | } 33 | 34 | export default TabItem 35 | -------------------------------------------------------------------------------- /src/components/avatar/Avatar.module.css: -------------------------------------------------------------------------------- 1 | .nu-avatar { 2 | display: flex; 3 | overflow: hidden; 4 | user-select: none; 5 | align-items: center; 6 | justify-content: center; 7 | color: var(--avatar-text-color); 8 | background: var(--avatar-bg-color); 9 | --avatar-bg-color: var(--primary); 10 | --avatar-text-color: var(--white); 11 | } 12 | 13 | .nu-avatar--img { 14 | width: 100%; 15 | height: 100%; 16 | object-fit: cover; 17 | text-align: center; 18 | } 19 | 20 | .nu-avatar--small { 21 | width: 24px; 22 | height: 24px; 23 | } 24 | 25 | .nu-avatar--medium { 26 | width: 40px; 27 | height: 40px; 28 | } 29 | 30 | .nu-avatar--large { 31 | width: 56px; 32 | height: 56px; 33 | } 34 | 35 | .nu-avatar--circle { 36 | border-radius: 50%; 37 | } 38 | 39 | .nu-avatar--square { 40 | border-radius: 0px; 41 | } 42 | 43 | .nu-avatar--rounded { 44 | border-radius: 8px; 45 | } 46 | -------------------------------------------------------------------------------- /src/components/carousel/CarouselItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Carousel.module.css' 4 | import { getModuleClasses, passDownProp } from '../../util' 5 | import { DEFAULT_PROPS, DEFAULT_PROPS_TYPE } from '../../assets/index' 6 | 7 | class CarouselItem extends React.Component { 8 | static displayName = 'NuCarouselItem' 9 | 10 | static defaultProps = DEFAULT_PROPS 11 | 12 | static propTypes = DEFAULT_PROPS_TYPE 13 | 14 | getClasses(type) { 15 | return getModuleClasses(styles, type) 16 | } 17 | 18 | render() { 19 | const { style, className, children } = this.props 20 | return ( 21 |
25 | {passDownProp(children, this.props, ['dark'])} 26 |
27 | ) 28 | } 29 | } 30 | 31 | export default CarouselItem 32 | -------------------------------------------------------------------------------- /example/src/docs/api/parallax-api.js: -------------------------------------------------------------------------------- 1 | import { createApiDoc, defaultApiDoc } from '../index.js' 2 | 3 | const attribute = (dark, attr) => 4 | createApiDoc( 5 | dark, 6 | attr, 7 | 'String', 8 | '', 9 | `The ${attr} attribute for the img element.` 10 | ) 11 | 12 | export const parallaxApi = (dark) => { 13 | return [ 14 | ...defaultApiDoc(dark), 15 | attribute(dark, 'alt'), 16 | attribute(dark, 'src'), 17 | createApiDoc( 18 | dark, 19 | 'height', 20 | 'Number', 21 | '400', 22 | 'Sets the height for the parallax component.' 23 | ), 24 | createApiDoc( 25 | dark, 26 | 'speed', 27 | 'Number', 28 | '1.0', 29 | 'Sets the speed of the parallax.' 30 | ), 31 | createApiDoc( 32 | dark, 33 | 'containerId', 34 | 'String', 35 | '', 36 | 'Id of the wrapping container(if scrolling inside a container).' 37 | ) 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /src/components/form/Form.jsx: -------------------------------------------------------------------------------- 1 | import React, { Children, cloneElement } from 'react' 2 | 3 | class Form extends React.Component { 4 | constructor(props) { 5 | super(props) 6 | this.state = {} 7 | console.log(props.children) 8 | } 9 | 10 | handleChange({ id, value }) { 11 | this.setState({ [id]: value }) 12 | // console.log(e) 13 | } 14 | 15 | handleFormChange(e) { 16 | // console.log(e.target.id) 17 | } 18 | 19 | handleSubmit(e) { 20 | // console.log(e) 21 | } 22 | 23 | render() { 24 | const { children } = this.props 25 | const formChildren = Children.map(children, (child) => { 26 | return cloneElement(child, { 27 | ...child.props, 28 | onChange: (e) => this.handleChange(e) 29 | }) 30 | }) 31 | return ( 32 |
33 | {formChildren} 34 |
35 | ) 36 | } 37 | } 38 | 39 | export default Form 40 | -------------------------------------------------------------------------------- /src/assets/types.js: -------------------------------------------------------------------------------- 1 | export const CONTEXT_COLORS = ['success', 'info', 'warning', 'error'] 2 | export const SELECTION_CONTROLS = ['radio', 'checkbox', 'switch'] 3 | export const POSITIONS = ['top', 'right', 'bottom', 'left'] 4 | export const ALTERNATE_BUTONS = ['fab', 'icon', 'toggle'] 5 | export const SIZES = ['small', 'medium', 'large'] 6 | export const MOUSE_EVENTS = [ 7 | 'onClick', 8 | 'onMouseUp', 9 | 'onMouseOut', 10 | 'onMouseMove', 11 | 'onMouseDown', 12 | 'onMouseOver', 13 | 'onMouseEnter', 14 | 'onMouseLeave' 15 | ] 16 | export const DARK_PASS_DOWN = ['dark'] 17 | export const CARD_PASS_DOWN = [ 18 | 'dark', 19 | 'rounded', 20 | 'disabled', 21 | 'outlined', 22 | 'bordered' 23 | ] 24 | export const CARD_CHILD_PASS_DOWN = ['dark', 'rounded', 'disabled'] 25 | export const CARD_HEAD_PASS_DOWN = ['dark', 'disabled'] 26 | export const CSS_DIMENSIONS = [ 27 | 'width', 28 | 'height', 29 | 'minWidth', 30 | 'maxWidth', 31 | 'minHeight', 32 | 'maxHeight' 33 | ] 34 | -------------------------------------------------------------------------------- /example/src/docs/api/tooltip-api.js: -------------------------------------------------------------------------------- 1 | import { 2 | createApiDoc, 3 | defaultApiDoc, 4 | cssDimensionsApi, 5 | positionApi 6 | } from '../index.js' 7 | 8 | export const tooltipApi = (dark) => { 9 | return [ 10 | ...defaultApiDoc(dark), 11 | ...cssDimensionsApi(dark, 'tooltip'), 12 | ...positionApi(dark, 'tooltip'), 13 | createApiDoc( 14 | dark, 15 | 'inset', 16 | 'Boolean', 17 | 'false', 18 | "Reverses the tooltip's elevation." 19 | ), 20 | createApiDoc( 21 | dark, 22 | 'content', 23 | 'Node, isRequired', 24 | '', 25 | 'Content of the tooltip.' 26 | ), 27 | createApiDoc( 28 | dark, 29 | 'transition', 30 | 'Grow | Fade', 31 | 'Grow', 32 | 'Transition style for the tooltip.' 33 | ), 34 | createApiDoc( 35 | dark, 36 | 'visible', 37 | 'Boolean', 38 | 'false', 39 | 'Controls whether the tooltip is visible or hidden.' 40 | ) 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /src/components/divider/Divider.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Divider.module.css' 4 | import { getModuleClasses } from '../../util' 5 | import { G_BOOL, DEFAULT_PROPS, DEFAULT_PROPS_TYPE } from '../../assets/index' 6 | 7 | class Divider extends React.Component { 8 | static displayName = 'NuDivider' 9 | 10 | static defaultProps = DEFAULT_PROPS 11 | 12 | static propTypes = { 13 | dense: G_BOOL, 14 | elevated: G_BOOL, 15 | ...DEFAULT_PROPS_TYPE 16 | } 17 | 18 | getClasses() { 19 | const { dark, dense, elevated } = this.props 20 | return getModuleClasses( 21 | styles, 22 | ` 23 | nu-divider 24 | ${dense ? 'nu-divider--dense' : ''} 25 | nu-divider--${dark ? 'dark' : 'light'} 26 | ${elevated ? 'nu-divider--elevated' : ''} 27 | ` 28 | ) 29 | } 30 | 31 | render() { 32 | const { style, className } = this.props 33 | return
34 | } 35 | } 36 | 37 | export default Divider 38 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { overrideThemeVariables, detectElementInDOM } from './util/' 2 | export { withImage, withResize, withClickOutside } from './hocs/' 3 | export { Grow, Fade, Slide, SlideCarousel } from './transitions' 4 | 5 | export { 6 | Typography, 7 | Subtitle2, 8 | Subtitle1, 9 | Overline, 10 | Caption, 11 | Body2, 12 | Body1, 13 | H6, 14 | H5, 15 | H4, 16 | H3, 17 | H2, 18 | H1, 19 | CardContent, 20 | CardHeader, 21 | CardAction, 22 | CardMedia, 23 | Card, 24 | List, 25 | ListItem, 26 | ListItemGroup, 27 | ToggleButtonGroup, 28 | ToggleButton, 29 | IconButton, 30 | Button, 31 | Avatar, 32 | Chip, 33 | Fab, 34 | TabItems, 35 | TabItem, 36 | Tabs, 37 | Tab, 38 | ProgressCircular, 39 | ProgressLinear, 40 | CarouselItem, 41 | Carousel, 42 | Parallax, 43 | Tooltip, 44 | Divider, 45 | Spacer, 46 | Dialog, 47 | Alert, 48 | Badge, 49 | Table, 50 | Form, 51 | Radio, 52 | RadioGroup, 53 | TextField, 54 | TextArea, 55 | Switch, 56 | Slider, 57 | Checkbox, 58 | SelectionControl 59 | } from './components/' 60 | -------------------------------------------------------------------------------- /src/util/common.js: -------------------------------------------------------------------------------- 1 | import globalModule from '../components/styles.css' 2 | 3 | export const getModuleClasses = (localModule, classNames) => { 4 | const styles = { 5 | ...localModule, 6 | ...globalModule 7 | } 8 | return classNames 9 | .replace(/^\s+|\s+$/g, '') 10 | .split(/\s+/) 11 | .map((cl) => styles[cl.trim()]) 12 | .join(' ') 13 | .trim() 14 | } 15 | 16 | export const callCallback = (callback, data) => { 17 | if (callback && typeof callback === 'function') { 18 | callback(data) 19 | } 20 | } 21 | 22 | export const pickKeys = (obj, keys) => { 23 | const newObj = {} 24 | const keysLength = keys.length 25 | for (let i = 0; i < keysLength; i++) { 26 | if (Object.prototype.hasOwnProperty.call(obj, keys[i])) { 27 | newObj[keys[i]] = obj[keys[i]] 28 | } 29 | } 30 | return newObj 31 | } 32 | 33 | export const uid = () => { 34 | return `_${(((1 + Math.random()) * 0x10000) | 0).toString(8).substring(1)}_` 35 | } 36 | 37 | export const clearAllTimeout = () => { 38 | let timeoutId = setTimeout(() => {}) 39 | while (timeoutId--) { 40 | clearTimeout(timeoutId) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ankit Kumar Pandit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-neumorphism-example", 3 | "homepage": "https://AKAspanion.github.io/ui-neumorphism", 4 | "version": "0.0.0", 5 | "private": true, 6 | "dependencies": { 7 | "@mdi/js": "^5.2.45", 8 | "@mdi/react": "^1.4.0", 9 | "react": "file:../node_modules/react", 10 | "react-dom": "file:../node_modules/react-dom", 11 | "react-router-dom": "^5.2.0", 12 | "react-scripts": "file:../node_modules/react-scripts", 13 | "react-syntax-highlighter": "^12.2.1", 14 | "ui-neumorphism": "file:.." 15 | }, 16 | "devDependencies": { 17 | "@types/react": "^16.9.43" 18 | }, 19 | "scripts": { 20 | "start": "node ../node_modules/react-scripts/bin/react-scripts.js start", 21 | "build": "node ../node_modules/react-scripts/bin/react-scripts.js build", 22 | "test": "node ../node_modules/react-scripts/bin/react-scripts.js test", 23 | "eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": "react-app" 27 | }, 28 | "browserslist": [ 29 | ">0.2%", 30 | "not dead", 31 | "not ie <= 11", 32 | "not op_mini all" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /src/components/card/CardAction.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Card.module.css' 4 | import { getModuleClasses, passDownProp } from '../../util' 5 | import { 6 | G_BOOL, 7 | DEFAULT_PROPS, 8 | DEFAULT_PROPS_TYPE, 9 | CARD_CHILD_PASS_DOWN 10 | } from '../../assets/index' 11 | 12 | class CardAction extends React.Component { 13 | static displayName = 'NuCardAction' 14 | 15 | static defaultProps = DEFAULT_PROPS 16 | 17 | static propTypes = { 18 | rounded: G_BOOL, 19 | disabled: G_BOOL, 20 | ...DEFAULT_PROPS_TYPE 21 | } 22 | 23 | getClass() { 24 | const { dark, rounded } = this.props 25 | return getModuleClasses( 26 | styles, 27 | ` 28 | nu-card-action 29 | nu-card-action--${dark ? 'dark' : 'light'} 30 | ${rounded ? 'nu-card-action--rounded' : ''} 31 | ` 32 | ) 33 | } 34 | 35 | render() { 36 | const { style, className, children } = this.props 37 | const cardChildren = passDownProp( 38 | children, 39 | this.props, 40 | CARD_CHILD_PASS_DOWN 41 | ) 42 | return ( 43 |
44 | {cardChildren} 45 |
46 | ) 47 | } 48 | } 49 | 50 | export default CardAction 51 | -------------------------------------------------------------------------------- /src/components/card/CardContent.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Card.module.css' 4 | import { getModuleClasses, passDownProp } from '../../util' 5 | import { 6 | G_BOOL, 7 | DEFAULT_PROPS, 8 | DEFAULT_PROPS_TYPE, 9 | CARD_CHILD_PASS_DOWN 10 | } from '../../assets/index' 11 | 12 | class CardContent extends React.Component { 13 | static displayName = 'NuCardContent' 14 | 15 | static defaultProps = DEFAULT_PROPS 16 | 17 | static propTypes = { 18 | rounded: G_BOOL, 19 | disabled: G_BOOL, 20 | ...DEFAULT_PROPS_TYPE 21 | } 22 | 23 | getClass() { 24 | const { dark, rounded } = this.props 25 | return getModuleClasses( 26 | styles, 27 | ` 28 | nu-card-content 29 | nu-card-content--${dark ? 'dark' : 'light'} 30 | ${rounded ? 'nu-card-content--rounded' : ''} 31 | ` 32 | ) 33 | } 34 | 35 | render() { 36 | const { style, className, children } = this.props 37 | const cardChildren = passDownProp( 38 | children, 39 | this.props, 40 | CARD_CHILD_PASS_DOWN 41 | ) 42 | return ( 43 |
44 | {cardChildren} 45 |
46 | ) 47 | } 48 | } 49 | 50 | export default CardContent 51 | -------------------------------------------------------------------------------- /example/src/pages/SnackbarView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, H4, H6 } from 'ui-neumorphism' 4 | 5 | // import { toggle, toggleLabel, switchApi } from '../docs/' 6 | 7 | import DocCard from '../containers/DocCard.jsx' 8 | // import ApiCard from '../containers/ApiCard.jsx' 9 | 10 | const url = 11 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/SnackbarView.jsx' 12 | class SnackbarView extends React.Component { 13 | render() { 14 | const { dark } = this.props 15 | return ( 16 | 17 |

18 | 19 | Snackbar 20 | 21 |

22 |
23 | The Snackbar component is used to display a quick message to a user. 24 |
25 | 29 | Coming soon.. 30 |
31 | } 32 | /> 33 |

34 | 35 | API 36 | 37 |

38 | Coming soon.. 39 | 40 | ) 41 | } 42 | } 43 | 44 | export default SnackbarView 45 | -------------------------------------------------------------------------------- /example/src/pages/MenuView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, H4, H6 } from 'ui-neumorphism' 4 | 5 | // import { toggle, toggleLabel, switchApi } from '../docs/' 6 | 7 | import DocCard from '../containers/DocCard.jsx' 8 | // import ApiCard from '../containers/ApiCard.jsx' 9 | 10 | const url = 11 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/MenuView.jsx' 12 | class MenuView extends React.Component { 13 | render() { 14 | const { dark } = this.props 15 | return ( 16 | 17 |

18 | 19 | Menu 20 | 21 |

22 |
23 | The Menu component shows a menu at the position of the element used to 24 | activate it. 25 |
26 | 30 | Coming soon.. 31 |
32 | } 33 | /> 34 |

35 | 36 | API 37 | 38 |

39 | Coming soon.. 40 | 41 | ) 42 | } 43 | } 44 | 45 | export default MenuView 46 | -------------------------------------------------------------------------------- /src/util/react-helpers.js: -------------------------------------------------------------------------------- 1 | import { 2 | Children, 3 | cloneElement 4 | } from 'react' 5 | 6 | /** 7 | * Check if component is valid in library 8 | * @param {*} component 9 | */ 10 | export const isMyReactComponent = (component) => { 11 | let componentName = '' 12 | if (component && component.type && typeof component.type !== 'string') { 13 | componentName = component.type.displayName 14 | } 15 | return componentName && componentName.includes('Nu') 16 | } 17 | 18 | /** 19 | * Pass down given prop to all given children 20 | * @param {*} children 21 | * @param {*} props 22 | * @param {*} propName 23 | */ 24 | export const passDownProp = (children, props, propName) => { 25 | return Children.map(children, (child) => { 26 | if (isMyReactComponent(child)) { 27 | const newProps = { 28 | ...child.props 29 | } 30 | if (typeof propName === 'string') { 31 | newProps[propName] = child.props[propName] === undefined ? props[propName] : child.props[propName] 32 | } else if (Array.isArray(propName)) { 33 | propName.forEach(prop => { 34 | newProps[prop] = child.props[prop] === undefined ? props[prop] : child.props[prop] 35 | }) 36 | } 37 | return cloneElement(child, newProps) 38 | } else { 39 | return child 40 | } 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /example/src/pages/SelectView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, H4, H6 } from 'ui-neumorphism' 4 | 5 | // import { toggle, toggleLabel, switchApi } from '../docs/' 6 | 7 | import DocCard from '../containers/DocCard.jsx' 8 | // import ApiCard from '../containers/ApiCard.jsx' 9 | 10 | const url = 11 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/SelectView.jsx' 12 | class SelectView extends React.Component { 13 | render() { 14 | const { dark } = this.props 15 | return ( 16 | 17 |

18 | 19 | Select 20 | 21 |

22 |
23 | Select components are used for collecting user provided information 24 | from a list of options. 25 |
26 | 30 | Coming soon.. 31 |
32 | } 33 | /> 34 |

35 | 36 | API 37 | 38 |

39 | Coming soon.. 40 | 41 | ) 42 | } 43 | } 44 | 45 | export default SelectView 46 | -------------------------------------------------------------------------------- /example/src/docs/api/avatar-api.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createApiDoc, defaultApiDoc } from '../index.js' 3 | 4 | const attribute = (dark, attr) => 5 | createApiDoc( 6 | dark, 7 | attr, 8 | 'String', 9 | '', 10 | `The ${attr} attribute for the img element.` 11 | ) 12 | 13 | const variant = (dark, type) => 14 | createApiDoc( 15 | dark, 16 | type, 17 | 'Boolean', 18 | 'false', 19 | `Renders ${type} variant of avatar.` 20 | ) 21 | 22 | export const avatarApi = (dark) => { 23 | return [ 24 | ...defaultApiDoc(dark, true), 25 | attribute(dark, 'alt'), 26 | attribute(dark, 'src'), 27 | createApiDoc( 28 | dark, 29 | 'size', 30 | `'small' | 'medium' | 'large' | Number`, 31 | 'medium', 32 | 'The css color of the avatar.' 33 | ), 34 | createApiDoc( 35 | dark, 36 | 'color', 37 | 'String', 38 | --white, 39 | 'The css color of the avatar.' 40 | ), 41 | createApiDoc( 42 | dark, 43 | 'bgColor', 44 | 'String', 45 | --primary, 46 | 'The css background color of the avatar.' 47 | ), 48 | variant(dark, 'square'), 49 | variant(dark, 'rounded') 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /example/src/pages/FormView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { H4, H6, Subtitle1, Card } from 'ui-neumorphism' 4 | import DocCard from '../containers/DocCard.jsx' 5 | const url = 6 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/ProgressLinearView.jsx' 7 | 8 | class FormView extends React.Component { 9 | render() { 10 | const { dark } = this.props 11 | return ( 12 | 13 |

Forms

14 |
Forms are essential part of any application.
15 | 16 | The Formcomponent makes it easy to add validation to form 17 | inputs.
18 | All input components have a rules prop which takes an array of 19 | functions.
20 | These functions allow you to specify conditions in which the field is 21 | valid or invalid.
22 | Whenever the value of an input is changed, each function in the array 23 | will receive the new value.
24 | If a function returns false or a string, validation has failed. 25 |
26 | 31 |
32 | ) 33 | } 34 | } 35 | 36 | export default FormView 37 | -------------------------------------------------------------------------------- /src/components/input/Textarea.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { TextField } from '../../index' 4 | import { callCallback } from '../../util' 5 | 6 | class TextArea extends React.Component { 7 | static displayName = 'NuTextarea' 8 | 9 | constructor(props) { 10 | super(props) 11 | const { dense, height } = props 12 | const defaultHeight = dense ? 32 : 40 13 | this.minHeight = Math.max(height || 0, defaultHeight) 14 | } 15 | 16 | onInput(e, prop) { 17 | if (!this.props.autoExpand) return 18 | const textarea = e.target 19 | 20 | const outerHeight = parseInt(window.getComputedStyle(textarea).height, 10) 21 | const diff = outerHeight - textarea.clientHeight 22 | 23 | textarea.style.height = 0 24 | textarea.style.height = `${Math.max( 25 | this.minHeight, 26 | textarea.scrollHeight + diff 27 | )}px` 28 | 29 | callCallback(this.props[prop], e) 30 | } 31 | 32 | render() { 33 | const { autoExpand, inputStyles, ...others } = this.props 34 | return ( 35 | this.onInput(e, 'onInput')} 38 | onKeyDown={(e) => this.onInput(e, 'onKeyDown')} 39 | inputStyles={{ resize: autoExpand ? 'none' : null, ...inputStyles }} 40 | {...others} 41 | /> 42 | ) 43 | } 44 | } 45 | 46 | export default TextArea 47 | -------------------------------------------------------------------------------- /example/src/pages/PaginationView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, H4, H6 } from 'ui-neumorphism' 4 | 5 | // import { toggle, toggleLabel, switchApi } from '../docs/' 6 | 7 | import DocCard from '../containers/DocCard.jsx' 8 | // import ApiCard from '../containers/ApiCard.jsx' 9 | 10 | const url = 11 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/PaginationView.jsx' 12 | class PaginationView extends React.Component { 13 | render() { 14 | const { dark } = this.props 15 | return ( 16 | 17 |

18 | 19 | Pagination 20 | 21 |

22 |
23 | The Pagination component is used to separate long sets of data so that it is 24 | easier for a user to consume information. 25 |
26 | 30 | Coming soon.. 31 |
32 | } 33 | /> 34 |

35 | 36 | API 37 | 38 |

39 | Coming soon.. 40 | 41 | ) 42 | } 43 | } 44 | 45 | export default PaginationView 46 | -------------------------------------------------------------------------------- /example/src/pages/ExpansionPanelView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, H4, H6 } from 'ui-neumorphism' 4 | 5 | // import { toggle, toggleLabel, switchApi } from '../docs/' 6 | 7 | import DocCard from '../containers/DocCard.jsx' 8 | // import ApiCard from '../containers/ApiCard.jsx' 9 | 10 | const url = 11 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/ExpansionPanelView.jsx' 12 | class ExpansionPanelView extends React.Component { 13 | render() { 14 | const { dark } = this.props 15 | return ( 16 | 17 |

18 | 19 | ExpansionPanel 20 | 21 |

22 |
23 | The ExpansionPanel component is used to segment content and show/hide 24 | when clicked, reducing vertical space with large amounts of 25 | information. 26 |
27 | 31 | Coming soon.. 32 |
33 | } 34 | /> 35 |

36 | 37 | API 38 | 39 |

40 | Coming soon.. 41 | 42 | ) 43 | } 44 | } 45 | 46 | export default ExpansionPanelView 47 | -------------------------------------------------------------------------------- /src/transitions/Fade.jsx: -------------------------------------------------------------------------------- 1 | import React, { cloneElement } from 'react' 2 | 3 | import TransitionWrapper from './TransitionWrapper' 4 | 5 | import { G_NUM } from '../assets' 6 | 7 | class Fade extends React.Component { 8 | static displayName = 'NuFade' 9 | 10 | static defaultProps = { 11 | duration: 200 12 | } 13 | 14 | static propTypes = { 15 | duration: G_NUM 16 | } 17 | 18 | defaultStyle = { 19 | opacity: 0, 20 | transition: `opacity ${this.props.duration}ms ease-in-out` 21 | } 22 | 23 | transitionStyles = { 24 | entering: { opacity: 1 }, 25 | entered: { opacity: 1 }, 26 | exiting: { opacity: 0 }, 27 | exited: { opacity: 0 } 28 | } 29 | 30 | constructor(props) { 31 | super(props) 32 | this.state = { status: '' } 33 | this.updateStatus = this.updateStatus.bind(this) 34 | } 35 | 36 | updateStatus(status) { 37 | this.setState({ status }) 38 | } 39 | 40 | render() { 41 | const { status } = this.state 42 | const { children: child, ...otherProps } = this.props 43 | return ( 44 | 45 | {cloneElement(child, { 46 | style: { 47 | ...this.defaultStyle, 48 | ...this.transitionStyles[status], 49 | ...child.props.style 50 | } 51 | })} 52 | 53 | ) 54 | } 55 | } 56 | 57 | export default Fade 58 | -------------------------------------------------------------------------------- /example/src/docs/api/table-api.js: -------------------------------------------------------------------------------- 1 | import { createApiDoc, defaultApiDoc } from '../index.js' 2 | 3 | const headerExample = `{ 4 | text: String, 5 | value: String, 6 | className?: String, 7 | verticalAlign?: 'top' | 'middle' | 'bottom', 8 | align?: 'inherit' | 'center' | 'left' | 'right' | 'justify', 9 | }` 10 | 11 | export const tableApi = (dark) => { 12 | return [ 13 | ...defaultApiDoc(dark), 14 | createApiDoc( 15 | dark, 16 | 'headers', 17 | 'Array', 18 | '[]', 19 | 'An array of objects that each describe a header column.', 20 | 'Header object definition', 21 | headerExample 22 | ), 23 | createApiDoc( 24 | dark, 25 | 'items', 26 | 'Array', 27 | '[]', 28 | 'The array of items to display.' 29 | ), 30 | createApiDoc(dark, 'flat', 'Boolean', 'false', 'Removes elevation.'), 31 | createApiDoc(dark, 'inset', 'Boolean', 'false', 'Reverses elevation.'), 32 | createApiDoc( 33 | dark, 34 | 'outlined', 35 | 'Boolean', 36 | 'false', 37 | 'Removes elevation and adds a border.' 38 | ), 39 | createApiDoc( 40 | dark, 41 | 'dense', 42 | 'Boolean', 43 | 'false', 44 | 'Decreases the height of rows, for an alternate style.' 45 | ), 46 | createApiDoc( 47 | dark, 48 | 'noHeaders', 49 | 'Boolean', 50 | 'false', 51 | 'Removes the header of the table.' 52 | ) 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /example/src/containers/DocCard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card } from 'ui-neumorphism' 4 | import CodeBlock from '../containers/CodeBlock.jsx' 5 | 6 | class DocCard extends React.Component { 7 | static displayName = 'NuDocCard' 8 | 9 | state = { 10 | darkTheme: this.props.dark 11 | } 12 | 13 | handleTheme(e) { 14 | this.setState({ darkTheme: !this.state.darkTheme }) 15 | } 16 | 17 | render() { 18 | const { 19 | url, 20 | code, 21 | dark, 22 | style, 23 | title, 24 | content, 25 | subtitle, 26 | className 27 | } = this.props 28 | const { darkTheme } = this.state 29 | const localDark = darkTheme === undefined ? false : true 30 | return ( 31 | 32 | {title} 33 | {subtitle} 34 | 35 | 36 | {content} 37 | 38 | 43 | {code 44 | ? code[0](localDark ? darkTheme : code[1], ...(code[2] || [])) 45 | : null} 46 | 47 | 48 | 49 | ) 50 | } 51 | } 52 | 53 | export default DocCard 54 | -------------------------------------------------------------------------------- /example/src/docs/api/alert-api.js: -------------------------------------------------------------------------------- 1 | import { cardApi } from '../index' 2 | import { createApiDoc } from '../index.js' 3 | 4 | export const alertApi = (dark) => { 5 | return [ 6 | ...cardApi(dark, 'alert').filter( 7 | (d) => !'disabledloading'.includes(d.title.toLowerCase()) 8 | ), 9 | createApiDoc( 10 | dark, 11 | 'dense', 12 | 'Boolean', 13 | 'false', 14 | "Hides the alert icon and decreases alerts's height." 15 | ), 16 | createApiDoc( 17 | dark, 18 | 'closable', 19 | 'Boolean', 20 | 'false', 21 | 'Adds a close icon that can hide the alert.' 22 | ), 23 | createApiDoc( 24 | dark, 25 | 'icon', 26 | 'Node', 27 | '', 28 | 'Designates a specific icon to the alert.' 29 | ), 30 | createApiDoc( 31 | dark, 32 | 'closeIcon', 33 | 'Node', 34 | '', 35 | 'Override the default icon used for closable alerts.' 36 | ), 37 | createApiDoc( 38 | dark, 39 | 'type', 40 | 'String', 41 | "'success' | 'info' | 'warning' | 'error'", 42 | 'Specify a success, info, warning or error alert.' 43 | ), 44 | createApiDoc( 45 | dark, 46 | 'color', 47 | 'String', 48 | '', 49 | 'Applies specified color to the alert component.' 50 | ), 51 | createApiDoc( 52 | dark, 53 | 'visible', 54 | 'Boolean', 55 | 'false', 56 | 'Controls whether the alert is visible or hidden.' 57 | ) 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /example/src/pages/SliderView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, H4, H6, Subtitle1 } from 'ui-neumorphism' 4 | 5 | // import { toggle, toggleLabel, switchApi } from '../docs/' 6 | 7 | import DocCard from '../containers/DocCard.jsx' 8 | // import ApiCard from '../containers/ApiCard.jsx' 9 | 10 | const url = 11 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/SliderView.jsx' 12 | class SliderView extends React.Component { 13 | render() { 14 | const { dark } = this.props 15 | return ( 16 | 17 |

18 | 19 | Slider 20 | 21 |

22 |
Sliders allow users to make selections from a range of values.
23 | 24 | Sliders reflect a range of values along a bar, from which users may 25 | select a single value. They are ideal for adjusting settings such as 26 | volume, brightness, or applying image filters. 27 | 28 | 32 | Coming soon.. 33 |
34 | } 35 | /> 36 |

37 | 38 | API 39 | 40 |

41 | Coming soon.. 42 | 43 | ) 44 | } 45 | } 46 | 47 | export default SliderView 48 | -------------------------------------------------------------------------------- /src/components/button-fab/Fab.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Button } from '../index' 4 | 5 | import styles from './Fab.module.css' 6 | import { getModuleClasses } from '../../util' 7 | import { FAB_BUTTON_PROP_TYPES, DEFAULT_PROPS } from '../../assets/index' 8 | 9 | class Fab extends React.Component { 10 | static displayName = 'NuFab' 11 | 12 | static defaultProps = { 13 | animation: true, 14 | ...DEFAULT_PROPS 15 | } 16 | 17 | static propTypes = FAB_BUTTON_PROP_TYPES 18 | 19 | getClasses() { 20 | const { fixed, top, right, bottom, left, absolute, animation } = this.props 21 | return getModuleClasses( 22 | styles, 23 | ` 24 | nu-fab 25 | ${top ? 'nu-fab--top' : ''} 26 | ${left ? 'nu-fab--left' : ''} 27 | ${right ? 'nu-fab--right' : ''} 28 | ${bottom ? 'nu-fab--bottom' : ''} 29 | ${fixed ? 'nu-fab--fixed' : ''} 30 | ${absolute ? 'nu-fab--absolute' : ''} 31 | ${animation ? 'nu-fab--animation' : ''} 32 | ` 33 | ) 34 | } 35 | 36 | render() { 37 | const { children, style, className, ...otherProps } = this.props 38 | return ( 39 |
40 | 51 |
52 | ) 53 | } 54 | } 55 | 56 | export default Fab 57 | -------------------------------------------------------------------------------- /src/components/divider/Divider.module.css: -------------------------------------------------------------------------------- 1 | .nu-divider { 2 | border: 0; 3 | height: 7px; 4 | border-radius: 10px; 5 | background: var(--bg-color); 6 | box-shadow: var(--box-shadow-inset); 7 | } 8 | 9 | .nu-divider.nu-divider--light { 10 | --bg-color: var(--light-bg); 11 | --box-shadow-inset: inset -3px -3px 5px var(--light-bg-light-shadow), 12 | inset 3px 3px 5px var(--light-bg-dark-shadow); 13 | --box-shadow-inset-dense: inset -1px -1px 3px var(--light-bg-light-shadow), 14 | inset 1px 1px 3px var(--light-bg-dark-shadow); 15 | --box-shadow: -2px -2px 5px var(--light-bg-light-shadow), 16 | 2px 2px 5px var(--light-bg-dark-shadow); 17 | --box-shadow-dense: -1px -1px 3px var(--light-bg-light-shadow), 18 | 1px 1px 3px var(--light-bg-dark-shadow); 19 | } 20 | 21 | .nu-divider.nu-divider--dark { 22 | --bg-color: var(--dark-bg); 23 | --box-shadow-inset: inset -3px -3px 5px var(--dark-bg-light-shadow), 24 | inset 3px 3px 5px var(--dark-bg-dark-shadow); 25 | --box-shadow-inset-dense: inset -1px -1px 3px var(--dark-bg-light-shadow), 26 | inset 1px 1px 3px var(--dark-bg-dark-shadow); 27 | --box-shadow: -2px -2px 5px var(--dark-bg-light-shadow), 28 | 2px 2px 5px var(--dark-bg-dark-shadow); 29 | --box-shadow-dense: -1px -1px 3px var(--dark-bg-light-shadow), 30 | 1px 1px 3px var(--dark-bg-dark-shadow); 31 | } 32 | 33 | .nu-divider.nu-divider--dense { 34 | height: 5px; 35 | box-shadow: var(--box-shadow-inset-dense); 36 | } 37 | 38 | .nu-divider.nu-divider--elevated { 39 | height: 4px; 40 | box-shadow: var(--box-shadow); 41 | } 42 | 43 | .nu-divider.nu-divider--dense.nu-divider--elevated { 44 | height: 3px; 45 | box-shadow: var(--box-shadow-dense); 46 | } 47 | -------------------------------------------------------------------------------- /src/index.test.js: -------------------------------------------------------------------------------- 1 | import { 2 | Typography, 3 | Subtitle2, 4 | Subtitle1, 5 | Overline, 6 | Caption, 7 | Body2, 8 | Body1, 9 | H6, 10 | H5, 11 | H4, 12 | H3, 13 | H2, 14 | H1 15 | } from '.' 16 | 17 | describe('Typography', () => { 18 | it('is truthy', () => { 19 | expect(Typography).toBeTruthy() 20 | }) 21 | }) 22 | 23 | describe('Subtitle2', () => { 24 | it('is truthy', () => { 25 | expect(Subtitle2).toBeTruthy() 26 | }) 27 | }) 28 | 29 | describe('Subtitle1', () => { 30 | it('is truthy', () => { 31 | expect(Subtitle1).toBeTruthy() 32 | }) 33 | }) 34 | 35 | describe('Overline', () => { 36 | it('is truthy', () => { 37 | expect(Overline).toBeTruthy() 38 | }) 39 | }) 40 | 41 | describe('Caption', () => { 42 | it('is truthy', () => { 43 | expect(Caption).toBeTruthy() 44 | }) 45 | }) 46 | 47 | describe('Body1', () => { 48 | it('is truthy', () => { 49 | expect(Body1).toBeTruthy() 50 | }) 51 | }) 52 | 53 | describe('Body2', () => { 54 | it('is truthy', () => { 55 | expect(Body2).toBeTruthy() 56 | }) 57 | }) 58 | 59 | describe('H6', () => { 60 | it('is truthy', () => { 61 | expect(H6).toBeTruthy() 62 | }) 63 | }) 64 | 65 | describe('H5', () => { 66 | it('is truthy', () => { 67 | expect(H5).toBeTruthy() 68 | }) 69 | }) 70 | 71 | describe('H4', () => { 72 | it('is truthy', () => { 73 | expect(H4).toBeTruthy() 74 | }) 75 | }) 76 | 77 | describe('H3', () => { 78 | it('is truthy', () => { 79 | expect(H3).toBeTruthy() 80 | }) 81 | }) 82 | 83 | describe('H2', () => { 84 | it('is truthy', () => { 85 | expect(H2).toBeTruthy() 86 | }) 87 | }) 88 | 89 | describe('H1', () => { 90 | it('is truthy', () => { 91 | expect(H1).toBeTruthy() 92 | }) 93 | }) 94 | -------------------------------------------------------------------------------- /src/components/typography/Typography.jsx: -------------------------------------------------------------------------------- 1 | import React, { createElement } from 'react' 2 | 3 | import styles from './Typography.module.css' 4 | import { getModuleClasses } from '../../util' 5 | import { 6 | G_STRING, 7 | DEFAULT_PROPS, 8 | TYPOGRAPHY_PROP_TYPES 9 | } from '../../assets/index' 10 | 11 | class Typography extends React.Component { 12 | static displayName = 'NuTypography' 13 | 14 | static defaultProps = DEFAULT_PROPS 15 | 16 | mapping = { 17 | h1: 'h1', 18 | h2: 'h2', 19 | h3: 'h3', 20 | h4: 'h4', 21 | h5: 'h5', 22 | h6: 'h6', 23 | caption: 'p', 24 | overline: 'p', 25 | 'subtitle-1': 'p', 26 | 'subtitle-2': 'p', 27 | 'body-1': 'p', 28 | 'body-2': 'p' 29 | } 30 | 31 | static propTypes = { 32 | type: G_STRING, 33 | ...TYPOGRAPHY_PROP_TYPES 34 | } 35 | 36 | getTypographyType() { 37 | const { disabled, secondary } = this.props 38 | return disabled ? 'disabled' : secondary ? 'secondary' : 'primary' 39 | } 40 | 41 | getMapping() { 42 | const { type, component } = this.props 43 | return component || this.mapping[type || 'body-1'] 44 | } 45 | 46 | getClass() { 47 | const { dark, type } = this.props 48 | return getModuleClasses( 49 | styles, 50 | ` 51 | nu-typography 52 | nu-${type || 'body-1'} 53 | nu-typography--${this.getTypographyType()} 54 | nu-typography--${dark ? 'dark' : 'light'} 55 | ` 56 | ) 57 | } 58 | 59 | render() { 60 | const { style, className } = this.props 61 | return createElement( 62 | this.getMapping(), 63 | { 64 | style, 65 | className: `${this.getClass()} ${className}` 66 | }, 67 | this.props.children 68 | ) 69 | } 70 | } 71 | 72 | export default Typography 73 | -------------------------------------------------------------------------------- /example/src/docs/code/progress-code.js: -------------------------------------------------------------------------------- 1 | export const progressLinear = (dark, prop, hideColor = false) => { 2 | const darkProp = dark ? ' dark' : ''; 3 | const propType = prop || ['', '', '']; 4 | return ` 5 | 6 | 7 | ` 8 | } 9 | 10 | export const progressCircular = (dark, prop, hideColor = false) => { 11 | const darkProp = dark ? ' dark' : ''; 12 | const propType = prop || ['', '', '', '', '']; 13 | return ` 14 | 15 | 16 | 17 | 18 | ` 19 | } 20 | 21 | export const progressCircularLabel = (dark) => { 22 | const darkProp = dark ? ' dark' : '' 23 | return ` 24 | // Icon component is from '@mdi/react' and is not bundled with this library 25 | 26 | 27 | 28 | 60 29 | 30 | 100` 31 | } 32 | -------------------------------------------------------------------------------- /src/transitions/Grow.jsx: -------------------------------------------------------------------------------- 1 | import React, { cloneElement } from 'react' 2 | 3 | import TransitionWrapper from './TransitionWrapper' 4 | 5 | import { G_NUM, G_STRING } from '../assets' 6 | 7 | class Grow extends React.Component { 8 | static displayName = 'NuGrow' 9 | 10 | static defaultProps = { 11 | duration: 200, 12 | origin: 'center center' 13 | } 14 | 15 | static propTypes = { 16 | duration: G_NUM, 17 | origin: G_STRING 18 | } 19 | 20 | constructor(props) { 21 | super(props) 22 | this.state = { status: '' } 23 | this.updateStatus = this.updateStatus.bind(this) 24 | } 25 | 26 | get transition() { 27 | return { transition: `all ${this.props.duration}ms ease-in-out` } 28 | } 29 | 30 | get transitionStyles() { 31 | return { 32 | entering: { opacity: 1, transform: 'scale(0)', visibility: 'visible' }, 33 | entered: { opacity: 1, transform: 'scale(1.0)', ...this.transition }, 34 | exiting: { opacity: 0, transform: 'scale(0)', ...this.transition }, 35 | exited: { opacity: 0, visibility: 'hidden' } 36 | } 37 | } 38 | 39 | updateStatus(status) { 40 | this.setState({ status }) 41 | } 42 | 43 | render() { 44 | const { status } = this.state 45 | const { origin, duration, children: child, ...otherProps } = this.props 46 | return ( 47 | 52 | {cloneElement(child, { 53 | style: { 54 | opacity: 0, 55 | transformOrigin: origin, 56 | ...this.transitionStyles[status], 57 | ...child.props.style 58 | } 59 | })} 60 | 61 | ) 62 | } 63 | } 64 | 65 | export default Grow 66 | -------------------------------------------------------------------------------- /example/src/pages/DividerView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Divider, Body2, Card, H6, H4 } from 'ui-neumorphism' 4 | 5 | import { divider, dividerApi } from '../docs/' 6 | import DocCard from '../containers/DocCard.jsx' 7 | import ApiCard from '../containers/ApiCard.jsx' 8 | const url = 9 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/DividerView.jsx' 10 | class DividerView extends React.Component { 11 | render() { 12 | const { dark } = this.props 13 | return ( 14 | 15 |

Divider

16 |
A divider is a line that separates content into clear groups.
17 | 21 | 22 |
23 | Default 24 |
25 |
26 | 27 |
28 | Dense 29 |
30 |
31 | 32 |
33 | Elevated 34 |
35 |
36 | 37 |
38 |
39 | Dense & Elevated 40 |
41 | } 42 | code={[divider, dark]} 43 | /> 44 | 45 |

46 | 47 | API 48 | 49 |

50 | 51 | 52 | ) 53 | } 54 | } 55 | 56 | export default DividerView 57 | -------------------------------------------------------------------------------- /src/hocs/withImage.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const withImage = (WrappedComponent, config = {}) => { 4 | return class withImage extends React.Component { 5 | image 6 | 7 | static displayName = `WithImage(${ 8 | WrappedComponent.displayName || WrappedComponent.name || 'Component' 9 | })` 10 | 11 | constructor(props) { 12 | super(props) 13 | this.state = { 14 | loaded: false, 15 | height: 0, 16 | width: 0 17 | } 18 | } 19 | 20 | setLoaded() { 21 | const { src } = this.props 22 | if (!src) { 23 | return null 24 | } 25 | // eslint-disable-next-line no-undef 26 | this.image = new Image() 27 | this.image.src = src 28 | this.image.onload = () => { 29 | const { width, height } = this.image 30 | this.setState((state) => ({ ...state, width, height, loaded: true })) 31 | } 32 | this.image.onerror = () => { 33 | this.setState((state) => ({ 34 | ...state, 35 | width: 0, 36 | height: 0, 37 | loaded: false 38 | })) 39 | } 40 | } 41 | 42 | componentWillMount() { 43 | this.setLoaded() 44 | } 45 | 46 | componentDidUpdate({ src }) { 47 | if (this.props.src !== src) { 48 | this.setLoaded() 49 | } 50 | } 51 | 52 | componentWillUnmount() { 53 | if (this.image) { 54 | this.image.onerror = null 55 | this.image.onload = null 56 | } 57 | } 58 | 59 | render() { 60 | const { loaded, width, height } = this.state 61 | return ( 62 | 68 | ) 69 | } 70 | } 71 | } 72 | 73 | export default withImage 74 | -------------------------------------------------------------------------------- /src/transitions/TransitionWrapper.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Transition } from 'react-transition-group' 3 | 4 | import { callCallback } from '../util' 5 | 6 | class TransitionWrapper extends React.Component { 7 | static displayName = 'NuTransitionWrapper' 8 | 9 | static defaultProps = { 10 | timeout: 0 11 | } 12 | 13 | constructor(props) { 14 | super(props) 15 | this.state = { updated: 0 } 16 | this.handleExit = this.handleExit.bind(this) 17 | this.handleEnter = this.handleEnter.bind(this) 18 | this.handleExited = this.handleExited.bind(this) 19 | this.handleExiting = this.handleExiting.bind(this) 20 | this.handleEntered = this.handleEntered.bind(this) 21 | this.handleEntering = this.handleEntering.bind(this) 22 | } 23 | 24 | update(data) { 25 | callCallback(this.props.onUpdate, data) 26 | } 27 | 28 | handleExit() { 29 | this.update('exit') 30 | } 31 | 32 | handleEnter() { 33 | this.update('enter') 34 | } 35 | 36 | handleExited() { 37 | this.update('exited') 38 | } 39 | 40 | handleExiting() { 41 | this.update('exiting') 42 | } 43 | 44 | handleEntered() { 45 | this.update('entered') 46 | } 47 | 48 | handleEntering() { 49 | this.update('entering') 50 | } 51 | 52 | componentDidMount() { 53 | this.setState({ updated: 1 }) 54 | } 55 | 56 | render() { 57 | const { children, onUpdate, ...otherProps } = this.props 58 | return ( 59 | 68 | {children} 69 | 70 | ) 71 | } 72 | } 73 | 74 | export default TransitionWrapper 75 | -------------------------------------------------------------------------------- /src/components/card/CardMedia.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { H6 } from '../../index' 4 | import styles from './Card.module.css' 5 | import { getModuleClasses } from '../../util' 6 | import { 7 | DEFAULT_PROPS_TYPE, 8 | DEFAULT_PROPS, 9 | G_STRING, 10 | G_BOOL, 11 | G_NUM 12 | } from '../../assets/index' 13 | 14 | class CardMedia extends React.Component { 15 | static displayName = 'NuCardMedia' 16 | 17 | static defaultProps = { 18 | height: 160, 19 | ...DEFAULT_PROPS 20 | } 21 | 22 | static propTypes = { 23 | height: G_NUM, 24 | src: G_STRING, 25 | title: G_STRING, 26 | rounded: G_BOOL, 27 | disabled: G_BOOL, 28 | ...DEFAULT_PROPS_TYPE 29 | } 30 | 31 | getClass(classType) { 32 | const { dark, rounded, disabled } = this.props 33 | switch (classType) { 34 | case 'media': 35 | return getModuleClasses( 36 | styles, 37 | ` 38 | nu-card-media 39 | nu-card-media--${dark ? 'dark' : 'light'} 40 | ${rounded ? 'nu-card-media--rounded' : ''} 41 | ${disabled ? 'nu-card-media--disabled' : ''} 42 | ` 43 | ) 44 | case 'title': 45 | return getModuleClasses(styles, 'nu-card-media-title') 46 | } 47 | } 48 | 49 | render() { 50 | const { src, dark, title, height, style, className } = this.props 51 | return ( 52 |
61 | {title ? ( 62 |
63 | {title} 64 |
65 | ) : null} 66 |
67 | ) 68 | } 69 | } 70 | 71 | export default CardMedia 72 | -------------------------------------------------------------------------------- /src/hocs/withClickOutside.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { findDOMNode } from 'react-dom' 3 | 4 | import { findClickInside } from '../util/' 5 | 6 | const withClickOutside = (WrappedComponent) => { 7 | const componentName = 8 | WrappedComponent.displayName || WrappedComponent.name || 'Component' 9 | return class WithClickOutside extends React.Component { 10 | static displayName = `WithClickOutside(${componentName})` 11 | 12 | constructor(props) { 13 | super(props) 14 | this.node = null 15 | this.handleClick = this.handleClick.bind(this) 16 | } 17 | 18 | componentDidMount() { 19 | document.addEventListener('click', this.handleClick) 20 | } 21 | 22 | componentWillUnmount() { 23 | document.removeEventListener('click', this.handleClick) 24 | } 25 | 26 | handleClick = (e) => { 27 | const parentNode = findDOMNode(this.node) 28 | const isClickInside = findClickInside(e, parentNode) 29 | if (isClickInside) { 30 | this.clickHandler(e, 'Inside') 31 | } else { 32 | this.clickHandler(e, 'Outside') 33 | } 34 | } 35 | 36 | clickHandler(e, type = 'Outside') { 37 | if (typeof this.node.props[`handleClick${type}`] === 'function') { 38 | this.node.props[`handleClick${type}`](e) 39 | return 40 | } 41 | 42 | if (typeof this.node[`handleClick${type}`] === 'function') { 43 | this.node[`handleClick${type}`](e) 44 | return 45 | } 46 | if (type === 'Outside') { 47 | throw new Error( 48 | `${componentName}: needs a handleClickOutside function to handle outside clicks` 49 | ) 50 | } 51 | } 52 | 53 | render() { 54 | return ( 55 | (this.node = ref)} {...this.props} /> 56 | ) 57 | } 58 | } 59 | } 60 | 61 | export default withClickOutside 62 | -------------------------------------------------------------------------------- /src/components/tab/Tab.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Button } from '../../index' 4 | 5 | import styles from './Tab.module.css' 6 | 7 | import { DEFAULT_PROPS, DEFAULT_PROPS_TYPE } from '../../assets/index' 8 | import { getModuleClasses, callCallback, pickKeys } from '../../util' 9 | 10 | class Tab extends React.Component { 11 | static displayName = 'NuTab' 12 | 13 | static defaultProps = DEFAULT_PROPS 14 | 15 | static propTypes = DEFAULT_PROPS_TYPE 16 | 17 | constructor(props) { 18 | super(props) 19 | this.state = { color: '' } 20 | } 21 | 22 | get color() { 23 | const { color } = this.state 24 | const { active, color: propColor } = this.props 25 | return active ? propColor : color 26 | } 27 | 28 | getClasses(elem) { 29 | const { dark } = this.props 30 | if (elem === 'tab') { 31 | return getModuleClasses( 32 | styles, 33 | ` 34 | nu-tab 35 | nu-tab--${dark ? 'dark' : 'light'} 36 | ` 37 | ) 38 | } else { 39 | return getModuleClasses(styles, elem) 40 | } 41 | } 42 | 43 | handleMouseOut(e) { 44 | this.setState({ color: '' }) 45 | callCallback(this.props.onMouseOut, e) 46 | } 47 | 48 | handleMouseOver(e) { 49 | this.setState({ color: this.props.color }) 50 | callCallback(this.props.onMouseOver, e) 51 | } 52 | 53 | render() { 54 | const { style, className, children } = this.props 55 | const pickedProps = pickKeys(this.props, ['dark', 'onClick', 'disabled']) 56 | return ( 57 | 69 | ) 70 | } 71 | } 72 | 73 | export default Tab 74 | -------------------------------------------------------------------------------- /example/src/docs/code/carousel-code.js: -------------------------------------------------------------------------------- 1 | export const simpleCarousel = (dark, type) => { 2 | const darkProp = dark ? ' dark' : '' 3 | const typeProp = type ? ' ' + type : '' 4 | return ` 5 | ${['info', 'error', 'success', 'warning'] 6 | .map( 7 | ( 8 | color, 9 | index 10 | ) => ` 11 |

Slide ${index + 1}

12 |
` 13 | ) 14 | .join('\n')} 15 | ` 16 | } 17 | 18 | export const customCarousel = (dark) => { 19 | const darkProp = dark ? '\n dark' : '' 20 | return `// Icon component is from '@mdi/react' and is not bundled with this library 21 | 30 | } 31 | delimiterIcon={ 32 | 37 | } 38 | > 39 | ${['info', 'error', 'success', 'warning'] 40 | .map( 41 | ( 42 | color, 43 | index 44 | ) => ` 45 |

Slide ${index + 1}

46 |
` 47 | ) 48 | .join('\n')} 49 | ` 50 | } 51 | export const customArrows = (dark) => { 52 | const darkProp = dark ? '\n dark' : '' 53 | return `// Icon component is from '@mdi/react' and is not bundled with this library 54 | } 57 | prevIcon={} 58 | > 59 | ${['info', 'error', 'success', 'warning'] 60 | .map( 61 | ( 62 | color, 63 | index 64 | ) => ` 65 |

Slide ${index + 1}

66 |
` 67 | ) 68 | .join('\n')} 69 | ` 70 | } 71 | -------------------------------------------------------------------------------- /example/src/pages/TextareaView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, H4, H6, TextArea } from 'ui-neumorphism' 4 | 5 | import { textAreaApi } from '../docs/' 6 | 7 | import DocCard from '../containers/DocCard.jsx' 8 | import ApiCard from '../containers/ApiCard.jsx' 9 | 10 | const url = 11 | 'https://github.com/AKAspanion/ui-neumorphism/blob/master/example/src/pages/TextareaView.jsx' 12 | class TextareaView extends React.Component { 13 | render() { 14 | const { dark } = this.props 15 | return ( 16 | 17 |

18 | 19 | TextArea 20 | 21 |

22 |
23 | The TextArea component is used for collecting large amounts of textual 24 | data. 25 |
26 | 30 |