mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-12-03 15:03:55 +03:00
Use prettier
This commit is contained in:
parent
458f9019aa
commit
6907c48147
File diff suppressed because one or more lines are too long
|
@ -6,3 +6,4 @@ umd
|
|||
build
|
||||
coverage
|
||||
node_modules
|
||||
__snapshots__
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ umd
|
|||
build
|
||||
coverage
|
||||
.idea
|
||||
.eslintcache
|
||||
|
|
|
@ -8,5 +8,5 @@ cache:
|
|||
- "node_modules"
|
||||
script:
|
||||
- yarn build:all
|
||||
- yarn lint
|
||||
- yarn lint:all
|
||||
- yarn test
|
||||
|
|
|
@ -11,4 +11,3 @@ Project maintainers have the right and responsibility to remove, edit, or reject
|
|||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ By installing [`redux-devtools-cli`](https://github.com/reduxjs/redux-devtools/t
|
|||
|
||||
We're using [SocketCluster](http://socketcluster.io/) for realtime communication, which provides a fast and scalable webSocket layer and a minimal pub/sub system. You need to include one of [its clients](https://github.com/SocketCluster/client-drivers) in your app to communicate with RemotedevServer. Currently there are clients for [JavaScript (NodeJS)](https://github.com/SocketCluster/socketcluster-client), [Java](https://github.com/sacOO7/socketcluster-client-java), [Python](https://github.com/sacOO7/socketcluster-client-python), [C](https://github.com/sacOO7/socketcluster-client-C), [Objective-C](https://github.com/abpopov/SocketCluster-ios-client) and [.NET/C#](https://github.com/sacOO7/SocketclusterClientDotNet).
|
||||
|
||||
By default, the websocket server is running on `ws://localhost:8000/socketcluster/`.
|
||||
By default, the websocket server is running on `ws://localhost:8000/socketcluster/`.
|
||||
|
||||
### Messaging lifecycle
|
||||
|
||||
|
@ -15,6 +15,7 @@ By default, the websocket server is running on `ws://localhost:8000/socketcluste
|
|||
The client driver provides a way to connect to the server via websockets (see the docs for the selected client).
|
||||
|
||||
##### JavaScript
|
||||
|
||||
```js
|
||||
var socket = socketCluster.connect({
|
||||
hostname: 'localhost',
|
||||
|
@ -23,18 +24,20 @@ var socket = socketCluster.connect({
|
|||
```
|
||||
|
||||
##### Python
|
||||
|
||||
```py
|
||||
socket = Socketcluster.socket("ws://localhost:8000/socketcluster/")
|
||||
socket = Socketcluster.socket("ws://localhost:8000/socketcluster/")
|
||||
socket.connect()
|
||||
```
|
||||
|
||||
> Note that JavaScript client composes the url from `hostname` and `port`, adding `/socketcluster/` path automatically. For other clients, you should specify that path. For example, for `ObjectiveC` it would be `self.client.initWithHost("localhost/socketcluster/", onPort: 8000, securely: false)`.
|
||||
|
||||
#### 2. Disconnecting and reconnecting
|
||||
|
||||
|
||||
SocketCluster client handles reconnecting for you, but you still might want to know when the connection is established, or when it failed to connect.
|
||||
|
||||
##### JavaScript
|
||||
|
||||
```js
|
||||
socket.on('connect', status => {
|
||||
// Here will come the next step
|
||||
|
@ -48,6 +51,7 @@ socket.on('error', error => {
|
|||
```
|
||||
|
||||
##### Python
|
||||
|
||||
```py
|
||||
def onconnect(socket):
|
||||
// Here will call the next step
|
||||
|
@ -66,9 +70,13 @@ socket.setBasicListener(onconnect, ondisconnect, onConnectError)
|
|||
We're not providing an authorizing mechanism yet. All you have to do is to emit a `login` event, and you'll get a `channelName` you should subscribe for, and watch for messages and events. Make sure to pass the `master` event, otherwise it should be a monitor, not a client app.
|
||||
|
||||
##### JavaScript
|
||||
|
||||
```js
|
||||
socket.emit('login', 'master', (error, channelName) => {
|
||||
if (error) { console.log(error); return; }
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return;
|
||||
}
|
||||
channel = socket.subscribe(channelName);
|
||||
channel.watch(handleMessages);
|
||||
socket.on(channelName, handleMessages);
|
||||
|
@ -80,6 +88,7 @@ function handleMessages(message) {
|
|||
```
|
||||
|
||||
##### Python
|
||||
|
||||
```py
|
||||
socket.emitack("login", "master", login)
|
||||
|
||||
|
@ -99,6 +108,7 @@ You could just emit the `login` event, and omit subscribing (and point `5` bello
|
|||
To send your data to the monitor use `log` or `log-noid` channel. The latter will add the socket id to the message from the server side (useful when the message was sent before the connection was established).
|
||||
|
||||
The message object includes the following:
|
||||
|
||||
- `type` - usually should be `ACTION`. If you want to indicate that we're starting a new log (clear all actions emitted before and add `@@INIT`), use `INIT`. In case you have a lifted state similar to one provided by [`redux-devtools-instrument`](https://github.com/zalmoxisus/redux-devtools-instrument), use `STATE`.
|
||||
- `action` - the action object. It is recommended to lift it in another object, and add `timestamp` to show when the action was fired off: `{ timestamp: Date.now(), action: { type: 'SOME_ACTION' } }`.
|
||||
- `payload` - usually the state or lifted state object.
|
||||
|
@ -107,6 +117,7 @@ The message object includes the following:
|
|||
- `id` - socket connection id, which should be either `socket.id` or should not provided and use `log-noid` channel.
|
||||
|
||||
##### JavaScript
|
||||
|
||||
```js
|
||||
const message = {
|
||||
type: 'ACTION',
|
||||
|
@ -120,6 +131,7 @@ socket.emit(socket.id ? 'log' : 'log-noid', message);
|
|||
```
|
||||
|
||||
##### Python
|
||||
|
||||
```py
|
||||
class Message:
|
||||
def __init__(self, action, state):
|
||||
|
@ -133,14 +145,16 @@ socket.emit(socket.id if "log" else "log-noid", Message(action, state));
|
|||
#### 5. Listening for monitor events
|
||||
|
||||
When a monitor action is emitted, you'll get an event on the subscribed function. The argument object includes a `type` key, which can be:
|
||||
|
||||
- `DISPATCH` - a monitor action dispatched on Redux DevTools monitor, like `{ type: 'DISPATCH', payload: { type: 'JUMP_TO_STATE', 'index': 2 }`. See [`redux-devtools-instrument`](https://github.com/zalmoxisus/redux-devtools-instrument/blob/master/src/instrument.js) for details. Additionally to that API, you'll get also a stringified `state` object when needed. So, for example, for time travelling (`JUMP_TO_STATE`) you can just parse and set the state (see the example). Usually implementing this type of actions would be enough.
|
||||
- `ACTION` - the user requested to dispatch an action remotely like `{ type: 'ACTION', action: '{ type: \'INCREMENT_COUNTER\' }' }`. The `action` can be either a stringified javascript object which should be evalled or a function which arguments should be evalled like [here](https://github.com/zalmoxisus/remotedev-utils/blob/master/src/index.js#L62-L70).
|
||||
- `START` - a monitor was opened. You could handle this event in order not to do extra tasks when the app is not monitored.
|
||||
- `STOP` - a monitor was closed. You can take this as no need to send data to the monitor. I there are several monitors and one was closed, all others will send `START` event to acknowledge that we still have to send data.
|
||||
- `STOP` - a monitor was closed. You can take this as no need to send data to the monitor. I there are several monitors and one was closed, all others will send `START` event to acknowledge that we still have to send data.
|
||||
|
||||
See [`mobx-remotedev`](https://github.com/zalmoxisus/mobx-remotedev/blob/master/src/monitorActions.js) for an example of implementation without [`redux-devtools-instrument`](https://github.com/zalmoxisus/redux-devtools-instrument/blob/master/src/instrument.js).
|
||||
|
||||
##### JavaScript
|
||||
|
||||
```js
|
||||
function handleMessages(message) {
|
||||
if (message.type === 'DISPATCH' && message.payload.type === 'JUMP_TO_STATE') {
|
||||
|
@ -150,6 +164,7 @@ function handleMessages(message) {
|
|||
```
|
||||
|
||||
##### Python
|
||||
|
||||
```py
|
||||
def handleMessages(key, message):
|
||||
if message.type === "DISPATCH" and message.payload.type === "JUMP_TO_STATE":
|
||||
|
|
|
@ -46,10 +46,12 @@ const DevTools = createDevTools(
|
|||
// Consult their repositories to learn about those props.
|
||||
// Here, we put LogMonitor inside a DockMonitor.
|
||||
// Note: DockMonitor is visible by default.
|
||||
<DockMonitor toggleVisibilityKey='ctrl-h'
|
||||
changePositionKey='ctrl-q'
|
||||
defaultIsVisible={true}>
|
||||
<LogMonitor theme='tomorrow' />
|
||||
<DockMonitor
|
||||
toggleVisibilityKey="ctrl-h"
|
||||
changePositionKey="ctrl-q"
|
||||
defaultIsVisible={true}
|
||||
>
|
||||
<LogMonitor theme="tomorrow" />
|
||||
</DockMonitor>
|
||||
);
|
||||
|
||||
|
@ -60,9 +62,7 @@ Note that you can use `LogMonitor` directly without wrapping it in `DockMonitor`
|
|||
|
||||
```js
|
||||
// If you'd rather not use docking UI, use <LogMonitor> directly
|
||||
const DevTools = createDevTools(
|
||||
<LogMonitor theme='solarized' />
|
||||
);
|
||||
const DevTools = createDevTools(<LogMonitor theme="solarized" />);
|
||||
```
|
||||
|
||||
#### Use `DevTools.instrument()` Store Enhancer
|
||||
|
@ -75,7 +75,7 @@ The easiest way to apply several store enhancers in a row is to use the [`compos
|
|||
|
||||
You can add additional options to it: `DevTools.instrument({ maxAge: 50, shouldCatchErrors: true })`. See [`redux-devtools-instrument`'s API](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-instrument#api) for more details.
|
||||
|
||||
It’s important that you should add `DevTools.instrument()` *after* `applyMiddleware` in your `compose()` function arguments. This is because `applyMiddleware` is potentially asynchronous, but `DevTools.instrument()` expects all actions to be plain objects rather than actions interpreted by asynchronous middleware such as [redux-promise](https://github.com/acdlite/redux-promise) or [redux-thunk](https://github.com/gaearon/redux-thunk). So make sure `applyMiddleware()` goes first in the `compose()` call, and `DevTools.instrument()` goes after it.
|
||||
It’s important that you should add `DevTools.instrument()` _after_ `applyMiddleware` in your `compose()` function arguments. This is because `applyMiddleware` is potentially asynchronous, but `DevTools.instrument()` expects all actions to be plain objects rather than actions interpreted by asynchronous middleware such as [redux-promise](https://github.com/acdlite/redux-promise) or [redux-thunk](https://github.com/gaearon/redux-thunk). So make sure `applyMiddleware()` goes first in the `compose()` call, and `DevTools.instrument()` goes after it.
|
||||
|
||||
##### `store/configureStore.js`
|
||||
|
||||
|
@ -99,7 +99,9 @@ export default function configureStore(initialState) {
|
|||
// Hot reload reducers (requires Webpack or Browserify HMR to be enabled)
|
||||
if (module.hot) {
|
||||
module.hot.accept('../reducers', () =>
|
||||
store.replaceReducer(require('../reducers')/*.default if you use Babel 6+ */)
|
||||
store.replaceReducer(
|
||||
require('../reducers') /*.default if you use Babel 6+ */
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -126,7 +128,7 @@ function getDebugSessionKey() {
|
|||
// You can write custom logic here!
|
||||
// By default we try to read the key from ?debug_session=<key> in the address bar
|
||||
const matches = window.location.href.match(/[?&]debug_session=([^&#]+)\b/);
|
||||
return (matches && matches.length > 0)? matches[1] : null;
|
||||
return matches && matches.length > 0 ? matches[1] : null;
|
||||
}
|
||||
|
||||
export default function configureStore(initialState) {
|
||||
|
@ -181,7 +183,7 @@ export default function configureStore(initialState) {
|
|||
// Note: only Redux >= 3.1.0 supports passing enhancer as third argument.
|
||||
// See https://github.com/rackt/redux/releases/tag/v3.1.0
|
||||
return createStore(rootReducer, initialState, enhancer);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
##### `store/configureStore.dev.js`
|
||||
|
@ -205,7 +207,7 @@ function getDebugSessionKey() {
|
|||
// You can write custom logic here!
|
||||
// By default we try to read the key from ?debug_session=<key> in the address bar
|
||||
const matches = window.location.href.match(/[?&]debug_session=([^&]+)\b/);
|
||||
return (matches && matches.length > 0)? matches[1] : null;
|
||||
return matches && matches.length > 0 ? matches[1] : null;
|
||||
}
|
||||
|
||||
export default function configureStore(initialState) {
|
||||
|
@ -216,7 +218,9 @@ export default function configureStore(initialState) {
|
|||
// Hot reload reducers (requires Webpack or Browserify HMR to be enabled)
|
||||
if (module.hot) {
|
||||
module.hot.accept('../reducers', () =>
|
||||
store.replaceReducer(require('../reducers')/*.default if you use Babel 6+ */)
|
||||
store.replaceReducer(
|
||||
require('../reducers') /*.default if you use Babel 6+ */
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -346,7 +350,11 @@ import { render } from 'react-dom';
|
|||
import DevTools from './containers/DevTools';
|
||||
|
||||
export default function showDevTools(store) {
|
||||
const popup = window.open(null, 'Redux DevTools', 'menubar=no,location=no,resizable=yes,scrollbars=no,status=no');
|
||||
const popup = window.open(
|
||||
null,
|
||||
'Redux DevTools',
|
||||
'menubar=no,location=no,resizable=yes,scrollbars=no,status=no'
|
||||
);
|
||||
// Reload in case it already exists
|
||||
popup.location.reload();
|
||||
|
||||
|
@ -366,11 +374,11 @@ Note that there are no useful props you can pass to the `DevTools` component oth
|
|||
|
||||
### Gotchas
|
||||
|
||||
* **Your reducers have to be pure and free of side effects to work correctly with DevTools.** For example, even generating a random ID in reducer makes it impure and non-deterministic. Instead, do this in action creators.
|
||||
- **Your reducers have to be pure and free of side effects to work correctly with DevTools.** For example, even generating a random ID in reducer makes it impure and non-deterministic. Instead, do this in action creators.
|
||||
|
||||
* **Make sure to only apply `DevTools.instrument()` and render `<DevTools>` in development!** In production, this will be terribly slow because actions just accumulate forever. As described above, you need to use conditional `require`s and use `DefinePlugin` (Webpack) or `loose-envify` (Browserify) together with Uglify to remove the dead code. Here is [an example](https://github.com/erikras/react-redux-universal-hot-example/) that adds Redux DevTools handling the production case correctly.
|
||||
- **Make sure to only apply `DevTools.instrument()` and render `<DevTools>` in development!** In production, this will be terribly slow because actions just accumulate forever. As described above, you need to use conditional `require`s and use `DefinePlugin` (Webpack) or `loose-envify` (Browserify) together with Uglify to remove the dead code. Here is [an example](https://github.com/erikras/react-redux-universal-hot-example/) that adds Redux DevTools handling the production case correctly.
|
||||
|
||||
* **It is important that `DevTools.instrument()` store enhancer should be added to your middleware stack *after* `applyMiddleware` in the `compose`d functions, as `applyMiddleware` is potentially asynchronous.** Otherwise, DevTools won’t see the raw actions emitted by asynchronous middleware such as [redux-promise](https://github.com/acdlite/redux-promise) or [redux-thunk](https://github.com/gaearon/redux-thunk).
|
||||
- **It is important that `DevTools.instrument()` store enhancer should be added to your middleware stack _after_ `applyMiddleware` in the `compose`d functions, as `applyMiddleware` is potentially asynchronous.** Otherwise, DevTools won’t see the raw actions emitted by asynchronous middleware such as [redux-promise](https://github.com/acdlite/redux-promise) or [redux-thunk](https://github.com/gaearon/redux-thunk).
|
||||
|
||||
### What Next?
|
||||
|
||||
|
|
|
@ -8,9 +8,5 @@
|
|||
"allowBranch": "master"
|
||||
}
|
||||
},
|
||||
"ignoreChanges": [
|
||||
"**/test/**",
|
||||
"**/examples/**",
|
||||
"**/*.md"
|
||||
]
|
||||
"ignoreChanges": ["**/test/**", "**/examples/**", "**/*.md"]
|
||||
}
|
||||
|
|
19
package.json
19
package.json
|
@ -9,7 +9,8 @@
|
|||
"eslint-plugin-react": "7.12.3",
|
||||
"jest": "^23.6.0",
|
||||
"lerna": "3.9.0",
|
||||
"pre-commit": "^1.1.3"
|
||||
"lint-staged": "^8.1.0",
|
||||
"prettier": "^1.15.3"
|
||||
},
|
||||
"scripts": {
|
||||
"lerna": "lerna",
|
||||
|
@ -21,13 +22,23 @@
|
|||
"lint": "eslint '**/*.{js,jsx}' --cache",
|
||||
"lint:fix": "eslint '**/*.{js,jsx}' --fix --cache",
|
||||
"lint:all": "eslint '**/*.{js,jsx}'",
|
||||
"prettify": "prettier '**/*.{js,jsx,json,css,html,md}' --ignore-path .eslintignore --single-quote --write",
|
||||
"precommit": "lint-staged",
|
||||
"test": "jest --onlyChanged",
|
||||
"test:all": "jest"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"pre-commit": [
|
||||
"lint"
|
||||
]
|
||||
"lint-staged": {
|
||||
"*.{js,jsx}": [
|
||||
"prettier --single-quote --write",
|
||||
"yarn lint:fix",
|
||||
"git add"
|
||||
],
|
||||
"*.{json,css,html,md}": [
|
||||
"prettier --single-quote --write",
|
||||
"git add"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
d3tooltip
|
||||
=========================
|
||||
# d3tooltip
|
||||
|
||||
This tooltip aims for a minimal yet highly configurable API. It has a long way to go, but the essentials are there.
|
||||
It was created by [@romseguy](https://github.com/romseguy) and merged from [`romseguy/d3tooltip`](https://github.com/romseguy/d3tooltip).
|
||||
|
@ -47,9 +46,9 @@ vis.selectAll('circle').data(someData).enter()
|
|||
|
||||
## API
|
||||
|
||||
Option | Type | Default | Description
|
||||
--------------------------|--------------|---------------------|--------------------------------------------------------------
|
||||
`root` | DOM.Element | `body` | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select)
|
||||
`left` | Number | `undefined` | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element
|
||||
`top` | Number | `undefined` | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element
|
||||
`offset` | Object | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option
|
||||
| Option | Type | Default | Description |
|
||||
| -------- | ----------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `root` | DOM.Element | `body` | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select) |
|
||||
| `left` | Number | `undefined` | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element |
|
||||
| `top` | Number | `undefined` | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element |
|
||||
| `offset` | Object | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option |
|
||||
|
|
28
packages/d3tooltip/src/index.js
vendored
28
packages/d3tooltip/src/index.js
vendored
|
@ -5,19 +5,14 @@ const { prependClass, functor } = utils.default || utils;
|
|||
const defaultOptions = {
|
||||
left: undefined, // mouseX
|
||||
top: undefined, // mouseY
|
||||
offset: {left: 0, top: 0},
|
||||
offset: { left: 0, top: 0 },
|
||||
root: undefined
|
||||
};
|
||||
|
||||
export default function tooltip(d3, className = 'tooltip', options = {}) {
|
||||
const {
|
||||
left,
|
||||
top,
|
||||
offset,
|
||||
root
|
||||
} = {...defaultOptions, ...options};
|
||||
const { left, top, offset, root } = { ...defaultOptions, ...options };
|
||||
|
||||
let attrs = {'class': className};
|
||||
let attrs = { class: className };
|
||||
let text = () => '';
|
||||
let styles = {};
|
||||
|
||||
|
@ -33,7 +28,8 @@ export default function tooltip(d3, className = 'tooltip', options = {}) {
|
|||
|
||||
anchor.selectAll(`div.${className}`).remove();
|
||||
|
||||
el = anchor.append('div')
|
||||
el = anchor
|
||||
.append('div')
|
||||
.attr(prependClass(className)(attrs))
|
||||
.style({
|
||||
position: 'absolute',
|
||||
|
@ -49,12 +45,10 @@ export default function tooltip(d3, className = 'tooltip', options = {}) {
|
|||
let [mouseX, mouseY] = d3.mouse(rootNode);
|
||||
let [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top];
|
||||
|
||||
el
|
||||
.style({
|
||||
left: x + 'px',
|
||||
top: y + 'px'
|
||||
})
|
||||
.html(() => text(node));
|
||||
el.style({
|
||||
left: x + 'px',
|
||||
top: y + 'px'
|
||||
}).html(() => text(node));
|
||||
},
|
||||
|
||||
'mouseout.tip': () => el.remove()
|
||||
|
@ -63,14 +57,14 @@ export default function tooltip(d3, className = 'tooltip', options = {}) {
|
|||
|
||||
tip.attr = function setAttr(d) {
|
||||
if (is(Object, d)) {
|
||||
attrs = {...attrs, ...d};
|
||||
attrs = { ...attrs, ...d };
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
tip.style = function setStyle(d) {
|
||||
if (is(Object, d)) {
|
||||
styles = {...styles, ...d};
|
||||
styles = { ...styles, ...d };
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
|
|
@ -1,31 +1,29 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = (env = {}) => (
|
||||
{
|
||||
mode: 'production',
|
||||
entry: {
|
||||
app: ['./src/index.js']
|
||||
},
|
||||
output: {
|
||||
library: 'd3tooltip',
|
||||
libraryTarget: 'umd',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: env.minimize ? 'd3tooltip.min.js' : 'd3tooltip.js'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
minimize: !!env.minimize
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
}
|
||||
module.exports = (env = {}) => ({
|
||||
mode: 'production',
|
||||
entry: {
|
||||
app: ['./src/index.js']
|
||||
},
|
||||
output: {
|
||||
library: 'd3tooltip',
|
||||
libraryTarget: 'umd',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: env.minimize ? 'd3tooltip.min.js' : 'd3tooltip.js'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
minimize: !!env.minimize
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -7,5 +7,6 @@ const parse = require('git-url-parse');
|
|||
var ghUrl = process.argv[2];
|
||||
const parsedUrl = parse(ghUrl);
|
||||
|
||||
const ghPagesUrl = 'https://' + parsedUrl.owner + '.github.io/' + parsedUrl.name;
|
||||
const ghPagesUrl =
|
||||
'https://' + parsedUrl.owner + '.github.io/' + parsedUrl.name;
|
||||
console.log(ghPagesUrl);
|
||||
|
|
|
@ -14,7 +14,7 @@ var exposedProperties = ['window', 'navigator', 'document'];
|
|||
|
||||
global.document = jsdom('');
|
||||
global.window = document.defaultView;
|
||||
Object.keys(document.defaultView).forEach((property) => {
|
||||
Object.keys(document.defaultView).forEach(property => {
|
||||
if (typeof global[property] === 'undefined') {
|
||||
exposedProperties.push(property);
|
||||
global[property] = document.defaultView[property];
|
||||
|
@ -25,9 +25,9 @@ global.navigator = {
|
|||
userAgent: 'node.js'
|
||||
};
|
||||
|
||||
process.on('unhandledRejection', function (error) {
|
||||
process.on('unhandledRejection', function(error) {
|
||||
console.error('Unhandled Promise Rejection:');
|
||||
console.error(error && error.stack || error);
|
||||
console.error((error && error.stack) || error);
|
||||
});
|
||||
|
||||
require('./user/pretest.js');
|
||||
|
|
|
@ -5,15 +5,17 @@ import { withKnobs } from '@storybook/addon-knobs';
|
|||
import { withTheme } from './themeAddon/theme';
|
||||
import '../src/presets.js';
|
||||
|
||||
addDecorator(withOptions({
|
||||
name: 'DevUI',
|
||||
url: 'https://github.com/reduxjs/redux-devtools/tree/master/packages/devui',
|
||||
goFullScreen: false,
|
||||
showStoriesPanel: true,
|
||||
showAddonPanel: true,
|
||||
showSearchBox: false,
|
||||
addonPanelInRight: true
|
||||
}));
|
||||
addDecorator(
|
||||
withOptions({
|
||||
name: 'DevUI',
|
||||
url: 'https://github.com/reduxjs/redux-devtools/tree/master/packages/devui',
|
||||
goFullScreen: false,
|
||||
showStoriesPanel: true,
|
||||
showAddonPanel: true,
|
||||
showSearchBox: false,
|
||||
addonPanelInRight: true
|
||||
})
|
||||
);
|
||||
|
||||
addDecorator(withTheme);
|
||||
addDecorator(withKnobs);
|
||||
|
|
|
@ -11,10 +11,11 @@
|
|||
min-height: 400px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Helvetica Neue", "Lucida Grande", sans-serif;
|
||||
font-family: 'Helvetica Neue', 'Lucida Grande', sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
#root, #root > div {
|
||||
#root,
|
||||
#root > div {
|
||||
height: 100%;
|
||||
}
|
||||
#root > div > div {
|
||||
|
|
|
@ -7,10 +7,7 @@ addons.register(ADDON_ID, api => {
|
|||
const channel = addons.getChannel();
|
||||
addons.addPanel(PANEL_ID, {
|
||||
title: 'Theme',
|
||||
render: ({ active }) => (
|
||||
active ?
|
||||
<Panel channel={channel} api={api} />
|
||||
: null
|
||||
)
|
||||
render: ({ active }) =>
|
||||
active ? <Panel channel={channel} api={api} /> : null
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Code Pro'), local('SourceCodePro-Regular'),
|
||||
url('./source-code-pro-v6-latin/source-code-pro-v6-latin-regular.woff2') format('woff2');
|
||||
url('./source-code-pro-v6-latin/source-code-pro-v6-latin-regular.woff2')
|
||||
format('woff2');
|
||||
}
|
||||
/* source-sans-pro-regular - latin */
|
||||
@font-face {
|
||||
|
@ -12,7 +13,8 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'),
|
||||
url('./source-sans-pro-v9-latin/source-sans-pro-v9-latin-regular.woff2') format('woff2');
|
||||
url('./source-sans-pro-v9-latin/source-sans-pro-v9-latin-regular.woff2')
|
||||
format('woff2');
|
||||
}
|
||||
/* source-sans-pro-600 - latin */
|
||||
@font-face {
|
||||
|
@ -20,7 +22,8 @@
|
|||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'),
|
||||
url('./source-sans-pro-v9-latin/source-sans-pro-v9-latin-600.woff2') format('woff2');
|
||||
url('./source-sans-pro-v9-latin/source-sans-pro-v9-latin-600.woff2')
|
||||
format('woff2');
|
||||
}
|
||||
|
||||
/* roboto-regular - latin */
|
||||
|
@ -29,7 +32,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto'), local('Roboto-Regular'),
|
||||
url('./roboto-v15-latin/roboto-v15-latin-regular.woff2') format('woff2');
|
||||
url('./roboto-v15-latin/roboto-v15-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
/* roboto-mono-regular - latin */
|
||||
@font-face {
|
||||
|
@ -37,7 +40,8 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'),
|
||||
url('./roboto-mono-v4-latin/roboto-mono-v4-latin-regular.woff2') format('woff2');
|
||||
url('./roboto-mono-v4-latin/roboto-mono-v4-latin-regular.woff2')
|
||||
format('woff2');
|
||||
}
|
||||
|
||||
/* Generated with https://google-webfonts-helper.herokuapp.com */
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
{
|
||||
"name": "devui",
|
||||
"version": "1.0.0-3",
|
||||
"description":
|
||||
"Reusable React components for building DevTools monitors and apps.",
|
||||
"files": ["lib", "fonts"],
|
||||
"description": "Reusable React components for building DevTools monitors and apps.",
|
||||
"files": [
|
||||
"lib",
|
||||
"fonts"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||
},
|
||||
"author":
|
||||
"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
||||
"author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "npm run storybook",
|
||||
|
|
|
@ -10,13 +10,15 @@ const CommonWrapper = createStyledComponent(commonStyle);
|
|||
|
||||
export default class Button extends Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return nextProps.children !== this.props.children ||
|
||||
return (
|
||||
nextProps.children !== this.props.children ||
|
||||
nextProps.disabled !== this.props.disabled ||
|
||||
nextProps.mark !== this.props.mark ||
|
||||
nextProps.size !== this.props.size ||
|
||||
nextProps.primary !== this.props.primary ||
|
||||
nextProps.tooltipPosition !== this.props.tooltipPosition ||
|
||||
nextProps.title !== this.props.title;
|
||||
nextProps.title !== this.props.title
|
||||
);
|
||||
}
|
||||
|
||||
onMouseUp = e => {
|
||||
|
@ -56,15 +58,32 @@ export default class Button extends Component {
|
|||
Button.propTypes = {
|
||||
children: PropTypes.any.isRequired,
|
||||
title: PropTypes.string,
|
||||
tooltipPosition: PropTypes.oneOf(['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right']),
|
||||
tooltipPosition: PropTypes.oneOf([
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
]),
|
||||
onClick: PropTypes.func,
|
||||
type: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
primary: PropTypes.bool,
|
||||
size: PropTypes.oneOf(['big', 'normal', 'small']),
|
||||
mark: PropTypes.oneOf([false, 'base08', 'base09', 'base0A', 'base0B',
|
||||
'base0C', 'base0D', 'base0E', 'base0F']),
|
||||
mark: PropTypes.oneOf([
|
||||
false,
|
||||
'base08',
|
||||
'base09',
|
||||
'base0A',
|
||||
'base0B',
|
||||
'base0C',
|
||||
'base0D',
|
||||
'base0E',
|
||||
'base0F'
|
||||
]),
|
||||
theme: PropTypes.object
|
||||
};
|
||||
|
||||
|
|
|
@ -16,44 +16,62 @@ export const Container = styled.div`
|
|||
|
||||
storiesOf('Button', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add(
|
||||
'default',
|
||||
() => (
|
||||
<Container>
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip! \\a And from new line hello!')}
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
primary={boolean('primary', true)}
|
||||
size={select('size', ['big', 'normal', 'small'], 'normal')}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
{text('Label', 'Hello Button')}
|
||||
</Button>
|
||||
</Container>
|
||||
)
|
||||
)
|
||||
.add(
|
||||
'mark',
|
||||
() => (
|
||||
<Container>
|
||||
<Button
|
||||
mark={select('mark', ['base08', 'base09', 'base0A', 'base0B',
|
||||
'base0C', 'base0D', 'base0E', 'base0F'], 'base08')}
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
size={select('size', ['big', 'normal', 'small'], 'normal')}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
<MdFiberManualRecord />
|
||||
</Button>
|
||||
</Container>
|
||||
)
|
||||
);
|
||||
.add('default', () => (
|
||||
<Container>
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip! \\a And from new line hello!')}
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
primary={boolean('primary', true)}
|
||||
size={select('size', ['big', 'normal', 'small'], 'normal')}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
{text('Label', 'Hello Button')}
|
||||
</Button>
|
||||
</Container>
|
||||
))
|
||||
.add('mark', () => (
|
||||
<Container>
|
||||
<Button
|
||||
mark={select(
|
||||
'mark',
|
||||
[
|
||||
'base08',
|
||||
'base09',
|
||||
'base0A',
|
||||
'base0B',
|
||||
'base0C',
|
||||
'base0D',
|
||||
'base0E',
|
||||
'base0F'
|
||||
],
|
||||
'base08'
|
||||
)}
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
size={select('size', ['big', 'normal', 'small'], 'normal')}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
<MdFiberManualRecord />
|
||||
</Button>
|
||||
</Container>
|
||||
));
|
||||
|
|
|
@ -2,7 +2,7 @@ import { css } from 'styled-components';
|
|||
import { fadeIn } from '../../utils/animations';
|
||||
import colorEffect from '../../utils/color';
|
||||
|
||||
const both = (tooltipPosition) => {
|
||||
const both = tooltipPosition => {
|
||||
switch (tooltipPosition) {
|
||||
case 'bottom':
|
||||
return `
|
||||
|
@ -46,7 +46,7 @@ const both = (tooltipPosition) => {
|
|||
}
|
||||
};
|
||||
|
||||
const before = (tooltipPosition) => {
|
||||
const before = tooltipPosition => {
|
||||
switch (tooltipPosition) {
|
||||
case 'bottom-left':
|
||||
return `
|
||||
|
@ -110,12 +110,13 @@ const after = (tooltipPosition, color) => {
|
|||
}
|
||||
};
|
||||
|
||||
const getDirection = (tooltipPosition) => {
|
||||
return (tooltipPosition.indexOf('-') > 0) ?
|
||||
tooltipPosition.substring(0, tooltipPosition.indexOf('-')) : tooltipPosition;
|
||||
const getDirection = tooltipPosition => {
|
||||
return tooltipPosition.indexOf('-') > 0
|
||||
? tooltipPosition.substring(0, tooltipPosition.indexOf('-'))
|
||||
: tooltipPosition;
|
||||
};
|
||||
|
||||
const getSize = (size) => {
|
||||
const getSize = size => {
|
||||
switch (size) {
|
||||
case 'big':
|
||||
return 'min-height: 34px; padding: 2px 12px;';
|
||||
|
@ -144,8 +145,13 @@ export const commonStyle = ({ theme, mark, size }) => css`
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
${mark && `
|
||||
background-color: ${colorEffect(theme[mark], 'fade', theme.light ? 0.92 : 0.82)};
|
||||
${mark &&
|
||||
`
|
||||
background-color: ${colorEffect(
|
||||
theme[mark],
|
||||
'fade',
|
||||
theme.light ? 0.92 : 0.82
|
||||
)};
|
||||
|
||||
> svg {
|
||||
color: ${theme[mark]};
|
||||
|
@ -158,7 +164,13 @@ export const commonStyle = ({ theme, mark, size }) => css`
|
|||
}
|
||||
`;
|
||||
|
||||
export const tooltipStyle = ({ theme, tooltipTitle, tooltipPosition, mark, size }) => css`
|
||||
export const tooltipStyle = ({
|
||||
theme,
|
||||
tooltipTitle,
|
||||
tooltipPosition,
|
||||
mark,
|
||||
size
|
||||
}) => css`
|
||||
${commonStyle({ theme, mark, size })}
|
||||
|
||||
&:before {
|
||||
|
@ -170,7 +182,9 @@ export const tooltipStyle = ({ theme, tooltipTitle, tooltipPosition, mark, size
|
|||
border-radius: 3px;
|
||||
background: ${theme.base01};
|
||||
border: 1px solid ${theme.base02};
|
||||
box-shadow: 1px 1px 2px -1px ${theme.base02}, 1px 1px 2px 0px ${theme.base02};
|
||||
box-shadow: 1px 1px 2px -1px ${theme.base02}, 1px 1px 2px 0px ${
|
||||
theme.base02
|
||||
};
|
||||
}
|
||||
|
||||
&:after,
|
||||
|
@ -194,7 +208,8 @@ export const tooltipStyle = ({ theme, tooltipTitle, tooltipPosition, mark, size
|
|||
${theme.type === 'material' ? `animation: ${fadeIn} 500ms;` : ''}
|
||||
}
|
||||
|
||||
${theme.type !== 'material' && `
|
||||
${theme.type !== 'material' &&
|
||||
`
|
||||
&:after {
|
||||
content: "";
|
||||
border-style: solid;
|
||||
|
|
|
@ -11,21 +11,30 @@ export const style = ({ theme, primary, disabled }) => css`
|
|||
margin: auto 0;
|
||||
border: 1px solid ${theme.base02};
|
||||
border-radius: 4px;
|
||||
${primary ? `
|
||||
${
|
||||
primary
|
||||
? `
|
||||
background-color: ${theme.base05};
|
||||
color: ${theme.base00};
|
||||
` : `
|
||||
`
|
||||
: `
|
||||
background-color: ${theme.base01};
|
||||
color: ${theme.base05};
|
||||
`}
|
||||
${disabled ? `
|
||||
`
|
||||
}
|
||||
${
|
||||
disabled
|
||||
? `
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
` : `
|
||||
`
|
||||
: `
|
||||
cursor: pointer;
|
||||
`}
|
||||
`
|
||||
}
|
||||
|
||||
${!disabled && `
|
||||
${!disabled &&
|
||||
`
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: ${primary ? theme.base07 : theme.base02};
|
||||
|
|
|
@ -13,20 +13,24 @@ export const style = ({ theme, primary, disabled }) => css`
|
|||
text-transform: uppercase;
|
||||
margin: auto 0;
|
||||
background-color: ${primary ? theme.base05 : theme.base01};
|
||||
${disabled ? `
|
||||
${disabled
|
||||
? `
|
||||
cursor: not-allowed;
|
||||
color: ${theme.base04};
|
||||
opacity: 0.6;
|
||||
` : `
|
||||
`
|
||||
: `
|
||||
cursor: pointer;
|
||||
color: ${primary ? theme.base00 : theme.base05};
|
||||
`}
|
||||
${!disabled ? `
|
||||
${!disabled
|
||||
? `
|
||||
box-shadow:
|
||||
0 2px 2px 0 ${theme.base03},
|
||||
0 3px 1px -2px ${theme.base02},
|
||||
0 1px 5px 0 ${theme.base02};
|
||||
` : ''}
|
||||
`
|
||||
: ''}
|
||||
|
||||
|
||||
&:hover, &:focus:not(:active) {
|
||||
|
|
|
@ -10,15 +10,23 @@ export const MainContainerWrapper = styled.div`
|
|||
color: ${props => props.theme.base07};
|
||||
font-size: 12px;
|
||||
|
||||
div, input, textarea, keygen, select, button {
|
||||
font-family: ${props => props.theme.fontFamily || 'monaco, monospace'};
|
||||
}
|
||||
div,
|
||||
input,
|
||||
textarea,
|
||||
keygen,
|
||||
select,
|
||||
button {
|
||||
font-family: ${props => props.theme.fontFamily || 'monaco, monospace'};
|
||||
}
|
||||
|
||||
.CodeMirror div, pre, .monitor-LogMonitor * {
|
||||
font-family: ${props => props.theme.codeFontFamily || props.theme.fontFamily || 'monospace'};
|
||||
}
|
||||
.CodeMirror div,
|
||||
pre,
|
||||
.monitor-LogMonitor * {
|
||||
font-family: ${props =>
|
||||
props.theme.codeFontFamily || props.theme.fontFamily || 'monospace'};
|
||||
}
|
||||
|
||||
.monitor {
|
||||
.monitor {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
|
|
@ -12,8 +12,10 @@ export default class ContextMenu extends Component {
|
|||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.items !== this.props.items ||
|
||||
nextProps.visible !== this.props.visible) {
|
||||
if (
|
||||
nextProps.items !== this.props.items ||
|
||||
nextProps.visible !== this.props.visible
|
||||
) {
|
||||
this.updateItems(nextProps.items);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +34,7 @@ export default class ContextMenu extends Component {
|
|||
e.target.blur();
|
||||
};
|
||||
|
||||
onClick = (e) => {
|
||||
onClick = e => {
|
||||
this.props.onClick(e.target.value);
|
||||
};
|
||||
|
||||
|
@ -78,7 +80,7 @@ export default class ContextMenu extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
menuRef = (c) => {
|
||||
menuRef = c => {
|
||||
this.menu = c;
|
||||
};
|
||||
|
||||
|
|
|
@ -16,17 +16,14 @@ export const Container = styled.div`
|
|||
|
||||
storiesOf('ContextMenu', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add(
|
||||
'default',
|
||||
() => (
|
||||
<Container>
|
||||
<ContextMenu
|
||||
visible
|
||||
onClick={action('menu item clicked')}
|
||||
x={number('x', 100)}
|
||||
y={number('y', 100)}
|
||||
items={items}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
);
|
||||
.add('default', () => (
|
||||
<Container>
|
||||
<ContextMenu
|
||||
visible
|
||||
onClick={action('menu item clicked')}
|
||||
x={number('x', 100)}
|
||||
y={number('y', 100)}
|
||||
items={items}
|
||||
/>
|
||||
</Container>
|
||||
));
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { css } from 'styled-components';
|
||||
|
||||
export default ({ theme, left, top, visible }) => css`
|
||||
${visible ? `
|
||||
${visible
|
||||
? `
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s linear;
|
||||
` : `
|
||||
`
|
||||
: `
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: visibility 0s 0.2s, opacity 0.2s linear;
|
||||
|
@ -36,7 +38,7 @@ export default ({ theme, left, top, visible }) => css`
|
|||
color: ${theme.base07};
|
||||
}
|
||||
&:focus {
|
||||
outline:0;
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -52,47 +52,47 @@ export default class Dialog extends (PureComponent || Component) {
|
|||
{!noHeader && (
|
||||
<div className="mc-dialog--header">
|
||||
<div>{schema ? schema.title || title : title}</div>
|
||||
{!modal && <button onClick={onDismiss}>×</button>}
|
||||
{!modal && <button onClick={onDismiss}>×</button>}
|
||||
</div>
|
||||
)}
|
||||
<div className="mc-dialog--body">
|
||||
{children}
|
||||
{schema && (
|
||||
<Form {...rest}>
|
||||
{!noFooter &&
|
||||
(
|
||||
{!noFooter && (
|
||||
<input
|
||||
type="submit"
|
||||
ref={this.getFormButtonRef}
|
||||
className="mc-dialog--hidden"
|
||||
/>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</Form>
|
||||
)}
|
||||
</div>
|
||||
{
|
||||
!noFooter &&
|
||||
(actions ?
|
||||
<div className="mc-dialog--footer">
|
||||
{submitText ?
|
||||
[...actions,
|
||||
<Button key="default-submit" primary onClick={this.onSubmit}>
|
||||
{!noFooter &&
|
||||
(actions ? (
|
||||
<div className="mc-dialog--footer">
|
||||
{submitText
|
||||
? [
|
||||
...actions,
|
||||
<Button
|
||||
key="default-submit"
|
||||
primary
|
||||
onClick={this.onSubmit}
|
||||
>
|
||||
{submitText}
|
||||
</Button>
|
||||
]
|
||||
: actions
|
||||
}
|
||||
</div>
|
||||
:
|
||||
<div className="mc-dialog--footer">
|
||||
<Button onClick={onDismiss}>Cancel</Button>
|
||||
<Button primary onClick={this.onSubmit}>
|
||||
{submitText || 'Submit'}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
: actions}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mc-dialog--footer">
|
||||
<Button onClick={onDismiss}>Cancel</Button>
|
||||
<Button primary onClick={this.onSubmit}>
|
||||
{submitText || 'Submit'}
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DialogWrapper>
|
||||
);
|
||||
|
|
|
@ -7,39 +7,33 @@ import { schema, uiSchema, formData } from '../../Form/stories/schema';
|
|||
|
||||
storiesOf('Dialog', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add(
|
||||
'default',
|
||||
() => (
|
||||
<Dialog
|
||||
title={text('title', 'Dialog Title')}
|
||||
submitText={text('submitText', 'Submit!')}
|
||||
open={boolean('open', true)}
|
||||
noHeader={boolean('noHeader', false)}
|
||||
noFooter={boolean('noFooter', false)}
|
||||
modal={boolean('modal', false)}
|
||||
fullWidth={boolean('fullWidth', false)}
|
||||
onDismiss={action('dialog dismissed')}
|
||||
onSubmit={action('dialog submitted')}
|
||||
>
|
||||
{text('children', 'Hello Dialog!')}
|
||||
</Dialog>
|
||||
)
|
||||
)
|
||||
.add(
|
||||
'with form',
|
||||
() => (
|
||||
<Dialog
|
||||
open={boolean('open', true)}
|
||||
noHeader={boolean('noHeader', false)}
|
||||
noFooter={boolean('noFooter', false)}
|
||||
fullWidth={boolean('fullWidth', false)}
|
||||
submitText={text('submitText', 'Submit!')}
|
||||
formData={object('formData', formData)}
|
||||
schema={object('schema', schema)}
|
||||
uiSchema={object('uiSchema', uiSchema)}
|
||||
onChange={action('form changed')}
|
||||
onSubmit={action('form submitted')}
|
||||
onDismiss={action('dialog dismissed')}
|
||||
/>
|
||||
)
|
||||
);
|
||||
.add('default', () => (
|
||||
<Dialog
|
||||
title={text('title', 'Dialog Title')}
|
||||
submitText={text('submitText', 'Submit!')}
|
||||
open={boolean('open', true)}
|
||||
noHeader={boolean('noHeader', false)}
|
||||
noFooter={boolean('noFooter', false)}
|
||||
modal={boolean('modal', false)}
|
||||
fullWidth={boolean('fullWidth', false)}
|
||||
onDismiss={action('dialog dismissed')}
|
||||
onSubmit={action('dialog submitted')}
|
||||
>
|
||||
{text('children', 'Hello Dialog!')}
|
||||
</Dialog>
|
||||
))
|
||||
.add('with form', () => (
|
||||
<Dialog
|
||||
open={boolean('open', true)}
|
||||
noHeader={boolean('noHeader', false)}
|
||||
noFooter={boolean('noFooter', false)}
|
||||
fullWidth={boolean('fullWidth', false)}
|
||||
submitText={text('submitText', 'Submit!')}
|
||||
formData={object('formData', formData)}
|
||||
schema={object('schema', schema)}
|
||||
uiSchema={object('uiSchema', uiSchema)}
|
||||
onChange={action('form changed')}
|
||||
onSubmit={action('form submitted')}
|
||||
onDismiss={action('dialog dismissed')}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -36,10 +36,8 @@ export const style = ({ theme, open, fullWidth }) => css`
|
|||
border: 1px outset ${theme.base01};
|
||||
border-radius: 2px;
|
||||
background-color: ${theme.base00};
|
||||
box-shadow:
|
||||
0 9px 46px 8px rgba(0, 0, 0, 0.14),
|
||||
0 11px 15px -7px rgba(0, 0, 0, 0.12),
|
||||
0 24px 38px 3px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14),
|
||||
0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
|
||||
|
||||
> div.mc-dialog--header {
|
||||
display: flex;
|
||||
|
@ -76,15 +74,23 @@ export const style = ({ theme, open, fullWidth }) => css`
|
|||
|
||||
> form {
|
||||
padding: 0;
|
||||
|
||||
> .form-group { margin-bottom: 0; }
|
||||
|
||||
> div > fieldset {
|
||||
legend { display: none; }
|
||||
#root__description { margin-top: 0; }
|
||||
> .form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mc-dialog--hidden { display: none; }
|
||||
> div > fieldset {
|
||||
legend {
|
||||
display: none;
|
||||
}
|
||||
#root__description {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mc-dialog--hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +108,7 @@ export const style = ({ theme, open, fullWidth }) => css`
|
|||
margin: 0 -16px -16px;
|
||||
padding: 2px 10px;
|
||||
border-top: 1px solid ${theme.base03};
|
||||
|
||||
|
||||
> button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
|
|
@ -35,10 +35,8 @@ export const style = ({ theme, open, fullWidth }) => css`
|
|||
margin-bottom: 16px;
|
||||
border: none;
|
||||
background-color: ${theme.base00};
|
||||
box-shadow:
|
||||
0 9px 46px 8px rgba(0, 0, 0, 0.14),
|
||||
0 11px 15px -7px rgba(0, 0, 0, 0.12),
|
||||
0 24px 38px 3px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14),
|
||||
0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
|
||||
|
||||
> div.mc-dialog--header {
|
||||
display: flex;
|
||||
|
@ -73,15 +71,23 @@ export const style = ({ theme, open, fullWidth }) => css`
|
|||
|
||||
> form {
|
||||
padding: 0;
|
||||
|
||||
> .form-group { margin-bottom: 0; }
|
||||
|
||||
> div > fieldset {
|
||||
legend { display: none; }
|
||||
#root__description { margin-top: 0; }
|
||||
> .form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mc-dialog--hidden { display: none; }
|
||||
> div > fieldset {
|
||||
legend {
|
||||
display: none;
|
||||
}
|
||||
#root__description {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mc-dialog--hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,28 +4,27 @@ import styled from 'styled-components';
|
|||
import CodeMirror from 'codemirror';
|
||||
import { defaultStyle, themedStyle } from './styles';
|
||||
|
||||
const EditorContainer = styled.div('',
|
||||
({ theme }) => (theme.scheme === 'default' && theme.light ? defaultStyle : themedStyle(theme))
|
||||
const EditorContainer = styled.div('', ({ theme }) =>
|
||||
theme.scheme === 'default' && theme.light ? defaultStyle : themedStyle(theme)
|
||||
);
|
||||
|
||||
export default class Editor extends Component {
|
||||
componentDidMount() {
|
||||
this.cm = CodeMirror( // eslint-disable-line new-cap
|
||||
this.node,
|
||||
{
|
||||
value: this.props.value,
|
||||
mode: this.props.mode,
|
||||
lineNumbers: this.props.lineNumbers,
|
||||
lineWrapping: this.props.lineWrapping,
|
||||
readOnly: this.props.readOnly,
|
||||
autofocus: this.props.autofocus,
|
||||
foldGutter: this.props.foldGutter,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
|
||||
}
|
||||
);
|
||||
this.cm = CodeMirror(this.node, {
|
||||
value: this.props.value,
|
||||
mode: this.props.mode,
|
||||
lineNumbers: this.props.lineNumbers,
|
||||
lineWrapping: this.props.lineWrapping,
|
||||
readOnly: this.props.readOnly,
|
||||
autofocus: this.props.autofocus,
|
||||
foldGutter: this.props.foldGutter,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
|
||||
});
|
||||
|
||||
if (this.props.onChange) {
|
||||
this.cm.on('change', (doc, change) => { this.props.onChange(doc.getValue(), change); });
|
||||
this.cm.on('change', (doc, change) => {
|
||||
this.props.onChange(doc.getValue(), change);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ export default class WithTabs extends Component {
|
|||
}
|
||||
]}
|
||||
selected={this.state.selected}
|
||||
onClick={selected => { this.setState({ selected }); }}
|
||||
onClick={selected => {
|
||||
this.setState({ selected });
|
||||
}}
|
||||
align={select('align', ['left', 'right', 'center'], 'left')}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -30,11 +30,6 @@ storiesOf('Editor', module)
|
|||
),
|
||||
{ info: 'Based on [CodeMirror](http://codemirror.net/).' }
|
||||
)
|
||||
.add(
|
||||
'with tabs',
|
||||
() => (
|
||||
<WithTabs
|
||||
lineNumbers={boolean('lineNumbers', true)}
|
||||
/>
|
||||
)
|
||||
);
|
||||
.add('with tabs', () => (
|
||||
<WithTabs lineNumbers={boolean('lineNumbers', true)} />
|
||||
));
|
||||
|
|
|
@ -19,37 +19,79 @@ export const themedStyle = theme => css`
|
|||
background-color: ${theme.base00};
|
||||
color: ${theme.base04};
|
||||
|
||||
.cm-header { color: ${theme.base05}; }
|
||||
.cm-quote { color: ${theme.base09}; }
|
||||
.cm-header {
|
||||
color: ${theme.base05};
|
||||
}
|
||||
.cm-quote {
|
||||
color: ${theme.base09};
|
||||
}
|
||||
|
||||
.cm-keyword { color: ${theme.base0F}; }
|
||||
.cm-atom { color: ${theme.base0F}; }
|
||||
.cm-number { color: ${theme.base0F}; }
|
||||
.cm-def { color: ${theme.base0D}; }
|
||||
.cm-keyword {
|
||||
color: ${theme.base0F};
|
||||
}
|
||||
.cm-atom {
|
||||
color: ${theme.base0F};
|
||||
}
|
||||
.cm-number {
|
||||
color: ${theme.base0F};
|
||||
}
|
||||
.cm-def {
|
||||
color: ${theme.base0D};
|
||||
}
|
||||
|
||||
.cm-variable { color: ${theme.base05}; }
|
||||
.cm-variable-2 { color: ${theme.base0A}; }
|
||||
.cm-variable-3 { color: ${theme.base0E}; }
|
||||
.cm-variable {
|
||||
color: ${theme.base05};
|
||||
}
|
||||
.cm-variable-2 {
|
||||
color: ${theme.base0A};
|
||||
}
|
||||
.cm-variable-3 {
|
||||
color: ${theme.base0E};
|
||||
}
|
||||
|
||||
.cm-property { color: ${theme.base0C}; }
|
||||
.cm-operator { color: ${theme.base0E}; }
|
||||
.cm-property {
|
||||
color: ${theme.base0C};
|
||||
}
|
||||
.cm-operator {
|
||||
color: ${theme.base0E};
|
||||
}
|
||||
|
||||
.cm-comment {
|
||||
color: ${theme.base05};
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.cm-string { color: ${theme.base0B}; }
|
||||
.cm-string-2 { color: ${theme.base0A}; }
|
||||
.cm-string {
|
||||
color: ${theme.base0B};
|
||||
}
|
||||
.cm-string-2 {
|
||||
color: ${theme.base0A};
|
||||
}
|
||||
|
||||
.cm-meta { color: ${theme.base0B}; }
|
||||
.cm-qualifier { color: ${theme.base0A}; }
|
||||
.cm-builtin { color: ${theme.base0F}; }
|
||||
.cm-bracket { color: ${theme.base09}; }
|
||||
.CodeMirror-matchingbracket { color: ${theme.base0B}; }
|
||||
.CodeMirror-nonmatchingbracket { color: ${theme.base08}; }
|
||||
.cm-tag { color: ${theme.base02}; }
|
||||
.cm-attribute { color: ${theme.base0C}; }
|
||||
.cm-meta {
|
||||
color: ${theme.base0B};
|
||||
}
|
||||
.cm-qualifier {
|
||||
color: ${theme.base0A};
|
||||
}
|
||||
.cm-builtin {
|
||||
color: ${theme.base0F};
|
||||
}
|
||||
.cm-bracket {
|
||||
color: ${theme.base09};
|
||||
}
|
||||
.CodeMirror-matchingbracket {
|
||||
color: ${theme.base0B};
|
||||
}
|
||||
.CodeMirror-nonmatchingbracket {
|
||||
color: ${theme.base08};
|
||||
}
|
||||
.cm-tag {
|
||||
color: ${theme.base02};
|
||||
}
|
||||
.cm-attribute {
|
||||
color: ${theme.base0C};
|
||||
}
|
||||
|
||||
.cm-hr {
|
||||
color: transparent;
|
||||
|
@ -62,7 +104,9 @@ export const themedStyle = theme => css`
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cm-special { color: ${theme.base0E}; }
|
||||
.cm-special {
|
||||
color: ${theme.base0E};
|
||||
}
|
||||
|
||||
.cm-em {
|
||||
color: #999;
|
||||
|
@ -70,7 +114,9 @@ export const themedStyle = theme => css`
|
|||
text-decoration-style: dotted;
|
||||
}
|
||||
|
||||
.cm-strong { color: ${theme.base01}; }
|
||||
.cm-strong {
|
||||
color: ${theme.base01};
|
||||
}
|
||||
|
||||
.cm-error,
|
||||
.cm-invalidchar {
|
||||
|
@ -78,7 +124,9 @@ export const themedStyle = theme => css`
|
|||
border-bottom: 1px dotted ${theme.base08};
|
||||
}
|
||||
|
||||
div.CodeMirror-selected { background: ${theme.base01}; }
|
||||
div.CodeMirror-selected {
|
||||
background: ${theme.base01};
|
||||
}
|
||||
|
||||
.CodeMirror-line::selection,
|
||||
.CodeMirror-line > span::selection,
|
||||
|
@ -106,17 +154,27 @@ export const themedStyle = theme => css`
|
|||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker-subtle { color: ${theme.base05}; }
|
||||
.CodeMirror-guttermarker { color: ${theme.base09}; }
|
||||
.CodeMirror-guttermarker-subtle {
|
||||
color: ${theme.base05};
|
||||
}
|
||||
.CodeMirror-guttermarker {
|
||||
color: ${theme.base09};
|
||||
}
|
||||
|
||||
.CodeMirror-gutter .CodeMirror-gutter-text {
|
||||
color: ${theme.base05};
|
||||
}
|
||||
|
||||
.CodeMirror-cursor { border-left: 1px solid #819090; }
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid #819090;
|
||||
}
|
||||
|
||||
.cm-fat-cursor .CodeMirror-cursor { background: ${theme.base02}; }
|
||||
.cm-animate-fat-cursor { background-color: ${theme.base02}; }
|
||||
.cm-fat-cursor .CodeMirror-cursor {
|
||||
background: ${theme.base02};
|
||||
}
|
||||
.cm-animate-fat-cursor {
|
||||
background-color: ${theme.base02};
|
||||
}
|
||||
|
||||
.CodeMirror-activeline-background {
|
||||
background: ${theme.base07};
|
||||
|
|
|
@ -10,16 +10,30 @@ const FormContainer = createStyledComponent(styles, JSONSchemaForm);
|
|||
|
||||
export default class Form extends (PureComponent || Component) {
|
||||
render() {
|
||||
const { widgets, children, submitText, primaryButton, noSubmit, ...rest } = this.props;
|
||||
const {
|
||||
widgets,
|
||||
children,
|
||||
submitText,
|
||||
primaryButton,
|
||||
noSubmit,
|
||||
...rest
|
||||
} = this.props;
|
||||
return (
|
||||
<FormContainer {...rest} widgets={{ ...customWidgets, ...widgets }}>
|
||||
{
|
||||
noSubmit ? <noscript /> :
|
||||
children ||
|
||||
<Button size="big" primary={primaryButton} theme={rest.theme} type="submit">
|
||||
{submitText || 'Submit'}
|
||||
</Button>
|
||||
}
|
||||
{noSubmit ? (
|
||||
<noscript />
|
||||
) : (
|
||||
children || (
|
||||
<Button
|
||||
size="big"
|
||||
primary={primaryButton}
|
||||
theme={rest.theme}
|
||||
type="submit"
|
||||
>
|
||||
{submitText || 'Submit'}
|
||||
</Button>
|
||||
)
|
||||
)}
|
||||
</FormContainer>
|
||||
);
|
||||
}
|
||||
|
@ -33,5 +47,7 @@ Form.propTypes = {
|
|||
schema: PropTypes.object.isRequired,
|
||||
uiSchema: PropTypes.object,
|
||||
formData: PropTypes.any,
|
||||
widgets: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object]))
|
||||
widgets: PropTypes.objectOf(
|
||||
PropTypes.oneOfType([PropTypes.func, PropTypes.object])
|
||||
)
|
||||
};
|
||||
|
|
|
@ -19,8 +19,9 @@ storiesOf('Form', module)
|
|||
onSubmit={action('form submitted')}
|
||||
/>
|
||||
),
|
||||
{ info:
|
||||
'Wrapper around [`react-jsonschema-form`](https://github.com/mozilla-services/react-jsonschema-form)'
|
||||
+ ' with custom widgets.'
|
||||
{
|
||||
info:
|
||||
'Wrapper around [`react-jsonschema-form`](https://github.com/mozilla-services/react-jsonschema-form)' +
|
||||
' with custom widgets.'
|
||||
}
|
||||
);
|
||||
|
|
|
@ -27,31 +27,19 @@ module.exports = {
|
|||
title: 'A multiple choices list',
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
'foo',
|
||||
'bar',
|
||||
'fuzz'
|
||||
]
|
||||
enum: ['foo', 'bar', 'fuzz']
|
||||
},
|
||||
uniqueItems: true
|
||||
},
|
||||
numberEnum: {
|
||||
type: 'number',
|
||||
title: 'Number enum',
|
||||
enum: [
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
enum: [1, 2, 3]
|
||||
},
|
||||
numberEnumRadio: {
|
||||
type: 'number',
|
||||
title: 'Number enum',
|
||||
enum: [
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
enum: [1, 2, 3]
|
||||
},
|
||||
integerRange: {
|
||||
title: 'Integer range',
|
||||
|
|
|
@ -1,368 +1,368 @@
|
|||
import { css } from 'styled-components';
|
||||
|
||||
export default ({ theme }) => css`
|
||||
padding: 10px;
|
||||
line-height: 1.846;
|
||||
font-size: 14px;
|
||||
color: ${theme.base06};
|
||||
padding: 10px;
|
||||
line-height: 1.846;
|
||||
font-size: 14px;
|
||||
color: ${theme.base06};
|
||||
|
||||
fieldset {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
fieldset {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
font-size: 20px;
|
||||
color: ${theme.base04};
|
||||
border: 0;
|
||||
}
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
font-size: 20px;
|
||||
color: ${theme.base04};
|
||||
border: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
font-weight: bold;
|
||||
}
|
||||
label {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
color: ${theme.base05};
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
line-height: ${theme.inputInternalHeight}px;
|
||||
padding: 0 ${theme.inputPadding}px;
|
||||
border-style: solid;
|
||||
border-width: ${theme.inputBorderWidth}px;
|
||||
border-color: ${theme.inputBorderColor};
|
||||
border-radius: ${theme.inputBorderRadius}px;
|
||||
}
|
||||
.form-control {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
color: ${theme.base05};
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
line-height: ${theme.inputInternalHeight}px;
|
||||
padding: 0 ${theme.inputPadding}px;
|
||||
border-style: solid;
|
||||
border-width: ${theme.inputBorderWidth}px;
|
||||
border-color: ${theme.inputBorderColor};
|
||||
border-radius: ${theme.inputBorderRadius}px;
|
||||
}
|
||||
|
||||
.form-control:focus,
|
||||
input.form-control:focus {
|
||||
outline: 0;
|
||||
${theme.inputFocusedStyle}
|
||||
}
|
||||
.form-control:focus,
|
||||
input.form-control:focus {
|
||||
outline: 0;
|
||||
${theme.inputFocusedStyle}
|
||||
}
|
||||
|
||||
.form-control[disabled],
|
||||
.form-control[readonly],
|
||||
fieldset[disabled] .form-control {
|
||||
background-color: transparent;
|
||||
opacity: 1;
|
||||
}
|
||||
.form-control[disabled],
|
||||
.form-control[readonly],
|
||||
fieldset[disabled] .form-control {
|
||||
background-color: transparent;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.form-control[disabled],
|
||||
fieldset[disabled] .form-control {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.form-control[disabled],
|
||||
fieldset[disabled] .form-control {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
}
|
||||
textarea.form-control {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.radio,
|
||||
.checkbox {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.radio,
|
||||
.checkbox {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.radio label,
|
||||
.checkbox label {
|
||||
min-height: 23px;
|
||||
padding-left: 20px;
|
||||
margin-bottom: 0;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
.radio label,
|
||||
.checkbox label {
|
||||
min-height: 23px;
|
||||
padding-left: 20px;
|
||||
margin-bottom: 0;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.radio input[type="radio"],
|
||||
.radio-inline input[type="radio"],
|
||||
.checkbox input[type="checkbox"],
|
||||
.checkbox-inline input[type="checkbox"] {
|
||||
position: absolute;
|
||||
margin-left: -20px;
|
||||
margin-top: 4px \\9;
|
||||
}
|
||||
.radio input[type='radio'],
|
||||
.radio-inline input[type='radio'],
|
||||
.checkbox input[type='checkbox'],
|
||||
.checkbox-inline input[type='checkbox'] {
|
||||
position: absolute;
|
||||
margin-left: -20px;
|
||||
margin-top: 4px \\9;
|
||||
}
|
||||
|
||||
.radio + .radio,
|
||||
.checkbox + .checkbox {
|
||||
margin-top: -5px;
|
||||
}
|
||||
.radio + .radio,
|
||||
.checkbox + .checkbox {
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.radio-inline,
|
||||
.checkbox-inline {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding-left: 25px;
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
.radio-inline,
|
||||
.checkbox-inline {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding-left: 25px;
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.radio-inline + .radio-inline,
|
||||
.checkbox-inline + .checkbox-inline {
|
||||
margin-top: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.radio-inline + .radio-inline,
|
||||
.checkbox-inline + .checkbox-inline {
|
||||
margin-top: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.radio label,
|
||||
.radio-inline label,
|
||||
.checkbox label,
|
||||
.checkbox-inline label {
|
||||
padding-left: 25px;
|
||||
}
|
||||
.radio label,
|
||||
.radio-inline label,
|
||||
.checkbox label,
|
||||
.checkbox-inline label {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.radio input[type="radio"],
|
||||
.radio-inline input[type="radio"],
|
||||
.checkbox input[type="radio"],
|
||||
.checkbox-inline input[type="radio"],
|
||||
.radio input[type="checkbox"],
|
||||
.radio-inline input[type="checkbox"],
|
||||
.checkbox input[type="checkbox"],
|
||||
.checkbox-inline input[type="checkbox"] {
|
||||
margin-left: -25px;
|
||||
}
|
||||
.radio input[type='radio'],
|
||||
.radio-inline input[type='radio'],
|
||||
.checkbox input[type='radio'],
|
||||
.checkbox-inline input[type='radio'],
|
||||
.radio input[type='checkbox'],
|
||||
.radio-inline input[type='checkbox'],
|
||||
.checkbox input[type='checkbox'],
|
||||
.checkbox-inline input[type='checkbox'] {
|
||||
margin-left: -25px;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
.radio input[type="radio"],
|
||||
.radio-inline input[type="radio"] {
|
||||
position: relative;
|
||||
margin-top: 6px;
|
||||
margin-right: 4px;
|
||||
vertical-align: top;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type='radio'],
|
||||
.radio input[type='radio'],
|
||||
.radio-inline input[type='radio'] {
|
||||
position: relative;
|
||||
margin-top: 6px;
|
||||
margin-right: 4px;
|
||||
vertical-align: top;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="radio"]:focus,
|
||||
.radio input[type="radio"]:focus,
|
||||
.radio-inline input[type="radio"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
input[type='radio']:focus,
|
||||
.radio input[type='radio']:focus,
|
||||
.radio-inline input[type='radio']:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type="radio"]:before,
|
||||
.radio input[type="radio"]:before,
|
||||
.radio-inline input[type="radio"]:before,
|
||||
input[type="radio"]:after,
|
||||
.radio input[type="radio"]:after,
|
||||
.radio-inline input[type="radio"]:after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
transition: 240ms;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input[type='radio']:before,
|
||||
.radio input[type='radio']:before,
|
||||
.radio-inline input[type='radio']:before,
|
||||
input[type='radio']:after,
|
||||
.radio input[type='radio']:after,
|
||||
.radio-inline input[type='radio']:after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
transition: 240ms;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input[type="radio"]:before,
|
||||
.radio input[type="radio"]:before,
|
||||
.radio-inline input[type="radio"]:before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -3px;
|
||||
background-color: ${theme.base0D};
|
||||
transform: scale(0);
|
||||
}
|
||||
input[type='radio']:before,
|
||||
.radio input[type='radio']:before,
|
||||
.radio-inline input[type='radio']:before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -3px;
|
||||
background-color: ${theme.base0D};
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
input[type="radio"]:after,
|
||||
.radio input[type="radio"]:after,
|
||||
.radio-inline input[type="radio"]:after {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
border: 2px solid ${theme.base03};
|
||||
}
|
||||
input[type='radio']:after,
|
||||
.radio input[type='radio']:after,
|
||||
.radio-inline input[type='radio']:after {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
border: 2px solid ${theme.base03};
|
||||
}
|
||||
|
||||
input[type="radio"]:checked:before,
|
||||
.radio input[type="radio"]:checked:before,
|
||||
.radio-inline input[type="radio"]:checked:before {
|
||||
transform: scale(0.5);
|
||||
}
|
||||
input[type='radio']:checked:before,
|
||||
.radio input[type='radio']:checked:before,
|
||||
.radio-inline input[type='radio']:checked:before {
|
||||
transform: scale(0.5);
|
||||
}
|
||||
|
||||
input[type="radio"]:disabled:checked:before,
|
||||
.radio input[type="radio"]:disabled:checked:before,
|
||||
.radio-inline input[type="radio"]:disabled:checked:before {
|
||||
background-color: ${theme.base03};
|
||||
}
|
||||
input[type='radio']:disabled:checked:before,
|
||||
.radio input[type='radio']:disabled:checked:before,
|
||||
.radio-inline input[type='radio']:disabled:checked:before {
|
||||
background-color: ${theme.base03};
|
||||
}
|
||||
|
||||
input[type="radio"]:checked:after,
|
||||
.radio input[type="radio"]:checked:after,
|
||||
.radio-inline input[type="radio"]:checked:after {
|
||||
border-color: ${theme.base0D};
|
||||
}
|
||||
input[type='radio']:checked:after,
|
||||
.radio input[type='radio']:checked:after,
|
||||
.radio-inline input[type='radio']:checked:after {
|
||||
border-color: ${theme.base0D};
|
||||
}
|
||||
|
||||
input[type="radio"]:disabled:after,
|
||||
.radio input[type="radio"]:disabled:after,
|
||||
.radio-inline input[type="radio"]:disabled:after,
|
||||
input[type="radio"]:disabled:checked:after,
|
||||
.radio input[type="radio"]:disabled:checked:after,
|
||||
.radio-inline input[type="radio"]:disabled:checked:after {
|
||||
border-color: ${theme.base03};
|
||||
}
|
||||
input[type='radio']:disabled:after,
|
||||
.radio input[type='radio']:disabled:after,
|
||||
.radio-inline input[type='radio']:disabled:after,
|
||||
input[type='radio']:disabled:checked:after,
|
||||
.radio input[type='radio']:disabled:checked:after,
|
||||
.radio-inline input[type='radio']:disabled:checked:after {
|
||||
border-color: ${theme.base03};
|
||||
}
|
||||
|
||||
input[type="checkbox"],
|
||||
.checkbox input[type="checkbox"],
|
||||
.checkbox-inline input[type="checkbox"] {
|
||||
position: relative;
|
||||
border: none;
|
||||
margin-bottom: -4px;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type='checkbox'],
|
||||
.checkbox input[type='checkbox'],
|
||||
.checkbox-inline input[type='checkbox'] {
|
||||
position: relative;
|
||||
border: none;
|
||||
margin-bottom: -4px;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:focus,
|
||||
.checkbox input[type="checkbox"]:focus,
|
||||
.checkbox-inline input[type="checkbox"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
input[type='checkbox']:focus,
|
||||
.checkbox input[type='checkbox']:focus,
|
||||
.checkbox-inline input[type='checkbox']:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:focus:after,
|
||||
.checkbox input[type="checkbox"]:focus:after,
|
||||
.checkbox-inline input[type="checkbox"]:focus:after {
|
||||
border-color: ${theme.base0D};
|
||||
}
|
||||
input[type='checkbox']:focus:after,
|
||||
.checkbox input[type='checkbox']:focus:after,
|
||||
.checkbox-inline input[type='checkbox']:focus:after {
|
||||
border-color: ${theme.base0D};
|
||||
}
|
||||
|
||||
input[type="checkbox"]:after,
|
||||
.checkbox input[type="checkbox"]:after,
|
||||
.checkbox-inline input[type="checkbox"]:after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-top: -2px;
|
||||
margin-right: 5px;
|
||||
border: 2px solid ${theme.base03};
|
||||
border-radius: 4px;
|
||||
transition: 240ms;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input[type='checkbox']:after,
|
||||
.checkbox input[type='checkbox']:after,
|
||||
.checkbox-inline input[type='checkbox']:after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-top: -2px;
|
||||
margin-right: 5px;
|
||||
border: 2px solid ${theme.base03};
|
||||
border-radius: 4px;
|
||||
transition: 240ms;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked:before,
|
||||
.checkbox input[type="checkbox"]:checked:before,
|
||||
.checkbox-inline input[type="checkbox"]:checked:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 6px;
|
||||
display: table;
|
||||
width: 6px;
|
||||
height: 12px;
|
||||
border: 2px solid #fff;
|
||||
border-top-width: 0;
|
||||
border-left-width: 0;
|
||||
transform: rotate(45deg);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input[type='checkbox']:checked:before,
|
||||
.checkbox input[type='checkbox']:checked:before,
|
||||
.checkbox-inline input[type='checkbox']:checked:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 6px;
|
||||
display: table;
|
||||
width: 6px;
|
||||
height: 12px;
|
||||
border: 2px solid #fff;
|
||||
border-top-width: 0;
|
||||
border-left-width: 0;
|
||||
transform: rotate(45deg);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked:after,
|
||||
.checkbox input[type="checkbox"]:checked:after,
|
||||
.checkbox-inline input[type="checkbox"]:checked:after {
|
||||
background-color: ${theme.base0D};
|
||||
border-color: ${theme.base0D};
|
||||
}
|
||||
input[type='checkbox']:checked:after,
|
||||
.checkbox input[type='checkbox']:checked:after,
|
||||
.checkbox-inline input[type='checkbox']:checked:after {
|
||||
background-color: ${theme.base0D};
|
||||
border-color: ${theme.base0D};
|
||||
}
|
||||
|
||||
input[type="checkbox"]:disabled:after,
|
||||
.checkbox input[type="checkbox"]:disabled:after,
|
||||
.checkbox-inline input[type="checkbox"]:disabled:after {
|
||||
border-color: ${theme.base03};
|
||||
}
|
||||
input[type='checkbox']:disabled:after,
|
||||
.checkbox input[type='checkbox']:disabled:after,
|
||||
.checkbox-inline input[type='checkbox']:disabled:after {
|
||||
border-color: ${theme.base03};
|
||||
}
|
||||
|
||||
input[type="checkbox"]:disabled:checked:after,
|
||||
.checkbox input[type="checkbox"]:disabled:checked:after,
|
||||
.checkbox-inline input[type="checkbox"]:disabled:checked:after {
|
||||
background-color: ${theme.base03};
|
||||
border-color: transparent;
|
||||
}
|
||||
input[type='checkbox']:disabled:checked:after,
|
||||
.checkbox input[type='checkbox']:disabled:checked:after,
|
||||
.checkbox-inline input[type='checkbox']:disabled:checked:after {
|
||||
background-color: ${theme.base03};
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
input[type="radio"][disabled],
|
||||
input[type="checkbox"][disabled],
|
||||
input[type="radio"].disabled,
|
||||
input[type="checkbox"].disabled,
|
||||
fieldset[disabled] input[type="radio"],
|
||||
fieldset[disabled] input[type="checkbox"] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
input[type='radio'][disabled],
|
||||
input[type='checkbox'][disabled],
|
||||
input[type='radio'].disabled,
|
||||
input[type='checkbox'].disabled,
|
||||
fieldset[disabled] input[type='radio'],
|
||||
fieldset[disabled] input[type='checkbox'] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.radio-inline.disabled,
|
||||
.checkbox-inline.disabled,
|
||||
fieldset[disabled] .radio-inline,
|
||||
fieldset[disabled] .checkbox-inline {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.radio-inline.disabled,
|
||||
.checkbox-inline.disabled,
|
||||
fieldset[disabled] .radio-inline,
|
||||
fieldset[disabled] .checkbox-inline {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.radio.disabled label,
|
||||
.checkbox.disabled label,
|
||||
fieldset[disabled] .radio label,
|
||||
fieldset[disabled] .checkbox label {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.radio.disabled label,
|
||||
.checkbox.disabled label,
|
||||
fieldset[disabled] .radio label,
|
||||
fieldset[disabled] .checkbox label {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.has-error .help-block,
|
||||
.has-error .control-label,
|
||||
.has-error .radio,
|
||||
.has-error .checkbox,
|
||||
.has-error .radio-inline,
|
||||
.has-error .checkbox-inline,
|
||||
.has-error.radio label,
|
||||
.has-error.checkbox label,
|
||||
.has-error.radio-inline label,
|
||||
.has-error.checkbox-inline label {
|
||||
color: ${theme.base08};
|
||||
}
|
||||
.has-error .help-block,
|
||||
.has-error .control-label,
|
||||
.has-error .radio,
|
||||
.has-error .checkbox,
|
||||
.has-error .radio-inline,
|
||||
.has-error .checkbox-inline,
|
||||
.has-error.radio label,
|
||||
.has-error.checkbox label,
|
||||
.has-error.radio-inline label,
|
||||
.has-error.checkbox-inline label {
|
||||
color: ${theme.base08};
|
||||
}
|
||||
|
||||
.panel {
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 4px ${theme.base03};
|
||||
margin-bottom: 23px;
|
||||
}
|
||||
.panel {
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 4px ${theme.base03};
|
||||
margin-bottom: 23px;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
padding: 5px 15px;
|
||||
}
|
||||
.panel-heading {
|
||||
padding: 5px 15px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
.panel-title {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.panel-danger {
|
||||
box-shadow: 0 1px 4px ${theme.base08};
|
||||
}
|
||||
.panel-danger {
|
||||
box-shadow: 0 1px 4px ${theme.base08};
|
||||
}
|
||||
|
||||
.panel-danger>.panel-heading {
|
||||
color: ${theme.base00};
|
||||
background-color: ${theme.base08};
|
||||
}
|
||||
.panel-danger > .panel-heading {
|
||||
color: ${theme.base00};
|
||||
background-color: ${theme.base08};
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: ${theme.base08};
|
||||
}
|
||||
.text-danger {
|
||||
color: ${theme.base08};
|
||||
}
|
||||
|
||||
.list-group {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.list-group {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.list-group-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -8,7 +8,9 @@ const SelectWidget = ({ options, multi, ...rest }) => (
|
|||
);
|
||||
|
||||
const RangeWidget = ({
|
||||
schema, readonly, autofocus,
|
||||
schema,
|
||||
readonly,
|
||||
autofocus,
|
||||
label, // eslint-disable-line
|
||||
options, // eslint-disable-line
|
||||
formContext, // eslint-disable-line
|
||||
|
|
|
@ -11,16 +11,22 @@ const NotificationWrapper = createStyledComponent(styles);
|
|||
|
||||
export default class Notification extends Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return nextProps.children !== this.props.children ||
|
||||
nextProps.type !== this.props.type;
|
||||
return (
|
||||
nextProps.children !== this.props.children ||
|
||||
nextProps.type !== this.props.type
|
||||
);
|
||||
}
|
||||
|
||||
getIcon = () => {
|
||||
switch (this.props.type) {
|
||||
case 'warning': return <WarningIcon />;
|
||||
case 'error': return <ErrorIcon />;
|
||||
case 'success': return <SuccessIcon />;
|
||||
default: return null;
|
||||
case 'warning':
|
||||
return <WarningIcon />;
|
||||
case 'error':
|
||||
return <ErrorIcon />;
|
||||
case 'success':
|
||||
return <SuccessIcon />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -29,9 +35,11 @@ export default class Notification extends Component {
|
|||
<NotificationWrapper type={this.props.type} theme={this.props.theme}>
|
||||
{this.getIcon()}
|
||||
<span>{this.props.children}</span>
|
||||
{this.props.onClose &&
|
||||
<button onClick={this.props.onClose}><CloseIcon /></button>
|
||||
}
|
||||
{this.props.onClose && (
|
||||
<button onClick={this.props.onClose}>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
)}
|
||||
</NotificationWrapper>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,18 +15,17 @@ export const Container = styled.div`
|
|||
|
||||
storiesOf('Notification', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add(
|
||||
'default',
|
||||
() => (
|
||||
<Container>
|
||||
<Notification
|
||||
type={
|
||||
select('type', ['info', 'success', 'warning', 'error'], 'warning')
|
||||
}
|
||||
onClose={action('notification closed')}
|
||||
>
|
||||
{text('Message', 'Hello Notification')}
|
||||
</Notification>
|
||||
</Container>
|
||||
)
|
||||
);
|
||||
.add('default', () => (
|
||||
<Container>
|
||||
<Notification
|
||||
type={select(
|
||||
'type',
|
||||
['info', 'success', 'warning', 'error'],
|
||||
'warning'
|
||||
)}
|
||||
onClose={action('notification closed')}
|
||||
>
|
||||
{text('Message', 'Hello Notification')}
|
||||
</Notification>
|
||||
</Container>
|
||||
));
|
||||
|
|
|
@ -49,7 +49,8 @@ export default ({ theme, type }) => css`
|
|||
opacity: 0.8;
|
||||
}
|
||||
|
||||
& > button:hover, & > button:active {
|
||||
& > button:hover,
|
||||
& > button:active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,10 @@ const SegmentedWrapper = createStyledComponent(styles);
|
|||
|
||||
export default class SegmentedControl extends Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return nextProps.disabled !== this.props.disabled ||
|
||||
nextProps.selected !== this.props.selected;
|
||||
return (
|
||||
nextProps.disabled !== this.props.disabled ||
|
||||
nextProps.selected !== this.props.selected
|
||||
);
|
||||
}
|
||||
|
||||
onClick = e => {
|
||||
|
|
|
@ -15,16 +15,13 @@ export const Container = styled.div`
|
|||
|
||||
storiesOf('SegmentedControl', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add(
|
||||
'default',
|
||||
() => (
|
||||
<Container>
|
||||
<SegmentedControl
|
||||
values={['Button1', 'Button2', 'Button3']}
|
||||
selected={text('selected', 'Button1')}
|
||||
onClick={action('button selected')}
|
||||
disabled={boolean('Disabled', false)}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
);
|
||||
.add('default', () => (
|
||||
<Container>
|
||||
<SegmentedControl
|
||||
values={['Button1', 'Button2', 'Button3']}
|
||||
selected={text('selected', 'Button1')}
|
||||
onClick={action('button selected')}
|
||||
disabled={boolean('Disabled', false)}
|
||||
/>
|
||||
</Container>
|
||||
));
|
||||
|
|
|
@ -5,7 +5,8 @@ export default ({ theme, disabled }) => css`
|
|||
display: flex;
|
||||
flex-shrink: 0;
|
||||
|
||||
> [data-selected], > [data-selected]:hover {
|
||||
> [data-selected],
|
||||
> [data-selected]:hover {
|
||||
background-color: ${theme.base04};
|
||||
color: ${theme.base00};
|
||||
}
|
||||
|
@ -19,10 +20,12 @@ export default ({ theme, disabled }) => css`
|
|||
border: 1px solid ${color(theme.base03, 'alpha', 0.4)};
|
||||
border-left-width: 0;
|
||||
padding: 5px 10px;
|
||||
${disabled ? `
|
||||
${disabled
|
||||
? `
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
` : `
|
||||
`
|
||||
: `
|
||||
cursor: pointer;
|
||||
color: ${theme.base05};
|
||||
background-color: ${theme.base01};
|
||||
|
|
|
@ -13,17 +13,22 @@ export default class Select extends (PureComponent || Component) {
|
|||
}
|
||||
|
||||
Select.propTypes = {
|
||||
autosize: PropTypes.bool, // whether to enable autosizing or not
|
||||
clearable: PropTypes.bool, // should it be possible to reset value
|
||||
disabled: PropTypes.bool, // whether the Select is disabled or not
|
||||
isLoading: PropTypes.bool, // whether the Select is loading externally or not
|
||||
menuMaxHeight: PropTypes.number, // maximum css height for the opened menu of options
|
||||
multi: PropTypes.bool, // multi-value input
|
||||
searchable: PropTypes.bool, // whether to enable searching feature or not
|
||||
simpleValue: PropTypes.bool, // pass the value with label to onChange
|
||||
value: PropTypes.any, // initial field value
|
||||
valueKey: PropTypes.string, // path of the label value in option objects
|
||||
openOuterUp: PropTypes.bool // value to control the opening direction
|
||||
autosize: PropTypes.bool, // whether to enable autosizing or not
|
||||
clearable: PropTypes.bool, // should it be possible to reset value
|
||||
disabled: PropTypes.bool, // whether the Select is disabled or not
|
||||
isLoading: PropTypes.bool, // whether the Select is loading externally or not
|
||||
menuMaxHeight: PropTypes.number, // maximum css height for the opened menu of options
|
||||
multi: PropTypes.bool, // multi-value input
|
||||
searchable: PropTypes.bool, // whether to enable searching feature or not
|
||||
simpleValue: PropTypes.bool, // pass the value with label to onChange
|
||||
value: PropTypes.any, // initial field value
|
||||
valueKey: PropTypes.string, // path of the label value in option objects
|
||||
openOuterUp: PropTypes.bool // value to control the opening direction
|
||||
};
|
||||
|
||||
Select.defaultProps = { autosize: true, clearable: false, simpleValue: true, menuMaxHeight: 200 };
|
||||
Select.defaultProps = {
|
||||
autosize: true,
|
||||
clearable: false,
|
||||
simpleValue: true,
|
||||
menuMaxHeight: 200
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ export const Container = styled.div`
|
|||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
|
||||
> div {
|
||||
width: 90%;
|
||||
}
|
||||
|
@ -39,8 +39,9 @@ storiesOf('Select', module)
|
|||
/>
|
||||
</Container>
|
||||
),
|
||||
{ info:
|
||||
'Wrapper around [React Select](https://github.com/JedWatson/react-select) with themes '
|
||||
+ 'and new props like `openOuterUp` and `menuMaxHeight`.'
|
||||
{
|
||||
info:
|
||||
'Wrapper around [React Select](https://github.com/JedWatson/react-select) with themes ' +
|
||||
'and new props like `openOuterUp` and `menuMaxHeight`.'
|
||||
}
|
||||
);
|
||||
|
|
|
@ -59,10 +59,9 @@ export default ({ theme, openOuterUp, menuMaxHeight }) => css`
|
|||
}
|
||||
|
||||
&.is-open > .Select-control {
|
||||
border-radius: ${openOuterUp ?
|
||||
`0 0 ${theme.inputBorderRadius}px ${theme.inputBorderRadius}px` :
|
||||
`${theme.inputBorderRadius}px ${theme.inputBorderRadius}px 0 0`
|
||||
};
|
||||
border-radius: ${openOuterUp
|
||||
? `0 0 ${theme.inputBorderRadius}px ${theme.inputBorderRadius}px`
|
||||
: `${theme.inputBorderRadius}px ${theme.inputBorderRadius}px 0 0`};
|
||||
}
|
||||
|
||||
&.is-searchable {
|
||||
|
@ -212,9 +211,7 @@ export default ({ theme, openOuterUp, menuMaxHeight }) => css`
|
|||
.Select-arrow {
|
||||
border-color: ${theme.base03} transparent transparent;
|
||||
border-style: solid;
|
||||
border-width:
|
||||
${theme.selectArrowWidth}px
|
||||
${theme.selectArrowWidth}px
|
||||
border-width: ${theme.selectArrowWidth}px ${theme.selectArrowWidth}px
|
||||
${theme.selectArrowWidth / 2}px;
|
||||
display: inline-block;
|
||||
height: 0;
|
||||
|
@ -317,7 +314,8 @@ export default ({ theme, openOuterUp, menuMaxHeight }) => css`
|
|||
border-bottom-right-radius: ${theme.inputBorderRadius}px;
|
||||
border-top-right-radius: ${theme.inputBorderRadius}px;
|
||||
cursor: default;
|
||||
padding: ${Math.floor(theme.inputPadding / 4)}px ${Math.floor(theme.inputPadding / 2)}px;
|
||||
padding: ${Math.floor(theme.inputPadding / 4)}px
|
||||
${Math.floor(theme.inputPadding / 2)}px;
|
||||
}
|
||||
|
||||
a.Select-value-label {
|
||||
|
|
|
@ -9,12 +9,14 @@ const ContainerWithValue = createStyledComponent(containerStyle);
|
|||
|
||||
export default class Slider extends Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return nextProps.label !== this.props.label ||
|
||||
return (
|
||||
nextProps.label !== this.props.label ||
|
||||
nextProps.value !== this.props.value ||
|
||||
nextProps.max !== this.props.max ||
|
||||
nextProps.min !== this.props.min ||
|
||||
nextProps.withValue !== this.props.withValue ||
|
||||
nextProps.disabled !== this.props.disabled;
|
||||
nextProps.disabled !== this.props.disabled
|
||||
);
|
||||
}
|
||||
|
||||
onChange = e => {
|
||||
|
@ -25,7 +27,7 @@ export default class Slider extends Component {
|
|||
const { label, sublabel, withValue, theme, ...rest } = this.props;
|
||||
const { value, max, min, disabled } = rest;
|
||||
const absMax = max - min;
|
||||
const percent = (value - min) / absMax * 100;
|
||||
const percent = ((value - min) / absMax) * 100;
|
||||
const slider = <input {...rest} onChange={this.onChange} type="range" />;
|
||||
|
||||
return (
|
||||
|
@ -35,13 +37,19 @@ export default class Slider extends Component {
|
|||
withLabel={!!label}
|
||||
theme={theme}
|
||||
>
|
||||
{label && <label>{label} {sublabel && <span>{sublabel}</span>}</label>}
|
||||
{!withValue ? slider :
|
||||
{label && (
|
||||
<label>
|
||||
{label} {sublabel && <span>{sublabel}</span>}
|
||||
</label>
|
||||
)}
|
||||
{!withValue ? (
|
||||
slider
|
||||
) : (
|
||||
<ContainerWithValue theme={theme}>
|
||||
{slider}
|
||||
<div>{value}</div>
|
||||
</ContainerWithValue>
|
||||
}
|
||||
)}
|
||||
</SliderWrapper>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,20 +15,17 @@ export const Container = styled.div`
|
|||
|
||||
storiesOf('Slider', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add(
|
||||
'default',
|
||||
() => (
|
||||
<Container>
|
||||
<Slider
|
||||
value={number('value', 0)}
|
||||
min={number('min', 0)}
|
||||
max={number('max', 100)}
|
||||
label={text('label', 'Slider label')}
|
||||
sublabel={text('sublabel', '(sublabel)')}
|
||||
withValue={boolean('withValue', false)}
|
||||
disabled={boolean('disabled', false)}
|
||||
onChange={action('slider changed')}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
);
|
||||
.add('default', () => (
|
||||
<Container>
|
||||
<Slider
|
||||
value={number('value', 0)}
|
||||
min={number('min', 0)}
|
||||
max={number('max', 100)}
|
||||
label={text('label', 'Slider label')}
|
||||
sublabel={text('sublabel', '(sublabel)')}
|
||||
withValue={boolean('withValue', false)}
|
||||
disabled={boolean('disabled', false)}
|
||||
onChange={action('slider changed')}
|
||||
/>
|
||||
</Container>
|
||||
));
|
||||
|
|
|
@ -42,21 +42,32 @@ export const style = ({ theme, percent, disabled, withLabel }) => css`
|
|||
border-radius: 0.8em/1.1em;
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
background: linear-gradient(${theme.base02}, ${theme.base00}) padding-box, 50% 50% border-box;
|
||||
background: linear-gradient(${theme.base02}, ${
|
||||
theme.base00
|
||||
}) padding-box, 50% 50% border-box;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
${prefixSelectors('input', ['webkit-slider-runnable-track', 'moz-range-track', 'ms-track'], `{
|
||||
${prefixSelectors(
|
||||
'input',
|
||||
['webkit-slider-runnable-track', 'moz-range-track', 'ms-track'],
|
||||
`{
|
||||
position: relative;
|
||||
height: 0.8em;
|
||||
border-radius: 0.5em;
|
||||
box-shadow: 0 0 .125em ${theme.base04};
|
||||
background: linear-gradient(${theme.base01}, ${theme.base02} 40%, ${theme.base01})
|
||||
background: linear-gradient(${theme.base01}, ${theme.base02} 40%, ${
|
||||
theme.base01
|
||||
})
|
||||
no-repeat ${theme.base00};
|
||||
background-size: ${percent}% 100%;
|
||||
}`)}
|
||||
}`
|
||||
)}
|
||||
|
||||
${prefixSelectors('input', ['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'], `{
|
||||
${prefixSelectors(
|
||||
'input',
|
||||
['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],
|
||||
`{
|
||||
position: relative;
|
||||
appearance: none;
|
||||
cursor: ew-resize;
|
||||
|
@ -68,13 +79,16 @@ export const style = ({ theme, percent, disabled, withLabel }) => css`
|
|||
height: 1.5em;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}`)}
|
||||
}`
|
||||
)}
|
||||
|
||||
${prefixSelectors('input:focus:not(:active)',
|
||||
['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],
|
||||
`{
|
||||
${prefixSelectors(
|
||||
'input:focus:not(:active)',
|
||||
['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],
|
||||
`{
|
||||
box-shadow: 0 0 1px 2px ${theme.base0D};
|
||||
}`)}
|
||||
}`
|
||||
)}
|
||||
|
||||
input::-moz-focus-outer {
|
||||
border: 0;
|
||||
|
|
|
@ -19,7 +19,9 @@ export const style = ({ theme, percent, disabled, withLabel }) => css`
|
|||
width: 100%;
|
||||
color: ${theme.base06};
|
||||
|
||||
> span { color: ${theme.base04}; }
|
||||
> span {
|
||||
color: ${theme.base04};
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
|
@ -32,8 +34,12 @@ export const style = ({ theme, percent, disabled, withLabel }) => css`
|
|||
cursor: pointer;
|
||||
color: inherit;
|
||||
background-color: ${theme.base02};
|
||||
background-image:
|
||||
linear-gradient(90deg, currentcolor, currentcolor ${percent}%, transparent ${percent}%);
|
||||
background-image: linear-gradient(
|
||||
90deg,
|
||||
currentcolor,
|
||||
currentcolor ${percent}%,
|
||||
transparent ${percent}%
|
||||
);
|
||||
background-clip: content-box;
|
||||
height: 0.5em;
|
||||
border-radius: 999px;
|
||||
|
@ -41,7 +47,10 @@ export const style = ({ theme, percent, disabled, withLabel }) => css`
|
|||
font-size: 1em;
|
||||
}
|
||||
|
||||
${prefixSelectors('input', ['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'], `{
|
||||
${prefixSelectors(
|
||||
'input',
|
||||
['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],
|
||||
`{
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
background-image: none;
|
||||
|
@ -53,14 +62,17 @@ export const style = ({ theme, percent, disabled, withLabel }) => css`
|
|||
border 0.18s ${animationCurve},
|
||||
box-shadow 0.18s ${animationCurve},
|
||||
background 0.28s ${animationCurve};
|
||||
}`)}
|
||||
}`
|
||||
)}
|
||||
|
||||
${prefixSelectors('input:focus:not(:active)',
|
||||
['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],
|
||||
`{
|
||||
${prefixSelectors(
|
||||
'input:focus:not(:active)',
|
||||
['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],
|
||||
`{
|
||||
box-shadow: 0 0 0 8px ${color(theme.base0D, 'alpha', 0.5)};
|
||||
transform: scale(1.2);
|
||||
}`)}
|
||||
}`
|
||||
)}
|
||||
|
||||
input::-moz-focus-outer {
|
||||
border: 0;
|
||||
|
|
|
@ -75,7 +75,9 @@ export default class Tabs extends Component {
|
|||
return (
|
||||
<TabsContainer position={this.props.position}>
|
||||
{tabsHeader}
|
||||
<div><this.SelectedComponent {...(this.selector && this.selector())} /></div>
|
||||
<div>
|
||||
<this.SelectedComponent {...this.selector && this.selector()} />
|
||||
</div>
|
||||
</TabsContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -22,9 +22,11 @@ export default class TabsHeader extends Component {
|
|||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.tabs !== this.props.tabs ||
|
||||
if (
|
||||
nextProps.tabs !== this.props.tabs ||
|
||||
nextProps.selected !== this.props.selected ||
|
||||
nextProps.collapsible !== this.props.collapsible) {
|
||||
nextProps.collapsible !== this.props.collapsible
|
||||
) {
|
||||
this.setState({ hiddenTabs: [], visibleTabs: nextProps.tabs.slice() });
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +49,9 @@ export default class TabsHeader extends Component {
|
|||
if (this.iconWidth === 0) {
|
||||
const tabButtons = this.tabsRef.children;
|
||||
if (this.tabsRef.children[tabButtons.length - 1].value === 'expandIcon') {
|
||||
this.iconWidth = tabButtons[tabButtons.length - 1].getBoundingClientRect().width;
|
||||
this.iconWidth = tabButtons[
|
||||
tabButtons.length - 1
|
||||
].getBoundingClientRect().width;
|
||||
shouldCollapse = true;
|
||||
}
|
||||
} else if (this.state.hiddenTabs.length === 0) {
|
||||
|
@ -96,14 +100,15 @@ export default class TabsHeader extends Component {
|
|||
|
||||
if (tabsRefRight >= tabsWrapperRight - this.iconWidth) {
|
||||
if (
|
||||
this.props.position === 'right' && hiddenTabs.length > 0 &&
|
||||
this.props.position === 'right' &&
|
||||
hiddenTabs.length > 0 &&
|
||||
tabsRef.getBoundingClientRect().width + this.hiddenTabsWidth[0] <
|
||||
tabsWrapperRef.getBoundingClientRect().width
|
||||
tabsWrapperRef.getBoundingClientRect().width
|
||||
) {
|
||||
while (
|
||||
i < tabs.length - 1 &&
|
||||
tabsRef.getBoundingClientRect().width + this.hiddenTabsWidth[0] <
|
||||
tabsWrapperRef.getBoundingClientRect().width
|
||||
tabsWrapperRef.getBoundingClientRect().width
|
||||
) {
|
||||
hiddenTab = hiddenTabs.shift();
|
||||
visibleTabs.splice(Number(hiddenTab.key), 0, hiddenTab);
|
||||
|
@ -111,12 +116,16 @@ export default class TabsHeader extends Component {
|
|||
}
|
||||
} else {
|
||||
while (
|
||||
i > 0 && tabButtons[i] &&
|
||||
tabButtons[i].getBoundingClientRect().right >= tabsWrapperRight - this.iconWidth
|
||||
i > 0 &&
|
||||
tabButtons[i] &&
|
||||
tabButtons[i].getBoundingClientRect().right >=
|
||||
tabsWrapperRight - this.iconWidth
|
||||
) {
|
||||
if (tabButtons[i].value !== selected) {
|
||||
hiddenTabs.unshift(...visibleTabs.splice(i, 1));
|
||||
this.hiddenTabsWidth.unshift(tabButtons[i].getBoundingClientRect().width);
|
||||
this.hiddenTabsWidth.unshift(
|
||||
tabButtons[i].getBoundingClientRect().width
|
||||
);
|
||||
} else {
|
||||
tabsWrapperRight -= tabButtons[i].getBoundingClientRect().width;
|
||||
}
|
||||
|
@ -125,9 +134,10 @@ export default class TabsHeader extends Component {
|
|||
}
|
||||
} else {
|
||||
while (
|
||||
i < tabs.length - 1 && tabButtons[i] &&
|
||||
tabButtons[i].getBoundingClientRect().right +
|
||||
this.hiddenTabsWidth[0] < tabsWrapperRight - this.iconWidth
|
||||
i < tabs.length - 1 &&
|
||||
tabButtons[i] &&
|
||||
tabButtons[i].getBoundingClientRect().right + this.hiddenTabsWidth[0] <
|
||||
tabsWrapperRight - this.iconWidth
|
||||
) {
|
||||
hiddenTab = hiddenTabs.shift();
|
||||
visibleTabs.splice(Number(hiddenTab.key), 0, hiddenTab);
|
||||
|
@ -150,7 +160,7 @@ export default class TabsHeader extends Component {
|
|||
this.tabsRef = node;
|
||||
};
|
||||
|
||||
expandMenu = (e) => {
|
||||
expandMenu = e => {
|
||||
const rect = e.currentTarget.children[0].getBoundingClientRect();
|
||||
this.setState({
|
||||
contextMenu: {
|
||||
|
@ -171,11 +181,14 @@ export default class TabsHeader extends Component {
|
|||
>
|
||||
<div ref={this.getTabsRef}>
|
||||
{visibleTabs}
|
||||
{this.props.collapsible && visibleTabs.length < this.props.items.length &&
|
||||
<button onClick={this.expandMenu} value="expandIcon"><CollapseIcon /></button>
|
||||
}
|
||||
{this.props.collapsible &&
|
||||
visibleTabs.length < this.props.items.length && (
|
||||
<button onClick={this.expandMenu} value="expandIcon">
|
||||
<CollapseIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{this.props.collapsible && contextMenu &&
|
||||
{this.props.collapsible && contextMenu && (
|
||||
<ContextMenu
|
||||
items={hiddenTabs}
|
||||
onClick={this.props.onClick}
|
||||
|
@ -183,7 +196,7 @@ export default class TabsHeader extends Component {
|
|||
y={contextMenu.top}
|
||||
visible={this.state.subMenuOpened}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</TabsWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -198,4 +211,3 @@ TabsHeader.propTypes = {
|
|||
collapsible: PropTypes.bool,
|
||||
selected: PropTypes.string
|
||||
};
|
||||
|
||||
|
|
|
@ -38,4 +38,5 @@ export const tabs = [
|
|||
];
|
||||
|
||||
export const simple10Tabs = [];
|
||||
for (let i = 1; i <= 10; i++) simple10Tabs.push({ name: `Tab${i}`, value: `${i}` });
|
||||
for (let i = 1; i <= 10; i++)
|
||||
simple10Tabs.push({ name: `Tab${i}`, value: `${i}` });
|
||||
|
|
|
@ -16,29 +16,25 @@ const Container = styled.div`
|
|||
|
||||
storiesOf('Tabs', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add(
|
||||
'default',
|
||||
() => (
|
||||
<Container><Tabs
|
||||
.add('default', () => (
|
||||
<Container>
|
||||
<Tabs
|
||||
tabs={simple10Tabs}
|
||||
selected={text('selected', '2')}
|
||||
main={boolean('main', true)}
|
||||
onClick={action('tab selected')}
|
||||
collapsible={boolean('collapsible', true)}
|
||||
position={select('position', ['left', 'right', 'center'], 'left')}
|
||||
/></Container>
|
||||
)
|
||||
)
|
||||
.add(
|
||||
'with content',
|
||||
() => (
|
||||
<Tabs
|
||||
tabs={tabs}
|
||||
selected={text('selected', 'Tab2')}
|
||||
main={boolean('main', false)}
|
||||
onClick={action('tab selected')}
|
||||
collapsible={boolean('collapsible', false)}
|
||||
position={select('position', ['left', 'right', 'center'], 'left')}
|
||||
/>
|
||||
)
|
||||
);
|
||||
</Container>
|
||||
))
|
||||
.add('with content', () => (
|
||||
<Tabs
|
||||
tabs={tabs}
|
||||
selected={text('selected', 'Tab2')}
|
||||
main={boolean('main', false)}
|
||||
onClick={action('tab selected')}
|
||||
collapsible={boolean('collapsible', false)}
|
||||
position={select('position', ['left', 'right', 'center'], 'left')}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -11,10 +11,14 @@ export const TabsContainer = styled.div`
|
|||
height: 100%;
|
||||
|
||||
> div > div:first-child {
|
||||
${props => props.position !== 'left' && `
|
||||
${props =>
|
||||
props.position !== 'left' &&
|
||||
`
|
||||
margin-left: auto !important;
|
||||
`}
|
||||
${props => props.position === 'center' && `
|
||||
${props =>
|
||||
props.position === 'center' &&
|
||||
`
|
||||
margin-right: auto !important;
|
||||
`}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ export const style = ({ theme, main }) => css`
|
|||
background-color: ${theme.base01};
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
${!main && `
|
||||
${!main &&
|
||||
`
|
||||
border-top: 1px solid ${theme.base01};
|
||||
border-bottom: 1px solid ${theme.base02};
|
||||
`}
|
||||
|
@ -39,9 +40,10 @@ export const style = ({ theme, main }) => css`
|
|||
}
|
||||
|
||||
> [data-selected] {
|
||||
${main ?
|
||||
`border-bottom: 2px solid ${theme.base0D};` :
|
||||
`
|
||||
${
|
||||
main
|
||||
? `border-bottom: 2px solid ${theme.base0D};`
|
||||
: `
|
||||
background-color: ${theme.base00};
|
||||
border: 1px solid ${theme.base02};
|
||||
border-bottom: 1px solid ${theme.base00};
|
||||
|
|
|
@ -8,7 +8,8 @@ export const style = ({ theme, main }) => css`
|
|||
background-color: ${theme.base01};
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
${!main && `
|
||||
${!main &&
|
||||
`
|
||||
border-top: 1px solid ${theme.base01};
|
||||
border-bottom: 1px solid ${theme.base02};
|
||||
`}
|
||||
|
@ -37,7 +38,7 @@ export const style = ({ theme, main }) => css`
|
|||
border-bottom: 2px solid ${theme.base03};
|
||||
color: ${theme.base04};
|
||||
}
|
||||
&.collapsed{
|
||||
&.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,27 @@ import React from 'react';
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import styled from 'styled-components';
|
||||
import { withKnobs, text, number, boolean, select } from '@storybook/addon-knobs';
|
||||
import {
|
||||
withKnobs,
|
||||
text,
|
||||
number,
|
||||
boolean,
|
||||
select
|
||||
} from '@storybook/addon-knobs';
|
||||
import PlayIcon from 'react-icons/lib/md/play-arrow';
|
||||
import RecordIcon from 'react-icons/lib/md/fiber-manual-record';
|
||||
import LeftIcon from 'react-icons/lib/md/keyboard-arrow-left';
|
||||
import RightIcon from 'react-icons/lib/md/keyboard-arrow-right';
|
||||
import { Toolbar, Divider, Spacer, Button, Select, Slider, SegmentedControl, Tabs } from '../../';
|
||||
import {
|
||||
Toolbar,
|
||||
Divider,
|
||||
Spacer,
|
||||
Button,
|
||||
Select,
|
||||
Slider,
|
||||
SegmentedControl,
|
||||
Tabs
|
||||
} from '../../';
|
||||
import { options } from '../../Select/stories/options';
|
||||
import { simple10Tabs } from '../../Tabs/stories/data';
|
||||
|
||||
|
@ -26,132 +41,165 @@ export const SliderContainer = styled.div`
|
|||
|
||||
storiesOf('Toolbar', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add(
|
||||
'default',
|
||||
() => (
|
||||
<Container>
|
||||
<Toolbar borderPosition={select('borderPosition', ['top', 'bottom'])}>
|
||||
.add('default', () => (
|
||||
<Container>
|
||||
<Toolbar borderPosition={select('borderPosition', ['top', 'bottom'])}>
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
{text('Label', 'Hello Button')}
|
||||
</Button>
|
||||
<Divider />
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
<RecordIcon />
|
||||
</Button>
|
||||
<Divider />
|
||||
<Spacer />
|
||||
<Select options={options} />
|
||||
</Toolbar>
|
||||
</Container>
|
||||
))
|
||||
.add('tabs', () => (
|
||||
<Container>
|
||||
<Toolbar>
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
{text('Label', 'Hello Button')}
|
||||
</Button>
|
||||
<Tabs
|
||||
tabs={simple10Tabs}
|
||||
selected={text('selected', '2')}
|
||||
main={boolean('main', true)}
|
||||
onClick={action('tab selected')}
|
||||
collapsible={boolean('collapsible', true)}
|
||||
position={select('position', ['left', 'right', 'center'], 'center')}
|
||||
/>
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
{text('Label', 'Hello Button')}
|
||||
</Button>
|
||||
</Toolbar>
|
||||
</Container>
|
||||
))
|
||||
.add('with slider', () => (
|
||||
<Container>
|
||||
<SliderContainer>
|
||||
<Toolbar noBorder fullHeight compact>
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
disabled={boolean('Disabled', false)}
|
||||
title={text('play title', 'Play')}
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
{text('Label', 'Hello Button')}
|
||||
<PlayIcon />
|
||||
</Button>
|
||||
<Divider />
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
<RecordIcon />
|
||||
</Button>
|
||||
<Divider />
|
||||
<Spacer />
|
||||
<Select options={options} />
|
||||
</Toolbar>
|
||||
</Container>
|
||||
)
|
||||
)
|
||||
.add(
|
||||
'tabs',
|
||||
() => (
|
||||
<Container>
|
||||
<Toolbar>
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
{text('Label', 'Hello Button')}
|
||||
</Button>
|
||||
<Tabs
|
||||
tabs={simple10Tabs}
|
||||
selected={text('selected', '2')}
|
||||
main={boolean('main', true)}
|
||||
onClick={action('tab selected')}
|
||||
collapsible={boolean('collapsible', true)}
|
||||
position={select('position', ['left', 'right', 'center'], 'center')}
|
||||
<Slider
|
||||
value={number('value', 80)}
|
||||
min={number('min', 0)}
|
||||
max={number('max', 100)}
|
||||
label={text('label', 'Slider label')}
|
||||
withValue={boolean('withValue', false)}
|
||||
onChange={action('slider changed')}
|
||||
/>
|
||||
<Button
|
||||
title={text('Title', 'Hello Tooltip')}
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
disabled={boolean('Disabled', false)}
|
||||
onClick={action('button clicked')}
|
||||
title="Previous state"
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
disabled
|
||||
onClick={action('previous state clicked')}
|
||||
>
|
||||
{text('Label', 'Hello Button')}
|
||||
<LeftIcon />
|
||||
</Button>
|
||||
<Button
|
||||
title="Next state"
|
||||
tooltipPosition={select('tooltipPosition', [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
'top-left',
|
||||
'top-right'
|
||||
])}
|
||||
onClick={action('next state clicked')}
|
||||
>
|
||||
<RightIcon />
|
||||
</Button>
|
||||
<SegmentedControl
|
||||
values={['live', '1x']}
|
||||
selected={select('selected', ['live', '1x'], 'live')}
|
||||
onClick={action('button selected')}
|
||||
/>
|
||||
</Toolbar>
|
||||
</Container>
|
||||
)
|
||||
)
|
||||
.add(
|
||||
'with slider',
|
||||
() => (
|
||||
<Container>
|
||||
<SliderContainer>
|
||||
<Toolbar noBorder fullHeight compact>
|
||||
<Button
|
||||
title={text('play title', 'Play')}
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
onClick={action('button clicked')}
|
||||
>
|
||||
<PlayIcon />
|
||||
</Button>
|
||||
<Slider
|
||||
value={number('value', 80)}
|
||||
min={number('min', 0)}
|
||||
max={number('max', 100)}
|
||||
label={text('label', 'Slider label')}
|
||||
withValue={boolean('withValue', false)}
|
||||
onChange={action('slider changed')}
|
||||
/>
|
||||
<Button
|
||||
title="Previous state"
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
disabled
|
||||
onClick={action('previous state clicked')}
|
||||
>
|
||||
<LeftIcon />
|
||||
</Button>
|
||||
<Button
|
||||
title="Next state"
|
||||
tooltipPosition={
|
||||
select('tooltipPosition', ['top', 'bottom', 'left', 'right',
|
||||
'bottom-left', 'bottom-right', 'top-left', 'top-right'])
|
||||
}
|
||||
onClick={action('next state clicked')}
|
||||
>
|
||||
<RightIcon />
|
||||
</Button>
|
||||
<SegmentedControl
|
||||
values={['live', '1x']}
|
||||
selected={select('selected', ['live', '1x'], 'live')}
|
||||
onClick={action('button selected')}
|
||||
/>
|
||||
</Toolbar>
|
||||
</SliderContainer>
|
||||
</Container>
|
||||
)
|
||||
);
|
||||
</SliderContainer>
|
||||
</Container>
|
||||
));
|
||||
|
|
|
@ -14,8 +14,7 @@ const Toolbar = styled.div`
|
|||
text-align: center;
|
||||
position: relative;
|
||||
${({ borderPosition, theme }) =>
|
||||
borderPosition && `border-${borderPosition}: 1px solid ${theme.base02};`
|
||||
}
|
||||
borderPosition && `border-${borderPosition}: 1px solid ${theme.base02};`}
|
||||
|
||||
& > div {
|
||||
margin: auto ${props => (props.noBorder ? '0' : '1px;')};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export default (colors) => ({
|
||||
export default colors => ({
|
||||
...colors,
|
||||
fontFamily: "'Source Sans Pro', sans-serif",
|
||||
codeFontFamily: "'Source Code Pro', monospace",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export default (colors) => ({
|
||||
export default colors => ({
|
||||
fontFamily: "'Roboto', sans-serif",
|
||||
codeFontFamily: "'Roboto Mono', monospace",
|
||||
inputPadding: 5,
|
||||
|
|
|
@ -36,7 +36,9 @@ export const ripple = theme => `
|
|||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
background-image: radial-gradient(circle, ${theme.base07} 11%, transparent 11%);
|
||||
background-image: radial-gradient(circle, ${
|
||||
theme.base07
|
||||
} 11%, transparent 11%);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50%;
|
||||
transform: scale(10, 10);
|
||||
|
|
|
@ -7,6 +7,10 @@ import Color from 'color';
|
|||
effect('#000000', 'alpha', 0.5);
|
||||
*/
|
||||
|
||||
export default (color, effect, val) => new Color(color)[effect](val).hsl().string();
|
||||
export default (color, effect, val) =>
|
||||
new Color(color)
|
||||
[effect](val)
|
||||
.hsl()
|
||||
.string();
|
||||
|
||||
// TODO: memoize it
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import styled from 'styled-components';
|
||||
import getDefaultTheme from '../themes/default';
|
||||
|
||||
const getStyle = (styles, type) => (
|
||||
typeof styles === 'object' ? styles[type] || styles.default : styles
|
||||
);
|
||||
const getStyle = (styles, type) =>
|
||||
typeof styles === 'object' ? styles[type] || styles.default : styles;
|
||||
|
||||
export default (styles, component) =>
|
||||
styled(component || 'div')`${
|
||||
props => (
|
||||
props.theme.type ? getStyle(styles, props.theme.type) :
|
||||
// used outside of container (theme provider)
|
||||
getStyle(styles, 'default')({ ...props, theme: getDefaultTheme(props.theme) })
|
||||
)
|
||||
}`;
|
||||
styled(component || 'div')`
|
||||
${props =>
|
||||
props.theme.type
|
||||
? getStyle(styles, props.theme.type)
|
||||
: // used outside of container (theme provider)
|
||||
getStyle(styles, 'default')({
|
||||
...props,
|
||||
theme: getDefaultTheme(props.theme)
|
||||
})}
|
||||
`;
|
||||
|
||||
// TODO: memoize it?
|
||||
|
|
|
@ -5,7 +5,10 @@ import * as additionalSchemes from '../colorSchemes';
|
|||
import invertColors from '../utils/invertColors';
|
||||
|
||||
export const schemes = { ...baseSchemes, ...additionalSchemes };
|
||||
export const listSchemes = () => Object.keys(schemes).slice(1).sort(); // remove `__esModule`
|
||||
export const listSchemes = () =>
|
||||
Object.keys(schemes)
|
||||
.slice(1)
|
||||
.sort(); // remove `__esModule`
|
||||
export const listThemes = () => Object.keys(themes);
|
||||
|
||||
export const getTheme = ({ theme: type, scheme, light }) => {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { render, mount } from 'enzyme';
|
|||
import { renderToJson } from 'enzyme-to-json';
|
||||
import { Button } from '../src';
|
||||
|
||||
describe('Button', function () {
|
||||
describe('Button', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(<Button>Text</Button>);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
|
|
|
@ -3,10 +3,12 @@ import { render } from 'enzyme';
|
|||
import { renderToJson } from 'enzyme-to-json';
|
||||
import { Container } from '../src';
|
||||
|
||||
describe('Container', function () {
|
||||
describe('Container', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(
|
||||
<Container themeData={{ theme: 'default', scheme: 'default', invert: false }}>
|
||||
<Container
|
||||
themeData={{ theme: 'default', scheme: 'default', invert: false }}
|
||||
>
|
||||
Text
|
||||
</Container>
|
||||
);
|
||||
|
|
|
@ -4,29 +4,23 @@ import { renderToJson } from 'enzyme-to-json';
|
|||
import { ContextMenu } from '../src';
|
||||
import { items } from '../src/ContextMenu/stories/data';
|
||||
|
||||
describe('ContextMenu', function () {
|
||||
describe('ContextMenu', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(
|
||||
<ContextMenu
|
||||
items={items}
|
||||
onClick={() => {}}
|
||||
x={100}
|
||||
y={100}
|
||||
/>
|
||||
<ContextMenu items={items} onClick={() => {}} x={100} y={100} />
|
||||
);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
it('should handle the click event', () => {
|
||||
const onClick = jest.fn();
|
||||
const wrapper = mount(
|
||||
<ContextMenu
|
||||
items={items}
|
||||
onClick={onClick}
|
||||
x={100}
|
||||
y={100}
|
||||
/>);
|
||||
<ContextMenu items={items} onClick={onClick} x={100} y={100} />
|
||||
);
|
||||
|
||||
wrapper.find('button').first().simulate('click');
|
||||
wrapper
|
||||
.find('button')
|
||||
.first()
|
||||
.simulate('click');
|
||||
expect(onClick).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import { render, mount } from 'enzyme';
|
|||
import { renderToJson } from 'enzyme-to-json';
|
||||
import { Dialog } from '../src';
|
||||
|
||||
describe('Dialog', function () {
|
||||
describe('Dialog', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(<Dialog />);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
|
@ -11,11 +11,7 @@ describe('Dialog', function () {
|
|||
|
||||
it('renders with props', () => {
|
||||
const wrapper = render(
|
||||
<Dialog
|
||||
title="Dialog Title"
|
||||
open
|
||||
fullWidth
|
||||
>
|
||||
<Dialog title="Dialog Title" open fullWidth>
|
||||
Hello Dialog!
|
||||
</Dialog>
|
||||
);
|
||||
|
@ -31,7 +27,10 @@ describe('Dialog', function () {
|
|||
const onDismiss = jest.fn();
|
||||
const wrapper = mount(<Dialog open onDismiss={onDismiss} />);
|
||||
|
||||
wrapper.find('button').first().simulate('click');
|
||||
wrapper
|
||||
.find('button')
|
||||
.first()
|
||||
.simulate('click');
|
||||
expect(onDismiss).toBeCalled();
|
||||
});
|
||||
|
||||
|
@ -39,7 +38,10 @@ describe('Dialog', function () {
|
|||
const onSubmit = jest.fn();
|
||||
const wrapper = mount(<Dialog open onSubmit={onSubmit} />);
|
||||
|
||||
wrapper.find('button').last().simulate('click');
|
||||
wrapper
|
||||
.find('button')
|
||||
.last()
|
||||
.simulate('click');
|
||||
expect(onSubmit).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,10 +4,10 @@ import { mountToJson } from 'enzyme-to-json';
|
|||
import { Editor } from '../src';
|
||||
import 'codemirror/mode/javascript/javascript';
|
||||
|
||||
describe('Editor', function () {
|
||||
describe('Editor', function() {
|
||||
const getBoundingClientRect = jest.fn();
|
||||
const getClientRects = jest.fn();
|
||||
document.body.createTextRange = function () {
|
||||
document.body.createTextRange = function() {
|
||||
return {
|
||||
getBoundingClientRect() {
|
||||
getBoundingClientRect();
|
||||
|
|
|
@ -4,14 +4,11 @@ import { shallowToJson } from 'enzyme-to-json';
|
|||
import { Form } from '../src';
|
||||
import { schema, uiSchema, formData } from '../src/Form/stories/schema';
|
||||
|
||||
describe('Form', function () {
|
||||
describe('Form', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = shallow(
|
||||
<Form
|
||||
formData={formData}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
/>);
|
||||
<Form formData={formData} schema={schema} uiSchema={uiSchema} />
|
||||
);
|
||||
expect(shallowToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -23,18 +20,15 @@ describe('Form', function () {
|
|||
formData={formData}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
/>);
|
||||
/>
|
||||
);
|
||||
expect(shallowToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders with no button', () => {
|
||||
const wrapper = shallow(
|
||||
<Form
|
||||
formData={formData}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
noSubmit
|
||||
/>);
|
||||
<Form formData={formData} schema={schema} uiSchema={uiSchema} noSubmit />
|
||||
);
|
||||
expect(shallowToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { render, mount } from 'enzyme';
|
|||
import { renderToJson } from 'enzyme-to-json';
|
||||
import { Notification } from '../src';
|
||||
|
||||
describe('Notification', function () {
|
||||
describe('Notification', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(<Notification>Message</Notification>);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
|
@ -11,14 +11,18 @@ describe('Notification', function () {
|
|||
|
||||
it('renders with props', () => {
|
||||
const wrapper = render(
|
||||
<Notification type="error" onClose={() => {}}>Message</Notification>
|
||||
<Notification type="error" onClose={() => {}}>
|
||||
Message
|
||||
</Notification>
|
||||
);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should handle the click event', () => {
|
||||
const onClose = jest.fn();
|
||||
const wrapper = mount(<Notification onClose={onClose}>Message</Notification>);
|
||||
const wrapper = mount(
|
||||
<Notification onClose={onClose}>Message</Notification>
|
||||
);
|
||||
|
||||
wrapper.find('button').simulate('click');
|
||||
expect(onClose).toBeCalled();
|
||||
|
|
|
@ -3,7 +3,7 @@ import { render, mount } from 'enzyme';
|
|||
import { renderToJson } from 'enzyme-to-json';
|
||||
import { SegmentedControl } from '../src';
|
||||
|
||||
describe('SegmentedControl', function () {
|
||||
describe('SegmentedControl', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(
|
||||
<SegmentedControl
|
||||
|
@ -17,15 +17,19 @@ describe('SegmentedControl', function () {
|
|||
});
|
||||
it('should handle the click event', () => {
|
||||
const onClick = jest.fn();
|
||||
const wrapper = mount(<SegmentedControl
|
||||
values={['Button1', 'Button2', 'Button3']}
|
||||
selected="Button1"
|
||||
disabled={false}
|
||||
onClick={onClick}
|
||||
/>
|
||||
const wrapper = mount(
|
||||
<SegmentedControl
|
||||
values={['Button1', 'Button2', 'Button3']}
|
||||
selected="Button1"
|
||||
disabled={false}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
|
||||
wrapper.find('button').first().simulate('click');
|
||||
wrapper
|
||||
.find('button')
|
||||
.first()
|
||||
.simulate('click');
|
||||
expect(onClick).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ import { renderToJson, mountToJson } from 'enzyme-to-json';
|
|||
import { Select } from '../src';
|
||||
import { options } from '../src/Select/stories/options';
|
||||
|
||||
describe('Select', function () {
|
||||
describe('Select', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(<Select options={options} onChange={() => {}} />);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
|
|
|
@ -3,7 +3,7 @@ import { render, mount } from 'enzyme';
|
|||
import { renderToJson } from 'enzyme-to-json';
|
||||
import { Slider } from '../src';
|
||||
|
||||
describe('Slider', function () {
|
||||
describe('Slider', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(<Slider />);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
|
|
|
@ -4,7 +4,7 @@ import { renderToJson } from 'enzyme-to-json';
|
|||
import { Tabs } from '../src';
|
||||
import { tabs, simple10Tabs } from '../src/Tabs/stories/data';
|
||||
|
||||
describe('Tabs', function () {
|
||||
describe('Tabs', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(<Tabs tabs={tabs} onClick={() => {}} />);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
|
@ -12,22 +12,14 @@ describe('Tabs', function () {
|
|||
|
||||
it('renders with props', () => {
|
||||
const wrapper = render(
|
||||
<Tabs
|
||||
tabs={tabs}
|
||||
onClick={() => {}}
|
||||
selected="Tab2"
|
||||
/>
|
||||
<Tabs tabs={tabs} onClick={() => {}} selected="Tab2" />
|
||||
);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders tabs without inner components', () => {
|
||||
const wrapper = render(
|
||||
<Tabs
|
||||
tabs={simple10Tabs}
|
||||
onClick={() => {}}
|
||||
selected="5"
|
||||
/>
|
||||
<Tabs tabs={simple10Tabs} onClick={() => {}} selected="5" />
|
||||
);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
@ -36,7 +28,10 @@ describe('Tabs', function () {
|
|||
const onClick = jest.fn();
|
||||
const wrapper = mount(<Tabs tabs={tabs} onClick={onClick} />);
|
||||
|
||||
wrapper.find('button').first().simulate('click');
|
||||
wrapper
|
||||
.find('button')
|
||||
.first()
|
||||
.simulate('click');
|
||||
expect(onClick).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import { render } from 'enzyme';
|
|||
import { renderToJson } from 'enzyme-to-json';
|
||||
import { Toolbar, Divider, Spacer, Button } from '../src';
|
||||
|
||||
describe('Toolbar', function () {
|
||||
describe('Toolbar', function() {
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(
|
||||
<Toolbar>
|
||||
|
@ -17,9 +17,7 @@ describe('Toolbar', function () {
|
|||
});
|
||||
|
||||
it('renders with props', () => {
|
||||
const wrapper = render(
|
||||
<Toolbar borderPosition="top" />
|
||||
);
|
||||
const wrapper = render(<Toolbar borderPosition="top" />);
|
||||
expect(renderToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
exports[`Button renders correctly 1`] = `
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat fWcQZ"
|
||||
class="sc-htpNat ldLqpm"
|
||||
>
|
||||
Text
|
||||
</button>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`Container renders correctly 1`] = `
|
||||
<div
|
||||
class="sc-bdVaJa dRsjcb"
|
||||
class="sc-bdVaJa ODaHo"
|
||||
>
|
||||
Text
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`ContextMenu renders correctly 1`] = `
|
||||
<div
|
||||
class="sc-EHOje dIpPFG"
|
||||
class="sc-EHOje cfLLnh"
|
||||
>
|
||||
<button
|
||||
value="Menu Item 1"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`Dialog renders correctly 1`] = `
|
||||
<div
|
||||
class="sc-iwsKbI fOBkrR"
|
||||
class="sc-iwsKbI islPis"
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
|
@ -21,19 +21,19 @@ exports[`Dialog renders correctly 1`] = `
|
|||
class="mc-dialog--footer"
|
||||
>
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat fWcQZ"
|
||||
class="sc-htpNat ldLqpm"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat iMkoYt"
|
||||
class="sc-htpNat cvNnmn"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
|
@ -45,7 +45,7 @@ exports[`Dialog renders correctly 1`] = `
|
|||
|
||||
exports[`Dialog renders modal 1`] = `
|
||||
<div
|
||||
class="sc-iwsKbI fOBkrR"
|
||||
class="sc-iwsKbI islPis"
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
|
@ -61,19 +61,19 @@ exports[`Dialog renders modal 1`] = `
|
|||
class="mc-dialog--footer"
|
||||
>
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat fWcQZ"
|
||||
class="sc-htpNat ldLqpm"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat iMkoYt"
|
||||
class="sc-htpNat cvNnmn"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
|
@ -85,7 +85,7 @@ exports[`Dialog renders modal 1`] = `
|
|||
|
||||
exports[`Dialog renders with props 1`] = `
|
||||
<div
|
||||
class="sc-iwsKbI fpUYbC"
|
||||
class="sc-iwsKbI hRSLqU"
|
||||
open=""
|
||||
>
|
||||
<div />
|
||||
|
@ -109,19 +109,19 @@ exports[`Dialog renders with props 1`] = `
|
|||
class="mc-dialog--footer"
|
||||
>
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat fWcQZ"
|
||||
class="sc-htpNat ldLqpm"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat iMkoYt"
|
||||
class="sc-htpNat cvNnmn"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
|
|
|
@ -14,7 +14,7 @@ exports[`Editor renders correctly 1`] = `
|
|||
innerRef={[Function]}
|
||||
>
|
||||
<div
|
||||
className="sc-gZMcBi eROHUl"
|
||||
className="sc-gZMcBi bFOJgt"
|
||||
/>
|
||||
</styled.div>
|
||||
</Editor>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`Notification renders correctly 1`] = `
|
||||
<div
|
||||
class="sc-fjdhpX fmuodm"
|
||||
class="sc-fjdhpX gcvrGp"
|
||||
type="info"
|
||||
>
|
||||
<span>
|
||||
|
@ -13,7 +13,7 @@ exports[`Notification renders correctly 1`] = `
|
|||
|
||||
exports[`Notification renders with props 1`] = `
|
||||
<div
|
||||
class="sc-fjdhpX fmuodm"
|
||||
class="sc-fjdhpX gcvrGp"
|
||||
type="error"
|
||||
>
|
||||
<svg
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`SegmentedControl renders correctly 1`] = `
|
||||
<div
|
||||
class="sc-jTzLTM jHNWjD"
|
||||
class="sc-jTzLTM bwMlok"
|
||||
>
|
||||
<button
|
||||
data-selected="true"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`Select renders correctly 1`] = `
|
||||
<div
|
||||
class="Select sc-bZQynM lpCNM is-searchable Select--single"
|
||||
class="Select sc-bZQynM eKUTFA is-searchable Select--single"
|
||||
>
|
||||
<div
|
||||
class="Select-control"
|
||||
|
@ -47,7 +47,7 @@ exports[`Select renders correctly 1`] = `
|
|||
|
||||
exports[`Select renders with props 1`] = `
|
||||
<div
|
||||
class="Select sc-bZQynM dVPEwd has-value is-clearable is-disabled is-loading Select--multi"
|
||||
class="Select sc-bZQynM lbesTc has-value is-clearable is-disabled is-loading Select--multi"
|
||||
>
|
||||
<div
|
||||
class="Select-control"
|
||||
|
@ -155,7 +155,7 @@ exports[`Select should select another option 1`] = `
|
|||
autosize={true}
|
||||
backspaceRemoves={true}
|
||||
backspaceToRemoveMessage="Press backspace to remove {label}"
|
||||
className="sc-bZQynM lpCNM"
|
||||
className="sc-bZQynM eKUTFA"
|
||||
clearAllText="Clear all"
|
||||
clearRenderer={[Function]}
|
||||
clearValueText="Clear value"
|
||||
|
@ -215,7 +215,7 @@ exports[`Select should select another option 1`] = `
|
|||
valueKey="value"
|
||||
>
|
||||
<div
|
||||
className="Select sc-bZQynM lpCNM is-open is-searchable Select--single"
|
||||
className="Select sc-bZQynM eKUTFA is-open is-searchable Select--single"
|
||||
>
|
||||
<div
|
||||
className="Select-control"
|
||||
|
@ -404,7 +404,7 @@ exports[`Select shouldn't find any results 1`] = `
|
|||
autosize={true}
|
||||
backspaceRemoves={true}
|
||||
backspaceToRemoveMessage="Press backspace to remove {label}"
|
||||
className="sc-bZQynM lpCNM"
|
||||
className="sc-bZQynM eKUTFA"
|
||||
clearAllText="Clear all"
|
||||
clearRenderer={[Function]}
|
||||
clearValueText="Clear value"
|
||||
|
@ -464,7 +464,7 @@ exports[`Select shouldn't find any results 1`] = `
|
|||
valueKey="value"
|
||||
>
|
||||
<div
|
||||
className="Select sc-bZQynM lpCNM is-open is-searchable Select--single"
|
||||
className="Select sc-bZQynM eKUTFA is-open is-searchable Select--single"
|
||||
>
|
||||
<div
|
||||
className="Select-control"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`Slider renders correctly 1`] = `
|
||||
<div
|
||||
class="sc-gzVnrw gTqmBD"
|
||||
class="sc-gzVnrw hKBSWW"
|
||||
>
|
||||
<input
|
||||
max="100"
|
||||
|
@ -15,7 +15,7 @@ exports[`Slider renders correctly 1`] = `
|
|||
|
||||
exports[`Slider renders with props 1`] = `
|
||||
<div
|
||||
class="sc-gzVnrw csqRof"
|
||||
class="sc-gzVnrw gnJNaZ"
|
||||
disabled=""
|
||||
>
|
||||
<label>
|
||||
|
|
|
@ -5,7 +5,7 @@ exports[`Tabs renders correctly 1`] = `
|
|||
class="sc-VigVT fmiisu"
|
||||
>
|
||||
<div
|
||||
class="sc-gqjmRU gEvsQs"
|
||||
class="sc-gqjmRU kpDKzc"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
|
@ -33,7 +33,7 @@ exports[`Tabs renders tabs without inner components 1`] = `
|
|||
class="sc-VigVT fmiisu"
|
||||
>
|
||||
<div
|
||||
class="sc-gqjmRU gEvsQs"
|
||||
class="sc-gqjmRU kpDKzc"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
|
@ -97,7 +97,7 @@ exports[`Tabs renders with props 1`] = `
|
|||
class="sc-VigVT fmiisu"
|
||||
>
|
||||
<div
|
||||
class="sc-gqjmRU gEvsQs"
|
||||
class="sc-gqjmRU kpDKzc"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
|
|
|
@ -5,10 +5,10 @@ exports[`Toolbar renders correctly 1`] = `
|
|||
class="sc-jzJRlG bBrbNn"
|
||||
>
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat fWcQZ"
|
||||
class="sc-htpNat ldLqpm"
|
||||
>
|
||||
1
|
||||
</button>
|
||||
|
@ -20,10 +20,10 @@ exports[`Toolbar renders correctly 1`] = `
|
|||
class="sc-kAzzGY lcEaIs"
|
||||
/>
|
||||
<div
|
||||
class="sc-ifAKCX jTewnV"
|
||||
class="sc-ifAKCX evScRP"
|
||||
>
|
||||
<button
|
||||
class="sc-htpNat fWcQZ"
|
||||
class="sc-htpNat ldLqpm"
|
||||
>
|
||||
2
|
||||
</button>
|
||||
|
|
|
@ -5,15 +5,16 @@ The following opinions must be taken into account since the primary use case of
|
|||
- Objects and arrays deeply nested within collections are not converted into a tree structure. See `someNestedObject` and `someNestedArray` in the [output](https://github.com/romseguy/map2tree#output) below, or the [corresponding test](https://github.com/romseguy/map2tree/blob/master/test/map2tree.js#L140).
|
||||
- Provides support for [Immutable.js](https://github.com/facebook/immutable-js) data structures (only List and Map though).
|
||||
|
||||
|
||||
# Usage
|
||||
|
||||
|
||||
```javascript
|
||||
map2tree(someMap, options = {
|
||||
key: 'state', // the name you want for as the root node of the output tree
|
||||
pushMethod: 'push' // use 'unshift' to change the order children nodes are added
|
||||
})
|
||||
map2tree(
|
||||
someMap,
|
||||
(options = {
|
||||
key: 'state', // the name you want for as the root node of the output tree
|
||||
pushMethod: 'push' // use 'unshift' to change the order children nodes are added
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
# Input
|
||||
|
@ -22,16 +23,16 @@ map2tree(someMap, options = {
|
|||
const someMap = {
|
||||
someReducer: {
|
||||
todos: [
|
||||
{title: 'map', someNestedObject: {foo: 'bar'}},
|
||||
{title: 'to', someNestedArray: ['foo', 'bar']},
|
||||
{title: 'tree'},
|
||||
{title: 'map2tree'}
|
||||
{ title: 'map', someNestedObject: { foo: 'bar' } },
|
||||
{ title: 'to', someNestedArray: ['foo', 'bar'] },
|
||||
{ title: 'tree' },
|
||||
{ title: 'map2tree' }
|
||||
],
|
||||
completedCount: 1
|
||||
},
|
||||
otherReducer: {
|
||||
foo: 0,
|
||||
bar:{key: 'value'}
|
||||
bar: { key: 'value' }
|
||||
}
|
||||
};
|
||||
```
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"test": "jest",
|
||||
"prepare": "npm run build && npm run build:umd",
|
||||
"prepublishOnly": "npm run test && npm run clean && npm run build && npm run build:umd && npm run build:umd:min"
|
||||
},
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||
|
|
|
@ -19,16 +19,24 @@ function visit(parent, visitFn, childrenFn) {
|
|||
function getNode(tree, key) {
|
||||
let node = null;
|
||||
|
||||
visit(tree, d => {
|
||||
if (d.name === key) {
|
||||
node = d;
|
||||
}
|
||||
}, d => d.children);
|
||||
visit(
|
||||
tree,
|
||||
d => {
|
||||
if (d.name === key) {
|
||||
node = d;
|
||||
}
|
||||
},
|
||||
d => d.children
|
||||
);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
export default function map2tree(root, options = {}, tree = {name: options.key || 'state', children: []}) {
|
||||
export default function map2tree(
|
||||
root,
|
||||
options = {},
|
||||
tree = { name: options.key || 'state', children: [] }
|
||||
) {
|
||||
if (!isPlainObject(root) && root && !root.toJS) {
|
||||
return {};
|
||||
}
|
||||
|
@ -41,8 +49,11 @@ export default function map2tree(root, options = {}, tree = {name: options.key |
|
|||
}
|
||||
|
||||
mapValues(root && root.toJS ? root.toJS() : root, (maybeImmutable, key) => {
|
||||
const value = maybeImmutable && maybeImmutable.toJS ? maybeImmutable.toJS() : maybeImmutable;
|
||||
let newNode = {name: key};
|
||||
const value =
|
||||
maybeImmutable && maybeImmutable.toJS
|
||||
? maybeImmutable.toJS()
|
||||
: maybeImmutable;
|
||||
let newNode = { name: key };
|
||||
|
||||
if (isArray(value)) {
|
||||
newNode.children = [];
|
||||
|
@ -61,7 +72,7 @@ export default function map2tree(root, options = {}, tree = {name: options.key |
|
|||
|
||||
currentNode.children[pushMethod](newNode);
|
||||
|
||||
map2tree(value, {key, pushMethod}, tree);
|
||||
map2tree(value, { key, pushMethod }, tree);
|
||||
});
|
||||
|
||||
return tree;
|
||||
|
|
|
@ -3,7 +3,7 @@ import immutable from 'immutable';
|
|||
|
||||
test('# rootNodeKey', () => {
|
||||
const map = {};
|
||||
const options = {key: 'foo'};
|
||||
const options = { key: 'foo' };
|
||||
|
||||
expect(map2tree(map, options).name).toBe('foo');
|
||||
});
|
||||
|
@ -16,9 +16,7 @@ describe('# shallow map', () => {
|
|||
|
||||
const expected = {
|
||||
name: 'state',
|
||||
children: [
|
||||
{name: 'a', value: null}
|
||||
]
|
||||
children: [{ name: 'a', value: null }]
|
||||
};
|
||||
|
||||
expect(map2tree(map)).toEqual(expected);
|
||||
|
@ -33,10 +31,7 @@ describe('# shallow map', () => {
|
|||
|
||||
const expected = {
|
||||
name: 'state',
|
||||
children: [
|
||||
{name: 'a', value: 'foo'},
|
||||
{name: 'b', value: 'bar'}
|
||||
]
|
||||
children: [{ name: 'a', value: 'foo' }, { name: 'b', value: 'bar' }]
|
||||
};
|
||||
|
||||
expect(map2tree(map)).toEqual(expected);
|
||||
|
@ -45,14 +40,12 @@ describe('# shallow map', () => {
|
|||
|
||||
test('## object', () => {
|
||||
const map = {
|
||||
a: {aa: 'foo'}
|
||||
a: { aa: 'foo' }
|
||||
};
|
||||
|
||||
const expected = {
|
||||
name: 'state',
|
||||
children: [
|
||||
{name: 'a', children: [{name: 'aa', value: 'foo'}]}
|
||||
]
|
||||
children: [{ name: 'a', children: [{ name: 'aa', value: 'foo' }] }]
|
||||
};
|
||||
|
||||
expect(map2tree(map)).toEqual(expected);
|
||||
|
@ -61,24 +54,27 @@ describe('# shallow map', () => {
|
|||
|
||||
test('## immutable Map', () => {
|
||||
const map = {
|
||||
a: immutable.fromJS({aa: 'foo', ab: 'bar'})
|
||||
a: immutable.fromJS({ aa: 'foo', ab: 'bar' })
|
||||
};
|
||||
|
||||
const expected = {
|
||||
name: 'state',
|
||||
children: [
|
||||
{name: 'a', children: [{name: 'aa', value: 'foo'}, {name: 'ab', value: 'bar'}]}
|
||||
{
|
||||
name: 'a',
|
||||
children: [{ name: 'aa', value: 'foo' }, { name: 'ab', value: 'bar' }]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(map2tree(map)).toEqual(expected);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe('# deep map', () => {
|
||||
test('## null', () => {
|
||||
const map = {
|
||||
a: {aa: null}
|
||||
a: { aa: null }
|
||||
};
|
||||
|
||||
const expected = {
|
||||
|
@ -102,7 +98,7 @@ describe('# deep map', () => {
|
|||
|
||||
test('## object', () => {
|
||||
const map = {
|
||||
a: {aa: {aaa: 'foo'}}
|
||||
a: { aa: { aaa: 'foo' } }
|
||||
};
|
||||
|
||||
const expected = {
|
||||
|
@ -113,9 +109,7 @@ describe('# deep map', () => {
|
|||
children: [
|
||||
{
|
||||
name: 'aa',
|
||||
children: [
|
||||
{name: 'aaa', value: 'foo'}
|
||||
]
|
||||
children: [{ name: 'aaa', value: 'foo' }]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -129,21 +123,18 @@ describe('# deep map', () => {
|
|||
|
||||
describe('# array map', () => {
|
||||
const map = {
|
||||
a: [
|
||||
1,
|
||||
2
|
||||
]
|
||||
a: [1, 2]
|
||||
};
|
||||
|
||||
test('## push', () => {
|
||||
const expected = {
|
||||
name: 'state',
|
||||
children: [{
|
||||
name: 'a',
|
||||
children: [
|
||||
{name: 'a[0]', value: 1},
|
||||
{name: 'a[1]', value: 2}]
|
||||
}]
|
||||
children: [
|
||||
{
|
||||
name: 'a',
|
||||
children: [{ name: 'a[0]', value: 1 }, { name: 'a[1]', value: 2 }]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(map2tree(map)).toEqual(expected);
|
||||
|
@ -151,16 +142,15 @@ describe('# array map', () => {
|
|||
});
|
||||
|
||||
test('## unshift', () => {
|
||||
const options = {pushMethod: 'unshift'};
|
||||
const options = { pushMethod: 'unshift' };
|
||||
const expected = {
|
||||
name: 'state',
|
||||
children: [{
|
||||
name: 'a',
|
||||
children: [
|
||||
{name: 'a[1]', value: 2},
|
||||
{name: 'a[0]', value: 1}
|
||||
]
|
||||
}]
|
||||
children: [
|
||||
{
|
||||
name: 'a',
|
||||
children: [{ name: 'a[1]', value: 2 }, { name: 'a[0]', value: 1 }]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(map2tree(map, options)).toEqual(expected);
|
||||
|
@ -169,33 +159,28 @@ describe('# array map', () => {
|
|||
|
||||
test('## null', () => {
|
||||
const map = {
|
||||
a: [
|
||||
null
|
||||
]
|
||||
a: [null]
|
||||
};
|
||||
|
||||
const expected = {
|
||||
name: 'state',
|
||||
children: [{
|
||||
name: 'a',
|
||||
children: [
|
||||
{name: 'a[0]', value: null}
|
||||
]
|
||||
}]
|
||||
children: [
|
||||
{
|
||||
name: 'a',
|
||||
children: [{ name: 'a[0]', value: null }]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(map2tree(map)).toEqual(expected);
|
||||
expect(map2tree(immutable.fromJS(map))).toEqual(expected);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe('# collection map', () => {
|
||||
test('## value', () => {
|
||||
const map = {
|
||||
a: [
|
||||
{aa: 1},
|
||||
{aa: 2}
|
||||
]
|
||||
a: [{ aa: 1 }, { aa: 2 }]
|
||||
};
|
||||
|
||||
const expected = {
|
||||
|
@ -204,8 +189,8 @@ describe('# collection map', () => {
|
|||
{
|
||||
name: 'a',
|
||||
children: [
|
||||
{name: 'a[0]', object: {aa: 1}},
|
||||
{name: 'a[1]', object: {aa: 2}}
|
||||
{ name: 'a[0]', object: { aa: 1 } },
|
||||
{ name: 'a[1]', object: { aa: 2 } }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -217,9 +202,7 @@ describe('# collection map', () => {
|
|||
|
||||
test('## object', () => {
|
||||
const map = {
|
||||
a: [
|
||||
{aa: {aaa: 'foo'}}
|
||||
]
|
||||
a: [{ aa: { aaa: 'foo' } }]
|
||||
};
|
||||
|
||||
const expected = {
|
||||
|
@ -227,14 +210,12 @@ describe('# collection map', () => {
|
|||
children: [
|
||||
{
|
||||
name: 'a',
|
||||
children: [
|
||||
{name: 'a[0]', object: {aa: {aaa: 'foo'}}}
|
||||
]
|
||||
children: [{ name: 'a[0]', object: { aa: { aaa: 'foo' } } }]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(map2tree(map)).toEqual(expected);
|
||||
expect(map2tree(immutable.fromJS(map))).toEqual(expected);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,31 +1,29 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = (env = {}) => (
|
||||
{
|
||||
mode: 'production',
|
||||
entry: {
|
||||
app: ['./src/index.js']
|
||||
},
|
||||
output: {
|
||||
library: 'd3tooltip',
|
||||
libraryTarget: 'umd',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: env.minimize ? 'map2tree.min.js' : 'map2tree.js'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
minimize: !!env.minimize
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
}
|
||||
module.exports = (env = {}) => ({
|
||||
mode: 'production',
|
||||
entry: {
|
||||
app: ['./src/index.js']
|
||||
},
|
||||
output: {
|
||||
library: 'd3tooltip',
|
||||
libraryTarget: 'umd',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: env.minimize ? 'map2tree.min.js' : 'map2tree.js'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
minimize: !!env.minimize
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -2,7 +2,6 @@ The MIT License (MIT)
|
|||
|
||||
Copyright (c) 2015 Shusaku Uesugi, (c) 2016-present Alexander Kuznetsov
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
|
|
|
@ -33,6 +33,7 @@ Check out [examples](examples) directory for more details.
|
|||
### Theming
|
||||
|
||||
This component now uses [react-base16-styling](https://github.com/alexkuz/react-base16-styling) module, which allows to customize component via `theme` property, which can be the following:
|
||||
|
||||
- [base16](http://chriskempson.github.io/base16) theme data. [The example theme data can be found here](https://github.com/gaearon/redux-devtools/tree/75322b15ee7ba03fddf10ac3399881e302848874/src/react/themes).
|
||||
- object that contains style objects, strings (that treated as classnames) or functions. A function is used to extend its first argument `{ style, className }` and should return an object with the same structure. Other arguments depend on particular context (and should be described here). See [createStylingFromTheme.js](https://github.com/alexkuz/react-json-tree/blob/feature-refactor-styling/src/createStylingFromTheme.js) for the list of styling object keys. Also, this object can extend `base16` theme via `extend` property.
|
||||
|
||||
|
@ -62,8 +63,7 @@ const theme = {
|
|||
|
||||
<div>
|
||||
<JSONTree data={data} theme={theme} invertTheme={false} />
|
||||
</div>
|
||||
|
||||
</div>;
|
||||
```
|
||||
|
||||
#### Result (Monokai theme, dark background):
|
||||
|
@ -74,21 +74,24 @@ const theme = {
|
|||
|
||||
```jsx
|
||||
<div>
|
||||
<JSONTree data={data} theme={{
|
||||
extend: theme,
|
||||
// underline keys for literal values
|
||||
valueLabel: {
|
||||
textDecoration: 'underline'
|
||||
},
|
||||
// switch key for objects to uppercase when object is expanded.
|
||||
// `nestedNodeLabel` receives additional arguments `expanded` and `keyPath`
|
||||
nestedNodeLabel: ({ style }, nodeType, expanded) => ({
|
||||
style: {
|
||||
...style,
|
||||
textTransform: expanded ? 'uppercase' : style.textTransform
|
||||
}
|
||||
})
|
||||
}} />
|
||||
<JSONTree
|
||||
data={data}
|
||||
theme={{
|
||||
extend: theme,
|
||||
// underline keys for literal values
|
||||
valueLabel: {
|
||||
textDecoration: 'underline'
|
||||
},
|
||||
// switch key for objects to uppercase when object is expanded.
|
||||
// `nestedNodeLabel` receives additional arguments `expanded` and `keyPath`
|
||||
nestedNodeLabel: ({ style }, nodeType, expanded) => ({
|
||||
style: {
|
||||
...style,
|
||||
textTransform: expanded ? 'uppercase' : style.textTransform
|
||||
}
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
@ -120,8 +123,8 @@ You can pass the following properties to customize rendered labels and values:
|
|||
|
||||
```jsx
|
||||
<JSONTree
|
||||
labelRenderer={raw => <strong>{raw}</strong>}
|
||||
valueRenderer={raw => <em>{raw}</em>}
|
||||
labelRenderer={raw => <strong>{raw}</strong>}
|
||||
valueRenderer={raw => <em>{raw}</em>}
|
||||
/>
|
||||
```
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
react-hot-boilerplate
|
||||
=====================
|
||||
# react-hot-boilerplate
|
||||
|
||||
The minimal dev environment to enable live-editing React components.
|
||||
|
||||
|
@ -32,16 +31,16 @@ This boilerplate is purposefully simple to show the minimal configuration for Re
|
|||
|
||||
### Dependencies
|
||||
|
||||
* React
|
||||
* Webpack
|
||||
* [webpack-dev-server](https://github.com/webpack/webpack-dev-server)
|
||||
* [babel-loader](https://github.com/babel/babel-loader)
|
||||
* [react-hot-loader](https://github.com/gaearon/react-hot-loader)
|
||||
- React
|
||||
- Webpack
|
||||
- [webpack-dev-server](https://github.com/webpack/webpack-dev-server)
|
||||
- [babel-loader](https://github.com/babel/babel-loader)
|
||||
- [react-hot-loader](https://github.com/gaearon/react-hot-loader)
|
||||
|
||||
### Resources
|
||||
|
||||
* [Demo video](http://vimeo.com/100010922)
|
||||
* [react-hot-loader on Github](https://github.com/gaearon/react-hot-loader)
|
||||
* [Integrating JSX live reload into your workflow](http://gaearon.github.io/react-hot-loader/getstarted/)
|
||||
* [Troubleshooting guide](https://github.com/gaearon/react-hot-loader/blob/master/docs/Troubleshooting.md)
|
||||
* Ping dan_abramov on Twitter or #reactjs IRC
|
||||
- [Demo video](http://vimeo.com/100010922)
|
||||
- [react-hot-loader on Github](https://github.com/gaearon/react-hot-loader)
|
||||
- [Integrating JSX live reload into your workflow](http://gaearon.github.io/react-hot-loader/getstarted/)
|
||||
- [Troubleshooting guide](https://github.com/gaearon/react-hot-loader/blob/master/docs/Troubleshooting.md)
|
||||
- Ping dan_abramov on Twitter or #reactjs IRC
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user