diff --git a/app/assets/stylesheets/common/_focusable.scss b/app/assets/stylesheets/common/_focusable.scss
new file mode 100644
index 00000000..eb3af643
--- /dev/null
+++ b/app/assets/stylesheets/common/_focusable.scss
@@ -0,0 +1,6 @@
+/* License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later */
+.focusable_item {
+ &:focus {
+ outline: 1px dotted black
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/global.css.scss b/app/assets/stylesheets/global.css.scss
index 745425dc..e89aee50 100644
--- a/app/assets/stylesheets/global.css.scss
+++ b/app/assets/stylesheets/global.css.scss
@@ -43,3 +43,5 @@
@import 'common/z_indices';
@import 'common/ios_hack';
@import 'common/minimal';
+
+@import 'common/focusable'
\ No newline at end of file
diff --git a/javascripts/src/components/common/BootstrapWrapper.tsx b/javascripts/src/components/common/BootstrapWrapper.tsx
new file mode 100644
index 00000000..231f2003
--- /dev/null
+++ b/javascripts/src/components/common/BootstrapWrapper.tsx
@@ -0,0 +1,16 @@
+// License: LGPL-3.0-or-later
+import * as React from 'react';
+import { observer } from 'mobx-react';
+
+class BootstrapWrapper extends React.Component<{}, {}> {
+ render() {
+ return
+ {this.props.children}
+
;
+ }
+}
+
+export default observer(BootstrapWrapper)
+
+
+
diff --git a/javascripts/src/components/common/DefaultCloseButton.tsx b/javascripts/src/components/common/DefaultCloseButton.tsx
new file mode 100644
index 00000000..2ce37e3e
--- /dev/null
+++ b/javascripts/src/components/common/DefaultCloseButton.tsx
@@ -0,0 +1,115 @@
+import React = require("react");
+import { action, observable } from "mobx";
+import { Transition } from "react-transition-group";
+import { CloseButton } from "./svg/CloseButton";
+import color = require("color");
+import { observer } from "mobx-react";
+import ScreenReaderOnlyText from "./ScreenReaderOnlyText";
+
+interface DefaultCloseButtonProps {
+ onClick?: () => void
+}
+
+const mainColor = '#969696'
+const darkenedColor = color(mainColor).darken(0.1).hex()
+const defaultStyles = {
+ foreground: {
+ fill: mainColor
+ },
+ background: {
+ stroke: mainColor,
+ fill: '#FFFFFF'
+ }
+}
+
+const states: { [state: string]: any } = {
+ entering: {
+ foreground: {
+ fill: darkenedColor,
+ transition: 'fill 250ms ease-in-out'
+ },
+ background: {
+ stroke: darkenedColor,
+ transition: 'stroke 250ms ease-in-out'
+ }
+ },
+ entered: {
+ foreground: {
+ fill: darkenedColor,
+ },
+ background: {
+ stroke: darkenedColor,
+ }
+ },
+ exiting: {
+ foreground: {
+ fill: mainColor,
+ transition: 'fill 250ms ease-in-out'
+ },
+ background: {
+ stroke: mainColor,
+ transition: 'stroke 250ms ease-in-out'
+ }
+ },
+ exited: {
+ foreground: {
+ fill: mainColor,
+ },
+ background: {
+ stroke: mainColor,
+ }
+ }
+}
+
+@observer
+export class DefaultCloseButton extends React.Component {
+ @observable
+ hovering: boolean
+
+ @observable
+ focusing: boolean
+
+ @action.bound
+ mouseEnter() {
+ this.hovering = true;
+ }
+
+ @action.bound
+ mouseLeave() {
+ this.hovering = false;
+ }
+
+ @action.bound
+ keyDown(event: React.KeyboardEvent) {
+ if (event.key == 'Enter') {
+ event.preventDefault();
+ this.props.onClick();
+ }
+ }
+
+ render() {
+ return
+ {(hoverState) => {
+ const backgroundStyle = {
+ ...defaultStyles.background,
+ ...((states[hoverState] && states[hoverState].background) || {})
+ }
+
+ const foregroundStyle =
+ {
+ ...defaultStyles.foreground,
+ ...((states[hoverState] && states[hoverState].foreground) || {})
+ }
+
+ return
+ Close modal
+
+
+ }
+ }
+
+
+ }
+}
diff --git a/javascripts/src/components/common/Modal.spec.tsx b/javascripts/src/components/common/Modal.spec.tsx
index dcad6ee5..7e534f25 100644
--- a/javascripts/src/components/common/Modal.spec.tsx
+++ b/javascripts/src/components/common/Modal.spec.tsx
@@ -2,9 +2,9 @@
import * as React from 'react';
import 'jest';
import Modal, {ModalProps} from './Modal'
-import {shallow} from "enzyme";
-import {toJS} from "mobx";
+import {shallow, mount, ReactWrapper} from "enzyme";
import toJson from "enzyme-to-json";
+import { DefaultCloseButton } from './DefaultCloseButton';
describe('Modal', () => {
test('nothing displayed if inactive', () => {
@@ -13,16 +13,47 @@ describe('Modal', () => {
expect(toJson(modal)).toMatchSnapshot()
})
- test('active modal displays', () => {
+ describe('active modal displays', () => {
let onCloseWasCalled = false
- let modal = shallow( {
+ onCloseWasCalled = false;
+ modal = mount( { onCloseWasCalled = true}}
+ childGenerator={() => }/>)
+ })
+
+ it('matches snapshot', () => {
+ expect(toJson(modal)).toMatchSnapshot()
+ })
+
+ it('closes on modal component close', () => {
+ let modalComponent = modal.instance() as React.Component //casting to modal didn't work for reasons?
+ modalComponent.props.onClose()
+ expect(onCloseWasCalled).toBeTruthy()
+ })
+
+ it('closes on closeButtonClick', () => {
+ let closeButton = modal.find('DefaultCloseButton')
+ let instanceButton = closeButton.instance() as DefaultCloseButton
+ instanceButton.props.onClick();
+ expect(onCloseWasCalled).toBeTruthy()
+ })
+ })
+
+
+ it('doesnt have a close button if we ask for none', () => {
+ let onCloseWasCalled = false
+ let modal = mount( { onCloseWasCalled = true}}
- childGenerator={() => }/>)
- expect(toJson(modal)).toMatchSnapshot()
- let modalComponent = modal.instance() as React.Component //casting to modal didn't work for reasons?
- modalComponent.props.onClose()
- expect(onCloseWasCalled).toBeTruthy()
+ childGenerator={() => }
+ />)
+ expect(modal.find('DefaultCloseButton').exists()).toBeFalsy()
})
+
})
\ No newline at end of file
diff --git a/javascripts/src/components/common/Modal.tsx b/javascripts/src/components/common/Modal.tsx
index 819915d3..7c04dc1d 100644
--- a/javascripts/src/components/common/Modal.tsx
+++ b/javascripts/src/components/common/Modal.tsx
@@ -5,6 +5,9 @@ import AriaModal = require('react-aria-modal');
import { VelocityTransitionGroup } from 'velocity-react';
import 'velocity-animate';
import 'velocity-animate/velocity.ui';
+import { DefaultCloseButton } from './DefaultCloseButton';
+import BootstrapWrapper from './BootstrapWrapper';
+import { Row, Column } from './layout';
export interface ModalProps {
onClose?: () => void // if you want your modal to close, this needs to set modalActive to false
@@ -12,25 +15,44 @@ export interface ModalProps {
titleText?: string
focusDialog?: boolean
dialogStyle?: any
+ showCloseButton?: boolean
childGenerator: () => any
}
class Modal extends React.Component {
static defaultProps = {
- dialogStyle: { minWidth: '768px' }
+ dialogStyle: { minWidth: '768px' },
+ showCloseButton: true
}
render() {
-
const innerModal = this.props.modalActive ?
-
- {this.props.titleText}
-
-
- {this.props.childGenerator()}
-
+
+
+
+
+ {this.props.titleText}
+
+ {this.props.showCloseButton ?
+
+
+ this.props.onClose()} />
+
+ : false
+ }
+
+
+
+
+ {this.props.childGenerator()}
+
+
+
: false
const modal =
@@ -61,7 +83,7 @@ class Modal extends React.Component {
}
}
}
-
+
runOnMount={true}>
{innerModal}
;
diff --git a/javascripts/src/components/common/ScreenReaderOnlyText.spec.tsx b/javascripts/src/components/common/ScreenReaderOnlyText.spec.tsx
new file mode 100644
index 00000000..b79664a0
--- /dev/null
+++ b/javascripts/src/components/common/ScreenReaderOnlyText.spec.tsx
@@ -0,0 +1,13 @@
+// License: LGPL-3.0-or-later
+import * as React from 'react';
+import 'jest';
+import ScreenReaderOnlyText from './ScreenReaderOnlyText'
+import toJson from 'enzyme-to-json';
+import { shallow } from 'enzyme';
+
+describe('ScreenReaderOnlyText', () => {
+ it('renders properly', () => {
+ let text = shallow(Test)
+ expect(toJson(text)).toMatchSnapshot()
+ })
+})
\ No newline at end of file
diff --git a/javascripts/src/components/common/ScreenReaderOnlyText.tsx b/javascripts/src/components/common/ScreenReaderOnlyText.tsx
new file mode 100644
index 00000000..132a71f5
--- /dev/null
+++ b/javascripts/src/components/common/ScreenReaderOnlyText.tsx
@@ -0,0 +1,29 @@
+// License: LGPL-3.0-or-later
+import * as React from 'react';
+
+export interface ScreenReaderOnlyTextProps
+{
+}
+
+class ScreenReaderOnlyText extends React.Component {
+
+
+ render() {
+ const style:React.CSSProperties = {
+ position: 'absolute',
+ width: '1px',
+ height: '1px',
+ padding: 0,
+ margin: '-1px',
+ overflow: 'hidden',
+ clip: 'rect(0,0,0,0)',
+ border: 0
+ }
+ return {this.props.children}
+ }
+}
+
+export default ScreenReaderOnlyText;
+
+
+
diff --git a/javascripts/src/components/common/__snapshots__/Modal.spec.tsx.snap b/javascripts/src/components/common/__snapshots__/Modal.spec.tsx.snap
index 178f305f..9ab548a2 100644
--- a/javascripts/src/components/common/__snapshots__/Modal.spec.tsx.snap
+++ b/javascripts/src/components/common/__snapshots__/Modal.spec.tsx.snap
@@ -1,68 +1,418 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Modal active modal displays 1`] = `
-
-
-
-
-
-
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ title text
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
exports[`Modal nothing displayed if inactive 1`] = `
diff --git a/javascripts/src/components/common/__snapshots__/ScreenReaderOnlyText.spec.tsx.snap b/javascripts/src/components/common/__snapshots__/ScreenReaderOnlyText.spec.tsx.snap
new file mode 100644
index 00000000..45084801
--- /dev/null
+++ b/javascripts/src/components/common/__snapshots__/ScreenReaderOnlyText.spec.tsx.snap
@@ -0,0 +1,20 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ScreenReaderOnlyText renders properly 1`] = `
+
+ Test
+
+`;
diff --git a/javascripts/src/components/common/__snapshots__/layout.spec.tsx.snap b/javascripts/src/components/common/__snapshots__/layout.spec.tsx.snap
new file mode 100644
index 00000000..b6c08e75
--- /dev/null
+++ b/javascripts/src/components/common/__snapshots__/layout.spec.tsx.snap
@@ -0,0 +1,142 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`layout Row renders multiple children properly 1`] = `
+
+
+
+`;
+
+exports[`layout Row renders single child properly 1`] = `
+
+
+
+`;
+
+exports[`layout ThreeColumnFields renders multiple children properly 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`layout ThreeColumnFields renders single child properly 1`] = `
+
+
+
+
+
+`;
+
+exports[`layout TwoColumnFields renders multiple children properly 1`] = `
+
+
+
+
+
+`;
+
+exports[`layout TwoColumnFields renders single child properly 1`] = `
+
+
+
+
+
+`;
diff --git a/javascripts/src/components/common/layout.spec.tsx b/javascripts/src/components/common/layout.spec.tsx
new file mode 100644
index 00000000..ffac94b0
--- /dev/null
+++ b/javascripts/src/components/common/layout.spec.tsx
@@ -0,0 +1,107 @@
+// License: LGPL-3.0-or-later
+import * as React from 'react';
+import 'jest';
+import Modal, { ModalProps } from './Modal'
+import { shallow, mount, ReactWrapper } from "enzyme";
+import toJson from "enzyme-to-json";
+import { DefaultCloseButton } from './DefaultCloseButton';
+import { Column, Row, ThreeColumnFields, TwoColumnFields } from './layout';
+
+const SimpleCheckerComponent = (props: { className?: string }) => {
+ return
+}
+
+describe('layout', () => {
+ describe('Column', () => {
+ it('sets proper class without none passed in', () => {
+ const column = shallow(
+
+ )
+
+ expect(column.find(SimpleCheckerComponent).props()['className']).toBe('col-sm-12 ')
+ })
+
+ it('sets proper class with one passed in', () => {
+ const column = shallow(
+
+ )
+
+ expect(column.find(SimpleCheckerComponent).props()['className'])
+ .toBe('col-lg-1 another_class')
+ })
+
+ it('sets proper display name', () => {
+ const column = shallow(
+
+ )
+ expect(Column.displayName).toBe('Column')
+ })
+ })
+
+ describe('Row', () => {
+ it('renders single child properly', () => {
+ const row = mount(
+
+
)
+
+ expect(toJson(row)).toMatchSnapshot()
+ })
+
+
+ it('renders multiple children properly', () => {
+ const row = mount(
+
+
+
)
+
+ expect(toJson(row)).toMatchSnapshot()
+ })
+
+ it('has correct display name', () => {
+ const row = mount(
+
+
)
+
+ expect(Row.displayName).toBe('Row')
+ })
+ })
+
+ describe('ThreeColumnFields',() => {
+ it('renders single child properly', () => {
+ const fields = mount(
+
+ )
+
+ expect(toJson(fields)).toMatchSnapshot()
+ })
+
+ it('renders multiple children properly', () => {
+ const fields = mount(
+
+
+
+ )
+
+ expect(toJson(fields)).toMatchSnapshot()
+ })
+ })
+
+ describe('TwoColumnFields',() => {
+ it('renders single child properly', () => {
+ const fields = mount(
+
+ )
+
+ expect(toJson(fields)).toMatchSnapshot()
+ })
+
+ it('renders multiple children properly', () => {
+ const fields = mount(
+
+
+ )
+
+ expect(toJson(fields)).toMatchSnapshot()
+ })
+ })
+})
\ No newline at end of file
diff --git a/javascripts/src/components/common/layout.tsx b/javascripts/src/components/common/layout.tsx
index 808933da..405aa960 100644
--- a/javascripts/src/components/common/layout.tsx
+++ b/javascripts/src/components/common/layout.tsx
@@ -3,36 +3,78 @@ import * as React from 'react';
import {observer} from "mobx-react";
import * as _ from 'lodash'
-export const TwoColumnFields = observer((props:{children:Array>}) => {
- return
+function arrayify
(items: Array|T){
+ return items instanceof Array ? items : [items]
+}
+
+export const TwoColumnFields: React.StatelessComponent<{}> = (props:{children:Array>|React.ReactElement}) => {
+ const children = arrayify(props.children)
+ return
{
- _.take(props.children, 2).map((i:React.ReactElement) => {
- let className = "col-sm-6"
- if (_.last(props.children) !== i){
+ children.map((i:React.ReactElement) => {
+ let className = ""
+ if (_.last(children) !== i){
className += " u-paddingRight--10"
}
if (i.props['className']){
className += i.props['className']
}
-
- return React.cloneElement(i, {wrapperClassName: className})
+ return
+ {React.cloneElement(i, {className: className})}
+
})}
-
-})
+
+}
-export const ThreeColumnFields = observer((props:{children:React.ReactElement[]}) => {
- return
+TwoColumnFields.displayName = 'TwoColumnFields'
+
+export const ThreeColumnFields: React.StatelessComponent<{}> = (props:{children:Array
>|React.ReactElement}) => {
+ const children = arrayify(props.children)
+ return
{
- _.take(props.children, 3).map((i:React.ReactElement) => {
- let className = "col-sm-4"
- if (_.last(props.children) !== i){
+ children.map((i:React.ReactElement) => {
+ let className = ""
+ if (_.last(children) !== i){
className += " u-paddingRight--10"
}
if (i.props['className']){
className += i.props['className']
}
-
- return React.cloneElement(i, {wrapperClassName: className})
+ return
+ {React.cloneElement(i, {className: className})}
+
})}
+
+}
+
+ThreeColumnFields.displayName = 'ThreeColumnFields'
+
+
+export const Row: React.StatelessComponent<{}> = (props:{children:Array>|React.ReactElement}) => {
+ return
+ {props.children}
-})
\ No newline at end of file
+}
+
+Row.displayName = 'Row'
+
+type ColumnBreakSize = 'xs'| 'sm'|'md'|'lg'
+type ColumnSpan = 1|2|3|4|5|6|7|8|9|10|11|12
+
+interface ColumnProps {
+ children:React.ReactElement
+ colSpan:ColumnSpan,
+ breakSize:ColumnBreakSize
+}
+
+export const Column: React.StatelessComponent = (props) => {
+ let className = `col-${props.breakSize}-${props.colSpan} `
+ props.children.props
+ if (props.children.props.className){
+ className += props.children.props['className']
+ }
+
+ return React.cloneElement(props.children, {className: className})
+}
+
+Column.displayName = 'Column'
diff --git a/javascripts/src/components/common/svg/CloseButton.tsx b/javascripts/src/components/common/svg/CloseButton.tsx
new file mode 100644
index 00000000..d8e23f00
--- /dev/null
+++ b/javascripts/src/components/common/svg/CloseButton.tsx
@@ -0,0 +1,39 @@
+// License: LGPL-3.0-or-later
+import React = require("react");
+interface CloseButtonProps {
+ backgroundCircleStyle:React.CSSProperties
+ foregroundCircleStyle:React.CSSProperties
+}
+
+export const CloseButton = (props: CloseButtonProps) => {
+ return
+}
\ No newline at end of file
diff --git a/javascripts/src/components/common/svg/checkbox.tsx b/javascripts/src/components/common/svg/checkbox.tsx
new file mode 100644
index 00000000..2f1840b7
--- /dev/null
+++ b/javascripts/src/components/common/svg/checkbox.tsx
@@ -0,0 +1,6 @@
+// License: LGPL-3.0-or-later
+import * as React from 'react';
+
+export const Checkbox = (props:React.SVGProps) => {
+ return
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 8cebff3d..58ee6b22 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -204,17 +204,17 @@
}
},
"@babel/runtime": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz",
- "integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==",
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz",
+ "integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==",
"requires": {
- "regenerator-runtime": "^0.12.0"
+ "regenerator-runtime": "^0.13.2"
},
"dependencies": {
"regenerator-runtime": {
- "version": "0.12.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz",
- "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg=="
+ "version": "0.13.2",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
+ "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
}
}
},
@@ -4974,6 +4974,30 @@
"integrity": "sha512-+T9qBbqe/jXtTjzVddArZExahoPPmt8eq3O1ZuCKZXjBVxf/ciUYNXrIDZJEVgYvpELnv6VlPRCfLzufRxpAag==",
"dev": true
},
+ "@types/color": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/color/-/color-3.0.0.tgz",
+ "integrity": "sha512-5qqtNia+m2I0/85+pd2YzAXaTyKO8j+svirO5aN+XaQJ5+eZ8nx0jPtEWZLxCi50xwYsX10xUHetFzfb1WEs4Q==",
+ "dev": true,
+ "requires": {
+ "@types/color-convert": "*"
+ }
+ },
+ "@types/color-convert": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-1.9.0.tgz",
+ "integrity": "sha512-OKGEfULrvSL2VRbkl/gnjjgbbF7ycIlpSsX7Nkab4MOWi5XxmgBYvuiQ7lcCFY5cPDz7MUNaKgxte2VRmtr4Fg==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "*"
+ }
+ },
+ "@types/color-name": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
+ "dev": true
+ },
"@types/enzyme": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.1.10.tgz",
@@ -5104,6 +5128,15 @@
"@types/react": "*"
}
},
+ "@types/react-transition-group": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.9.0.tgz",
+ "integrity": "sha512-hP7vUaZMVSWKxo133P8U51U6UZ7+pbY+eAQb8+p6SZ2rB1rj3mOTDgTzhhi+R2SCB4S+sWekAAGoxdiZPG0ReQ==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*"
+ }
+ },
"@types/sinon": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.3.3.tgz",
@@ -7402,7 +7435,8 @@
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+ "dev": true
},
"clone-deep": {
"version": "2.0.2",
@@ -7448,21 +7482,29 @@
}
},
"color": {
- "version": "0.11.3",
- "resolved": "https://registry.npmjs.org/color/-/color-0.11.3.tgz",
- "integrity": "sha1-S60dDVJJndANvW8IaEQkZ+STlOY=",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.1.0.tgz",
+ "integrity": "sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==",
"requires": {
- "clone": "^1.0.2",
- "color-convert": "^1.3.0",
- "color-string": "^0.3.0"
+ "color-convert": "^1.9.1",
+ "color-string": "^1.5.2"
},
"dependencies": {
"color-convert": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
- "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
- "color-name": "^1.1.1"
+ "color-name": "1.1.3"
+ }
+ },
+ "color-string": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
+ "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
+ "requires": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
}
}
}
@@ -7481,6 +7523,7 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
"integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
+ "dev": true,
"requires": {
"color-name": "^1.0.0"
}
@@ -7494,6 +7537,28 @@
"color": "^0.11.0",
"css-color-names": "0.0.4",
"has": "^1.0.1"
+ },
+ "dependencies": {
+ "color": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
+ "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.2",
+ "color-convert": "^1.3.0",
+ "color-string": "^0.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ }
}
},
"colors": {
@@ -7853,6 +7918,26 @@
"integrity": "sha1-tQS9BYabOSWd0MXvw12EMXbczEo=",
"dev": true
},
+ "color": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
+ "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.2",
+ "color-convert": "^1.3.0",
+ "color-string": "^0.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
@@ -15239,6 +15324,28 @@
"postcss": "^5.0.4",
"postcss-message-helpers": "^2.0.0",
"reduce-function-call": "^1.0.1"
+ },
+ "dependencies": {
+ "color": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
+ "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.2",
+ "color-convert": "^1.3.0",
+ "color-string": "^0.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ }
}
},
"postcss-color-hex-alpha": {
@@ -16732,11 +16839,11 @@
}
},
"react-transition-group": {
- "version": "2.5.3",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz",
- "integrity": "sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
+ "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
"requires": {
- "dom-helpers": "^3.3.1",
+ "dom-helpers": "^3.4.0",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4"
@@ -16759,11 +16866,6 @@
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
- },
- "react-is": {
- "version": "16.8.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.1.tgz",
- "integrity": "sha512-ioMCzVDWvCvKD8eeT+iukyWrBGrA3DiFYkXfBsVYIRdaREZuBjENG+KjrikavCLasozqRWTwFUagU/O4vPpRMA=="
}
}
},
@@ -17507,6 +17609,21 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
+ "simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+ "requires": {
+ "is-arrayish": "^0.3.1"
+ },
+ "dependencies": {
+ "is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+ }
+ }
+ },
"sinon": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.7.tgz",
diff --git a/package.json b/package.json
index b8fc04b6..a4cb5c71 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"generate-api-js": "rm -rf javascripts/api && npm run get-codegen-cli && npm run generate-openapi && java -jar .bin/swagger-codegen-cli.jar generate -l 'typescript-jquery' -i tmp/openapi.json -o javascripts/api --config 'swagger.json' -t lib/swagger-typescript-jquery"
},
"devDependencies": {
+ "@types/color": "^3.0.0",
"@types/enzyme": "^3.1.9",
"@types/enzyme-to-json": "^1.5.1",
"@types/es6-promise": "^3.3.0",
@@ -32,6 +33,7 @@
"@types/react-intl": "^2.3.7",
"@types/react-test-renderer": "^16.0.1",
"@types/react-text-mask": "^5.4.2",
+ "@types/react-transition-group": "^2.9.0",
"@types/sinon": "^4.3.3",
"@types/validator": "^9.4.1",
"@types/velocity-animate": "^1.2.33",
@@ -87,7 +89,7 @@
"attr-binder": "0.3.1",
"aws-sdk": "^2.402.0",
"chart.js": "2.1.4",
- "color": "0.11.3",
+ "color": "^3.1.0",
"commons.css": "0.1.8",
"cookie": "0.3.1",
"cropperjs": "1.0.0-beta.2",
@@ -138,6 +140,7 @@
"react-dom": "^16.3.1",
"react-intl": "^2.4.0",
"react-text-mask": "^5.3.0",
+ "react-transition-group": "^2.9.0",
"shuffle-array": "1.0.1",
"snabbdom": "0.3.0",
"snake-case": "2.1.0",