diff --git a/README.md b/README.md index 8b57a85..3eafb76 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,17 @@ npm install react-popover-control ```javascript import Popover from 'react-popover-control'; -actions = [ +const actions = [ { title: 'Edit', - func: () => { - ... + func() { + // some action here } }, { title: 'Delete', - func: () => { - ... + func() { + // some action here } } ]; @@ -31,23 +31,21 @@ actions = [ class Page extends React.Component { render() { return ( - - Click Here - +
+ Some component... + + + Click Here + +
) } -} +}; ``` ## Styling -Default styles are included in `css/ReactPopoverControl.scss`. - -If you are using webpack with sass-loader, you can load the style in like this: - -```javascript -require('react-popover-control/css/ReactPopoverControl.scss') -``` +Default styles are included as jss, but you can opt out by... (TODO) ## A good popover... @@ -61,4 +59,4 @@ require('react-popover-control/css/ReactPopoverControl.scss') - Arrow key control - Scrolling when there are too many items - Using keyboard letters as shortcuts to certain fields -- Filtering items with an input field \ No newline at end of file +- Filtering items with an input field diff --git a/css/ReactPopoverControl.scss b/css/ReactPopoverControl.scss deleted file mode 100644 index a5a7a04..0000000 --- a/css/ReactPopoverControl.scss +++ /dev/null @@ -1,21 +0,0 @@ -.ReactPopoverList { - background-color: white; - min-width: 150px; - overflow: hidden; - box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.25); - border-radius: 5px; - - a { - display: block; - height: 40px; - line-height: 40px; - padding: 0 10px; - color: #1A2D36; - - &:hover { - text-decoration: none; - color: #1A2D36; - background-color: #e1f0f7; - } - } -} \ No newline at end of file diff --git a/package.json b/package.json index 028d57c..79d7ecd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-popover-control", - "version": "0.1.1", + "version": "0.1.4", "description": "A popover control for React", "repository": { "type": "git", @@ -15,8 +15,15 @@ ], "main": "lib/index.js", "dependencies": { + "classnames": "^2.1.3", + "jss": "^2.1.2", + "jss-camel-case": "^0.1.2", + "jss-nested": "^0.1.8", + "jss-px": "^0.1.3", + "jss-vendor-prefixer": "^0.2.2", "keycode": "^2.1.0", - "lodash": "^3.8.0" + "lodash": "^3.8.0", + "react-jss": "^1.0.4" }, "peerDependencies": { "react": "^0.13.2", diff --git a/site/package.json b/site/package.json index 8bd0360..463b4a9 100644 --- a/site/package.json +++ b/site/package.json @@ -2,13 +2,15 @@ "description": "A simple, idiomatic popover control for React", "scripts": { "start": "NODE_ENV=development webpack-dev-server --progress", + "build-dev": "NODE_ENV=development webpack --progress", "build-prod": "NODE_ENV=production webpack -p --progress" }, "dependencies": { "active-event-stack": "^1.0.0", "react": "^0.13.3", - "react-popover-control": "^0.1.0", - "react-router": "^0.13.3" + "react-popover-control": "^0.1.1", + "react-router": "^0.13.3", + "source-map-support": "^0.3.2" }, "devDependencies": { "autoprefixer-core": "^5.2.1", diff --git a/site/src/js/index.js b/site/src/js/index.js index c0bb26a..1233270 100644 --- a/site/src/js/index.js +++ b/site/src/js/index.js @@ -5,6 +5,8 @@ import routes from './routes'; require('../css/reset.scss'); export default function(path, props, done) { + console.log(typeof global); + Router.run(routes, path, Handler => { done( '' + @@ -17,4 +19,4 @@ if (typeof document != 'undefined') { Router.run(routes, Router.HashLocation, Handler => { React.render(, document); }); -} \ No newline at end of file +} diff --git a/site/src/js/pages/HomePage.js b/site/src/js/pages/HomePage.js index 0f34d7d..ac86fb5 100644 --- a/site/src/js/pages/HomePage.js +++ b/site/src/js/pages/HomePage.js @@ -6,7 +6,7 @@ import marked from 'marked'; import customMarkedRenderer from '../customMarkedRenderer'; import Popover from 'react-popover-control'; -require('react-popover-control/css/ReactPopoverControl.scss'); + require('../../css/HomePage.scss') const HomePageMarkdown = require('../markdown/HomePage.md'); @@ -30,7 +30,7 @@ export default class HomePage extends React.Component { render() { return (
- @@ -57,4 +57,4 @@ export default class HomePage extends React.Component {
) } -} \ No newline at end of file +} diff --git a/site/webpack.config.js b/site/webpack.config.js index fd3ea92..97a31d8 100644 --- a/site/webpack.config.js +++ b/site/webpack.config.js @@ -1,3 +1,5 @@ +var path = require('path'); + var ExtractTextPlugin = require('extract-text-webpack-plugin'); var StaticRenderWebpackPlugin = require('static-render-webpack-plugin'); var webpack = require('webpack'); @@ -27,15 +29,23 @@ module.exports = { {test: /\.md$/, loader: 'raw'} ] }, + resolveLoader: { + alias: { + babel: __dirname + '/node_modules/babel-loader' + } + }, resolve: { alias: { + 'react-popover-control$': path.join(__dirname, '../src/index.js'), react: __dirname + '/node_modules/react' } }, devServer: { - port: 9000 + port: 9000, + contentBase: './build' }, - devtool: IS_DEV ? 'cheap-module-source-map' : undefined, + devtool: 'sourcemap', + // devtool: IS_DEV ? 'cheap-module-source-map' : undefined, postcss: function() { return [autoprefixer]; }, @@ -44,4 +54,4 @@ module.exports = { new ExtractTextPlugin('style.css'), new StaticRenderWebpackPlugin('bundle.js', routes) ] -} \ No newline at end of file +} diff --git a/src/index.js b/src/index.js index 091f006..e22008d 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,14 @@ import React, {PropTypes} from 'react'; import {debounce, map} from 'lodash'; import keycode from 'keycode'; import EventStack from 'active-event-stack'; +import classNames from 'classnames'; + +let useSheet; +if (typeof window === 'undefined') { + useSheet = x => x => x; +} else { + useSheet = require('./useSheet'); +} const PopoverActionsType = PropTypes.arrayOf(PropTypes.shape({ title: PropTypes.string.isRequired, @@ -11,7 +19,8 @@ const PopoverActionsType = PropTypes.arrayOf(PropTypes.shape({ export default class PopoverControl extends React.Component { static propTypes = { actions: PopoverActionsType.isRequired, - className: PropTypes.string + className: PropTypes.string, + sheet: PropTypes.object } state = { isPopped: false @@ -45,29 +54,23 @@ export default class PopoverControl extends React.Component { } }, 100); - document.addEventListener('scroll', this._debouncedScroll, true); + document.addEventListener('scroll', this._debouncedScroll); window.addEventListener('resize', this._debouncedScroll); } componentWillUnmount = () => { - document.removeEventListener('scroll', this._debouncedScroll, true); + document.removeEventListener('scroll', this._debouncedScroll); window.removeEventListener('resize', this._debouncedScroll); } render = () => { const {top, left, width, height} = this.state; - let popoverControlStyle = { - position: 'relative' - } - return ( -
-
+
+
{this.props.children}
{this.state.isPopped ? - ) } -} +}; +const PopoverListStyles = { + base: { + backgroundColor: 'white', + minWidth: 150, + overflow: 'hidden', + boxShadow: '0px 1px 4px rgba(0, 0, 0, 0.25)', + borderRadius: 5 + }, + item: { + display: 'block', + height: 40, + lineHeight: 40, + padding: '0 10px', + color: '#1A2D36', + '&:hover': { + textDecoration: 'none', + color: '#1A2D36', + backgroundColor: '#e1f0f7', + } + } +}; + +@useSheet(PopoverListStyles) class PopoverList extends React.Component { static propTypes = { actions: PopoverActionsType.isRequired, @@ -86,13 +112,19 @@ class PopoverList extends React.Component { getPopoverReferenceFrame: PropTypes.func.isRequired }).isRequired, windowMargin: PropTypes.number.isRequired, - launcherMargin: PropTypes.number.isRequired + launcherMargin: PropTypes.number.isRequired, + zIndex: PropTypes.number.isRequired } static defaultProps = { + zIndex: 10, windowMargin: 20, launcherMargin: 10 } state = { + top: null, + left: null, + width: null, + height: null, offsetX: 0, isFlipped: false, // usually bottom facing, but if true, then the popover should appear above } @@ -103,8 +135,8 @@ class PopoverList extends React.Component { ]); // Once the element is in the dom, we can measure its height - const {width, height} = React.findDOMNode(this).getBoundingClientRect(); - this.setState({width, height}); + const {top, left, width, height} = React.findDOMNode(this).getBoundingClientRect(); + this.setState({top, left, width, height}); } componentWillUnmount() { EventStack.removeListenable(this.eventToken); @@ -119,6 +151,7 @@ class PopoverList extends React.Component { this.props.delegate.shouldHidePopover(); } render() { + const {props: {sheet: {classes}}} = this; const {windowMargin, launcherMargin, parentFrame, actions} = this.props; const {width, height} = this.state; @@ -128,7 +161,7 @@ class PopoverList extends React.Component { }; // State - let offsetY = parentFrame.height + launcherMargin, + let offsetY = parentFrame.height + launcherMargin, offsetX = 0; // Flipping @@ -144,18 +177,20 @@ class PopoverList extends React.Component { position: 'absolute', top: 0, left: 0, - transform: `translate(${offsetX}px, ${offsetY}px)` + transform: `translate(${offsetX}px, ${offsetY}px)`, + zIndex: this.props.zIndex }; return ( -
+
{map(actions, (action, i) => - + {action.title} )}
) } -} \ No newline at end of file +}; diff --git a/src/useSheet.js b/src/useSheet.js new file mode 100644 index 0000000..6364583 --- /dev/null +++ b/src/useSheet.js @@ -0,0 +1,17 @@ +import {Jss} from 'jss'; +import reactJss from 'react-jss'; +import jssPx from 'jss-px'; +import jssCamelCase from 'jss-camel-case'; +import jssNested from 'jss-nested'; + +const jss = new Jss(); + +if (typeof window !== 'undefined') { + const vendorPrefixer = require('jss-vendor-prefixer'); + jss.use(vendorPrefixer); +} +jss.use(jssPx); +jss.use(jssCamelCase); +jss.use(jssNested); + +export default reactJss(jss);