Merge pull request #183 from houdiniproject/layout_improvements
Layout improvements for modals and other areas
This commit is contained in:
commit
5de56f392c
17 changed files with 1177 additions and 117 deletions
6
app/assets/stylesheets/common/_focusable.scss
Normal file
6
app/assets/stylesheets/common/_focusable.scss
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,3 +43,5 @@
|
||||||
@import 'common/z_indices';
|
@import 'common/z_indices';
|
||||||
@import 'common/ios_hack';
|
@import 'common/ios_hack';
|
||||||
@import 'common/minimal';
|
@import 'common/minimal';
|
||||||
|
|
||||||
|
@import 'common/focusable'
|
16
javascripts/src/components/common/BootstrapWrapper.tsx
Normal file
16
javascripts/src/components/common/BootstrapWrapper.tsx
Normal file
|
@ -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 <div className={"tw-bs"}>
|
||||||
|
{this.props.children}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default observer(BootstrapWrapper)
|
||||||
|
|
||||||
|
|
||||||
|
|
115
javascripts/src/components/common/DefaultCloseButton.tsx
Normal file
115
javascripts/src/components/common/DefaultCloseButton.tsx
Normal file
|
@ -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<DefaultCloseButtonProps, {}> {
|
||||||
|
@observable
|
||||||
|
hovering: boolean
|
||||||
|
|
||||||
|
@observable
|
||||||
|
focusing: boolean
|
||||||
|
|
||||||
|
@action.bound
|
||||||
|
mouseEnter() {
|
||||||
|
this.hovering = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action.bound
|
||||||
|
mouseLeave() {
|
||||||
|
this.hovering = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action.bound
|
||||||
|
keyDown(event: React.KeyboardEvent<HTMLAnchorElement>) {
|
||||||
|
if (event.key == 'Enter') {
|
||||||
|
event.preventDefault();
|
||||||
|
this.props.onClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <Transition in={this.hovering} timeout={250}>
|
||||||
|
{(hoverState) => {
|
||||||
|
const backgroundStyle = {
|
||||||
|
...defaultStyles.background,
|
||||||
|
...((states[hoverState] && states[hoverState].background) || {})
|
||||||
|
}
|
||||||
|
|
||||||
|
const foregroundStyle =
|
||||||
|
{
|
||||||
|
...defaultStyles.foreground,
|
||||||
|
...((states[hoverState] && states[hoverState].foreground) || {})
|
||||||
|
}
|
||||||
|
|
||||||
|
return <a onMouseEnter={this.mouseEnter} onMouseLeave={this.mouseLeave} onClick={this.props.onClick} onKeyDown={this.keyDown} tabIndex={0} className={'focusable_item'}>
|
||||||
|
<CloseButton backgroundCircleStyle={backgroundStyle}
|
||||||
|
foregroundCircleStyle={foregroundStyle}
|
||||||
|
/><ScreenReaderOnlyText>Close modal</ScreenReaderOnlyText>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,9 +2,9 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import 'jest';
|
import 'jest';
|
||||||
import Modal, {ModalProps} from './Modal'
|
import Modal, {ModalProps} from './Modal'
|
||||||
import {shallow} from "enzyme";
|
import {shallow, mount, ReactWrapper} from "enzyme";
|
||||||
import {toJS} from "mobx";
|
|
||||||
import toJson from "enzyme-to-json";
|
import toJson from "enzyme-to-json";
|
||||||
|
import { DefaultCloseButton } from './DefaultCloseButton';
|
||||||
|
|
||||||
describe('Modal', () => {
|
describe('Modal', () => {
|
||||||
test('nothing displayed if inactive', () => {
|
test('nothing displayed if inactive', () => {
|
||||||
|
@ -13,16 +13,47 @@ describe('Modal', () => {
|
||||||
expect(toJson(modal)).toMatchSnapshot()
|
expect(toJson(modal)).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('active modal displays', () => {
|
describe('active modal displays', () => {
|
||||||
let onCloseWasCalled = false
|
let onCloseWasCalled = false
|
||||||
let modal = shallow(<Modal titleText={"title text"}
|
let modal:ReactWrapper
|
||||||
|
beforeEach(() => {
|
||||||
|
onCloseWasCalled = false;
|
||||||
|
modal = mount(<Modal titleText={"title text"}
|
||||||
|
focusDialog={true}
|
||||||
|
modalActive={true}
|
||||||
|
onClose={() => { onCloseWasCalled = true}}
|
||||||
|
childGenerator={() => <div/>}/>)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('matches snapshot', () => {
|
||||||
|
expect(toJson(modal)).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('closes on modal component close', () => {
|
||||||
|
let modalComponent = modal.instance() as React.Component<ModalProps, {}> //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(<Modal titleText={"title text"}
|
||||||
focusDialog={true}
|
focusDialog={true}
|
||||||
modalActive={true}
|
modalActive={true}
|
||||||
|
showCloseButton={false}
|
||||||
onClose={() => { onCloseWasCalled = true}}
|
onClose={() => { onCloseWasCalled = true}}
|
||||||
childGenerator={() => <div/>}/>)
|
childGenerator={() => <div/>}
|
||||||
expect(toJson(modal)).toMatchSnapshot()
|
/>)
|
||||||
let modalComponent = modal.instance() as React.Component<ModalProps, {}> //casting to modal didn't work for reasons?
|
expect(modal.find('DefaultCloseButton').exists()).toBeFalsy()
|
||||||
modalComponent.props.onClose()
|
|
||||||
expect(onCloseWasCalled).toBeTruthy()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
|
@ -5,6 +5,9 @@ import AriaModal = require('react-aria-modal');
|
||||||
import { VelocityTransitionGroup } from 'velocity-react';
|
import { VelocityTransitionGroup } from 'velocity-react';
|
||||||
import 'velocity-animate';
|
import 'velocity-animate';
|
||||||
import 'velocity-animate/velocity.ui';
|
import 'velocity-animate/velocity.ui';
|
||||||
|
import { DefaultCloseButton } from './DefaultCloseButton';
|
||||||
|
import BootstrapWrapper from './BootstrapWrapper';
|
||||||
|
import { Row, Column } from './layout';
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
onClose?: () => void // if you want your modal to close, this needs to set modalActive to false
|
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
|
titleText?: string
|
||||||
focusDialog?: boolean
|
focusDialog?: boolean
|
||||||
dialogStyle?: any
|
dialogStyle?: any
|
||||||
|
showCloseButton?: boolean
|
||||||
childGenerator: () => any
|
childGenerator: () => any
|
||||||
}
|
}
|
||||||
|
|
||||||
class Modal extends React.Component<ModalProps, {}> {
|
class Modal extends React.Component<ModalProps, {}> {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
dialogStyle: { minWidth: '768px' }
|
dialogStyle: { minWidth: '768px' },
|
||||||
|
showCloseButton: true
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const innerModal = this.props.modalActive ? <AriaModal mounted={this.props.modalActive} titleText={this.props.titleText} focusDialog={this.props.focusDialog}
|
const innerModal = this.props.modalActive ? <AriaModal mounted={this.props.modalActive} titleText={this.props.titleText} focusDialog={this.props.focusDialog}
|
||||||
onExit={this.props.onClose} dialogStyle={this.props.dialogStyle}>
|
onExit={this.props.onClose} dialogStyle={this.props.dialogStyle}>
|
||||||
<header className='modal-header'>
|
<BootstrapWrapper>
|
||||||
<h4 className='modal-header-title'>{this.props.titleText}</h4>
|
<header className='modal-header' style={{
|
||||||
</header>
|
position: 'relative',
|
||||||
<div className="modal-body">
|
padding: '12px 10px 12px 20px'
|
||||||
{this.props.childGenerator()}
|
}}>
|
||||||
</div>
|
<Row>
|
||||||
|
<Column colSpan={11} breakSize={'xs'}>
|
||||||
|
<h3 className='modal-header-title' style={{ margin: 0 }}>{this.props.titleText}</h3>
|
||||||
|
</Column>
|
||||||
|
{this.props.showCloseButton ?
|
||||||
|
<Column colSpan={1} breakSize={'xs'}>
|
||||||
|
<div style={{ textAlign: 'right' }}>
|
||||||
|
<DefaultCloseButton onClick={() => this.props.onClose()} />
|
||||||
|
</div>
|
||||||
|
</Column> : false
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
</header>
|
||||||
|
<div className="modal-body">
|
||||||
|
<div style={{ position: 'relative' }}>
|
||||||
|
{this.props.childGenerator()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BootstrapWrapper>
|
||||||
</AriaModal> : false
|
</AriaModal> : false
|
||||||
|
|
||||||
const modal =
|
const modal =
|
||||||
|
@ -61,7 +83,7 @@ class Modal extends React.Component<ModalProps, {}> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runOnMount={true}>
|
runOnMount={true}>
|
||||||
{innerModal}
|
{innerModal}
|
||||||
</VelocityTransitionGroup>;
|
</VelocityTransitionGroup>;
|
||||||
|
|
|
@ -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(<ScreenReaderOnlyText>Test</ScreenReaderOnlyText>)
|
||||||
|
expect(toJson(text)).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
})
|
29
javascripts/src/components/common/ScreenReaderOnlyText.tsx
Normal file
29
javascripts/src/components/common/ScreenReaderOnlyText.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// License: LGPL-3.0-or-later
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export interface ScreenReaderOnlyTextProps
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScreenReaderOnlyText extends React.Component<ScreenReaderOnlyTextProps, {}> {
|
||||||
|
|
||||||
|
|
||||||
|
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 <span style={style}>{this.props.children}</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ScreenReaderOnlyText;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,68 +1,418 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Modal active modal displays 1`] = `
|
exports[`Modal active modal displays matches snapshot 1`] = `
|
||||||
<VelocityTransitionGroup
|
<Modal
|
||||||
enter={
|
childGenerator={[Function]}
|
||||||
|
dialogStyle={
|
||||||
Object {
|
Object {
|
||||||
"animation": "fadeIn",
|
"minWidth": "768px",
|
||||||
"style": Object {
|
|
||||||
"left": "0px",
|
|
||||||
"position": "fixed",
|
|
||||||
"top": "0px",
|
|
||||||
"zIndex": "5000",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enterHideStyle={
|
focusDialog={true}
|
||||||
Object {
|
modalActive={true}
|
||||||
"display": "none",
|
onClose={[Function]}
|
||||||
}
|
showCloseButton={true}
|
||||||
}
|
titleText="title text"
|
||||||
enterShowStyle={
|
|
||||||
Object {
|
|
||||||
"display": "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
leave={
|
|
||||||
Object {
|
|
||||||
"animation": "fadeOut",
|
|
||||||
"style": Object {
|
|
||||||
"left": "0px",
|
|
||||||
"position": "fixed",
|
|
||||||
"top": "0px",
|
|
||||||
"zIndex": "5000",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runOnMount={true}
|
|
||||||
>
|
>
|
||||||
<Displaced
|
<VelocityTransitionGroup
|
||||||
dialogStyle={
|
enter={
|
||||||
Object {
|
Object {
|
||||||
"minWidth": "768px",
|
"animation": "fadeIn",
|
||||||
|
"style": Object {
|
||||||
|
"left": "0px",
|
||||||
|
"position": "fixed",
|
||||||
|
"top": "0px",
|
||||||
|
"zIndex": "5000",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
focusDialog={true}
|
enterHideStyle={
|
||||||
mounted={true}
|
Object {
|
||||||
onExit={[Function]}
|
"display": "none",
|
||||||
titleText="title text"
|
}
|
||||||
|
}
|
||||||
|
enterShowStyle={
|
||||||
|
Object {
|
||||||
|
"display": "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
leave={
|
||||||
|
Object {
|
||||||
|
"animation": "fadeOut",
|
||||||
|
"style": Object {
|
||||||
|
"left": "0px",
|
||||||
|
"position": "fixed",
|
||||||
|
"top": "0px",
|
||||||
|
"zIndex": "5000",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runOnMount={true}
|
||||||
>
|
>
|
||||||
<header
|
<TransitionGroup
|
||||||
className="modal-header"
|
childFactory={[Function]}
|
||||||
|
component="div"
|
||||||
>
|
>
|
||||||
<h4
|
<div>
|
||||||
className="modal-header-title"
|
<Displaced
|
||||||
>
|
dialogStyle={
|
||||||
title text
|
Object {
|
||||||
</h4>
|
"minWidth": "768px",
|
||||||
</header>
|
}
|
||||||
<div
|
}
|
||||||
className="modal-body"
|
focusDialog={true}
|
||||||
>
|
in={true}
|
||||||
<div />
|
key=".0"
|
||||||
</div>
|
mounted={true}
|
||||||
</Displaced>
|
onExit={[Function]}
|
||||||
</VelocityTransitionGroup>
|
onExited={[Function]}
|
||||||
|
titleText="title text"
|
||||||
|
>
|
||||||
|
<Portal
|
||||||
|
containerInfo={
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
style="position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; z-index: 1050; overflow-x: hidden; overflow-y: auto; text-align: center; background: rgba(0, 0, 0, 0.5); cursor: pointer;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-label="title text"
|
||||||
|
id="react-aria-modal-dialog"
|
||||||
|
role="dialog"
|
||||||
|
style="display: inline-block; text-align: left; top: 0px; max-width: 100%; cursor: default; outline: 0; min-width: 768px;"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="tw-bs"
|
||||||
|
>
|
||||||
|
<header
|
||||||
|
class="modal-header"
|
||||||
|
style="position: relative; padding: 12px 10px 12px 20px;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="row"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="col-xs-11 modal-header-title"
|
||||||
|
style="margin: 0px;"
|
||||||
|
>
|
||||||
|
title text
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
class="col-xs-1 "
|
||||||
|
style="text-align: right;"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="focusable_item"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
height="24"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10.65625"
|
||||||
|
style="stroke: #969696; fill: #FFFFFF;"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="9.25"
|
||||||
|
style="fill: #969696;"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M 7.130438,16.869562 16.869562,7.130438"
|
||||||
|
style="stroke: #ffffff; stroke-width: 1.375; stroke-linecap: square;"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M 16.869562,16.869562 7.130438,7.130438"
|
||||||
|
style="stroke: #ffffff; stroke-width: 1.375; stroke-linecap: square;"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
style="position: absolute; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); border: 0px;"
|
||||||
|
>
|
||||||
|
Close modal
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div
|
||||||
|
class="modal-body"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style="position: relative;"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Modal
|
||||||
|
dialogId="react-aria-modal-dialog"
|
||||||
|
dialogStyle={
|
||||||
|
Object {
|
||||||
|
"minWidth": "768px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
escapeExits={true}
|
||||||
|
focusDialog={true}
|
||||||
|
focusTrapPaused={false}
|
||||||
|
in={true}
|
||||||
|
includeDefaultStyles={true}
|
||||||
|
mounted={true}
|
||||||
|
onExit={[Function]}
|
||||||
|
onExited={[Function]}
|
||||||
|
scrollDisabled={true}
|
||||||
|
titleText="title text"
|
||||||
|
underlayClickExits={true}
|
||||||
|
underlayColor="rgba(0,0,0,0.5)"
|
||||||
|
underlayProps={Object {}}
|
||||||
|
>
|
||||||
|
<FocusTrap
|
||||||
|
_createFocusTrap={[Function]}
|
||||||
|
active={true}
|
||||||
|
focusTrapOptions={
|
||||||
|
Object {
|
||||||
|
"escapeDeactivates": true,
|
||||||
|
"initialFocus": "#react-aria-modal-dialog",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paused={false}
|
||||||
|
tag="div"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"WebkitOverflowScrolling": "touch",
|
||||||
|
"background": "rgba(0,0,0,0.5)",
|
||||||
|
"cursor": "pointer",
|
||||||
|
"height": "100%",
|
||||||
|
"left": 0,
|
||||||
|
"overflowX": "hidden",
|
||||||
|
"overflowY": "auto",
|
||||||
|
"position": "fixed",
|
||||||
|
"textAlign": "center",
|
||||||
|
"top": 0,
|
||||||
|
"width": "100%",
|
||||||
|
"zIndex": 1050,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-label="title text"
|
||||||
|
id="react-aria-modal-dialog"
|
||||||
|
key="b"
|
||||||
|
role="dialog"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"cursor": "default",
|
||||||
|
"display": "inline-block",
|
||||||
|
"maxWidth": "100%",
|
||||||
|
"minWidth": "768px",
|
||||||
|
"outline": 0,
|
||||||
|
"textAlign": "left",
|
||||||
|
"top": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabIndex="-1"
|
||||||
|
>
|
||||||
|
<BootstrapWrapper>
|
||||||
|
<div
|
||||||
|
className="tw-bs"
|
||||||
|
>
|
||||||
|
<header
|
||||||
|
className="modal-header"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"padding": "12px 10px 12px 20px",
|
||||||
|
"position": "relative",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Row>
|
||||||
|
<div
|
||||||
|
className="row"
|
||||||
|
>
|
||||||
|
<Column
|
||||||
|
breakSize="xs"
|
||||||
|
colSpan={11}
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
className="col-xs-11 modal-header-title"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"margin": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
title text
|
||||||
|
</h3>
|
||||||
|
</Column>
|
||||||
|
<Column
|
||||||
|
breakSize="xs"
|
||||||
|
colSpan={1}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="col-xs-1 "
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"textAlign": "right",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DefaultCloseButton
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<Transition
|
||||||
|
appear={false}
|
||||||
|
enter={true}
|
||||||
|
exit={true}
|
||||||
|
in={false}
|
||||||
|
mountOnEnter={false}
|
||||||
|
onEnter={[Function]}
|
||||||
|
onEntered={[Function]}
|
||||||
|
onEntering={[Function]}
|
||||||
|
onExit={[Function]}
|
||||||
|
onExited={[Function]}
|
||||||
|
onExiting={[Function]}
|
||||||
|
timeout={250}
|
||||||
|
unmountOnExit={false}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
className="focusable_item"
|
||||||
|
onClick={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onMouseLeave={[Function]}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<Component
|
||||||
|
backgroundCircleStyle={
|
||||||
|
Object {
|
||||||
|
"fill": "#FFFFFF",
|
||||||
|
"stroke": "#969696",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foregroundCircleStyle={
|
||||||
|
Object {
|
||||||
|
"fill": "#969696",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
height="24"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10.65625"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"fill": "#FFFFFF",
|
||||||
|
"stroke": "#969696",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="9.25"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"fill": "#969696",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M 7.130438,16.869562 16.869562,7.130438"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"stroke": "#ffffff",
|
||||||
|
"strokeLinecap": "square",
|
||||||
|
"strokeWidth": 1.375,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M 16.869562,16.869562 7.130438,7.130438"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"stroke": "#ffffff",
|
||||||
|
"strokeLinecap": "square",
|
||||||
|
"strokeWidth": 1.375,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</Component>
|
||||||
|
<ScreenReaderOnlyText>
|
||||||
|
<span
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0,0,0,0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Close modal
|
||||||
|
</span>
|
||||||
|
</ScreenReaderOnlyText>
|
||||||
|
</a>
|
||||||
|
</Transition>
|
||||||
|
</DefaultCloseButton>
|
||||||
|
</div>
|
||||||
|
</Column>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</header>
|
||||||
|
<div
|
||||||
|
className="modal-body"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"position": "relative",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BootstrapWrapper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FocusTrap>
|
||||||
|
</Modal>
|
||||||
|
</Portal>
|
||||||
|
</Displaced>
|
||||||
|
</div>
|
||||||
|
</TransitionGroup>
|
||||||
|
</VelocityTransitionGroup>
|
||||||
|
</Modal>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Modal nothing displayed if inactive 1`] = `
|
exports[`Modal nothing displayed if inactive 1`] = `
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`ScreenReaderOnlyText renders properly 1`] = `
|
||||||
|
<span
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0,0,0,0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Test
|
||||||
|
</span>
|
||||||
|
`;
|
|
@ -0,0 +1,142 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`layout Row renders multiple children properly 1`] = `
|
||||||
|
<Row>
|
||||||
|
<div
|
||||||
|
className="row"
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
<SimpleCheckerComponent>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`layout Row renders single child properly 1`] = `
|
||||||
|
<Row>
|
||||||
|
<div
|
||||||
|
className="row"
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`layout ThreeColumnFields renders multiple children properly 1`] = `
|
||||||
|
<ThreeColumnFields>
|
||||||
|
<Row>
|
||||||
|
<div
|
||||||
|
className="row"
|
||||||
|
>
|
||||||
|
<Column
|
||||||
|
breakSize="sm"
|
||||||
|
colSpan={4}
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent
|
||||||
|
className="col-sm-4 u-paddingRight--10"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</Column>
|
||||||
|
<Column
|
||||||
|
breakSize="sm"
|
||||||
|
colSpan={4}
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent
|
||||||
|
className="col-sm-4 u-paddingRight--10"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</Column>
|
||||||
|
<Column
|
||||||
|
breakSize="sm"
|
||||||
|
colSpan={4}
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent
|
||||||
|
className="col-sm-4 "
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</Column>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</ThreeColumnFields>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`layout ThreeColumnFields renders single child properly 1`] = `
|
||||||
|
<ThreeColumnFields>
|
||||||
|
<Row>
|
||||||
|
<div
|
||||||
|
className="row"
|
||||||
|
>
|
||||||
|
<Column
|
||||||
|
breakSize="sm"
|
||||||
|
colSpan={4}
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent
|
||||||
|
className="col-sm-4 "
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</Column>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</ThreeColumnFields>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`layout TwoColumnFields renders multiple children properly 1`] = `
|
||||||
|
<TwoColumnFields>
|
||||||
|
<Row>
|
||||||
|
<div
|
||||||
|
className="row"
|
||||||
|
>
|
||||||
|
<Column
|
||||||
|
breakSize="sm"
|
||||||
|
colSpan={6}
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent
|
||||||
|
className="col-sm-6 u-paddingRight--10"
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</Column>
|
||||||
|
<Column
|
||||||
|
breakSize="sm"
|
||||||
|
colSpan={6}
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent
|
||||||
|
className="col-sm-6 "
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</Column>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</TwoColumnFields>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`layout TwoColumnFields renders single child properly 1`] = `
|
||||||
|
<TwoColumnFields>
|
||||||
|
<Row>
|
||||||
|
<div
|
||||||
|
className="row"
|
||||||
|
>
|
||||||
|
<Column
|
||||||
|
breakSize="sm"
|
||||||
|
colSpan={6}
|
||||||
|
>
|
||||||
|
<SimpleCheckerComponent
|
||||||
|
className="col-sm-6 "
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</SimpleCheckerComponent>
|
||||||
|
</Column>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</TwoColumnFields>
|
||||||
|
`;
|
107
javascripts/src/components/common/layout.spec.tsx
Normal file
107
javascripts/src/components/common/layout.spec.tsx
Normal file
|
@ -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 <div></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('layout', () => {
|
||||||
|
describe('Column', () => {
|
||||||
|
it('sets proper class without none passed in', () => {
|
||||||
|
const column = shallow(<Column colSpan={12} breakSize={'sm'}>
|
||||||
|
<SimpleCheckerComponent />
|
||||||
|
</Column>)
|
||||||
|
|
||||||
|
expect(column.find(SimpleCheckerComponent).props()['className']).toBe('col-sm-12 ')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets proper class with one passed in', () => {
|
||||||
|
const column = shallow(<Column colSpan={1} breakSize={'lg'}>
|
||||||
|
<SimpleCheckerComponent className="another_class" />
|
||||||
|
</Column>)
|
||||||
|
|
||||||
|
expect(column.find(SimpleCheckerComponent).props()['className'])
|
||||||
|
.toBe('col-lg-1 another_class')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets proper display name', () => {
|
||||||
|
const column = shallow(<Column colSpan={1} breakSize={'lg'}>
|
||||||
|
<SimpleCheckerComponent className="another_class" />
|
||||||
|
</Column>)
|
||||||
|
expect(Column.displayName).toBe('Column')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Row', () => {
|
||||||
|
it('renders single child properly', () => {
|
||||||
|
const row = mount(<Row>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
</Row>)
|
||||||
|
|
||||||
|
expect(toJson(row)).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it('renders multiple children properly', () => {
|
||||||
|
const row = mount(<Row>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
</Row>)
|
||||||
|
|
||||||
|
expect(toJson(row)).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has correct display name', () => {
|
||||||
|
const row = mount(<Row>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
</Row>)
|
||||||
|
|
||||||
|
expect(Row.displayName).toBe('Row')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('ThreeColumnFields',() => {
|
||||||
|
it('renders single child properly', () => {
|
||||||
|
const fields = mount(<ThreeColumnFields>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
</ThreeColumnFields>)
|
||||||
|
|
||||||
|
expect(toJson(fields)).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders multiple children properly', () => {
|
||||||
|
const fields = mount(<ThreeColumnFields>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
</ThreeColumnFields>)
|
||||||
|
|
||||||
|
expect(toJson(fields)).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('TwoColumnFields',() => {
|
||||||
|
it('renders single child properly', () => {
|
||||||
|
const fields = mount(<TwoColumnFields>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
</TwoColumnFields>)
|
||||||
|
|
||||||
|
expect(toJson(fields)).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders multiple children properly', () => {
|
||||||
|
const fields = mount(<TwoColumnFields>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
<SimpleCheckerComponent/>
|
||||||
|
</TwoColumnFields>)
|
||||||
|
|
||||||
|
expect(toJson(fields)).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -3,36 +3,78 @@ import * as React from 'react';
|
||||||
import {observer} from "mobx-react";
|
import {observer} from "mobx-react";
|
||||||
import * as _ from 'lodash'
|
import * as _ from 'lodash'
|
||||||
|
|
||||||
export const TwoColumnFields = observer((props:{children:Array<React.ReactElement<any>>}) => {
|
function arrayify<T>(items: Array<T>|T){
|
||||||
return <div className="row">
|
return items instanceof Array ? items : [items]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TwoColumnFields: React.StatelessComponent<{}> = (props:{children:Array<React.ReactElement<any>>|React.ReactElement<any>}) => {
|
||||||
|
const children = arrayify(props.children)
|
||||||
|
return <Row>
|
||||||
{
|
{
|
||||||
_.take(props.children, 2).map((i:React.ReactElement<any>) => {
|
children.map((i:React.ReactElement<any>) => {
|
||||||
let className = "col-sm-6"
|
let className = ""
|
||||||
if (_.last(props.children) !== i){
|
if (_.last(children) !== i){
|
||||||
className += " u-paddingRight--10"
|
className += " u-paddingRight--10"
|
||||||
}
|
}
|
||||||
if (i.props['className']){
|
if (i.props['className']){
|
||||||
className += i.props['className']
|
className += i.props['className']
|
||||||
}
|
}
|
||||||
|
return <Column colSpan={6} breakSize={'sm'}>
|
||||||
return React.cloneElement(i, {wrapperClassName: className})
|
{React.cloneElement(i, {className: className})}
|
||||||
|
</Column>
|
||||||
})}
|
})}
|
||||||
</div>
|
</Row>
|
||||||
})
|
}
|
||||||
|
|
||||||
export const ThreeColumnFields = observer((props:{children:React.ReactElement<any>[]}) => {
|
TwoColumnFields.displayName = 'TwoColumnFields'
|
||||||
return <div className="row">
|
|
||||||
|
export const ThreeColumnFields: React.StatelessComponent<{}> = (props:{children:Array<React.ReactElement<any>>|React.ReactElement<any>}) => {
|
||||||
|
const children = arrayify(props.children)
|
||||||
|
return <Row>
|
||||||
{
|
{
|
||||||
_.take(props.children, 3).map((i:React.ReactElement<any>) => {
|
children.map((i:React.ReactElement<any>) => {
|
||||||
let className = "col-sm-4"
|
let className = ""
|
||||||
if (_.last(props.children) !== i){
|
if (_.last(children) !== i){
|
||||||
className += " u-paddingRight--10"
|
className += " u-paddingRight--10"
|
||||||
}
|
}
|
||||||
if (i.props['className']){
|
if (i.props['className']){
|
||||||
className += i.props['className']
|
className += i.props['className']
|
||||||
}
|
}
|
||||||
|
return <Column colSpan={4} breakSize={'sm'}>
|
||||||
return React.cloneElement(i, {wrapperClassName: className})
|
{React.cloneElement(i, {className: className})}
|
||||||
|
</Column>
|
||||||
})}
|
})}
|
||||||
|
</Row>
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreeColumnFields.displayName = 'ThreeColumnFields'
|
||||||
|
|
||||||
|
|
||||||
|
export const Row: React.StatelessComponent<{}> = (props:{children:Array<React.ReactElement<any>>|React.ReactElement<any>}) => {
|
||||||
|
return <div className="row">
|
||||||
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
})
|
}
|
||||||
|
|
||||||
|
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<any>
|
||||||
|
colSpan:ColumnSpan,
|
||||||
|
breakSize:ColumnBreakSize
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Column: React.StatelessComponent<ColumnProps> = (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'
|
||||||
|
|
39
javascripts/src/components/common/svg/CloseButton.tsx
Normal file
39
javascripts/src/components/common/svg/CloseButton.tsx
Normal file
|
@ -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 <svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
version="1.1">
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10.65625"
|
||||||
|
style={props.backgroundCircleStyle} />
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="9.25"
|
||||||
|
style={props.foregroundCircleStyle} />
|
||||||
|
<path
|
||||||
|
d="M 7.130438,16.869562 16.869562,7.130438"
|
||||||
|
style={{
|
||||||
|
stroke: '#ffffff',
|
||||||
|
strokeWidth:1.375,
|
||||||
|
strokeLinecap:'square'
|
||||||
|
}} />
|
||||||
|
<path
|
||||||
|
d="M 16.869562,16.869562 7.130438,7.130438"
|
||||||
|
style={{
|
||||||
|
stroke: '#ffffff',
|
||||||
|
strokeWidth:1.375,
|
||||||
|
strokeLinecap:'square'
|
||||||
|
}} />
|
||||||
|
</svg>
|
||||||
|
}
|
6
javascripts/src/components/common/svg/checkbox.tsx
Normal file
6
javascripts/src/components/common/svg/checkbox.tsx
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// License: LGPL-3.0-or-later
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export const Checkbox = (props:React.SVGProps<SVGPathElement>) => {
|
||||||
|
return <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="10px" width="10px"><path d="M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z" {...props}/></svg>
|
||||||
|
}
|
171
package-lock.json
generated
171
package-lock.json
generated
|
@ -204,17 +204,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.3.1",
|
"version": "7.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz",
|
||||||
"integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==",
|
"integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.12.0"
|
"regenerator-runtime": "^0.13.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": {
|
"regenerator-runtime": {
|
||||||
"version": "0.12.1",
|
"version": "0.13.2",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
|
||||||
"integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg=="
|
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -4974,6 +4974,30 @@
|
||||||
"integrity": "sha512-+T9qBbqe/jXtTjzVddArZExahoPPmt8eq3O1ZuCKZXjBVxf/ciUYNXrIDZJEVgYvpELnv6VlPRCfLzufRxpAag==",
|
"integrity": "sha512-+T9qBbqe/jXtTjzVddArZExahoPPmt8eq3O1ZuCKZXjBVxf/ciUYNXrIDZJEVgYvpELnv6VlPRCfLzufRxpAag==",
|
||||||
"dev": true
|
"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": {
|
"@types/enzyme": {
|
||||||
"version": "3.1.10",
|
"version": "3.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.1.10.tgz",
|
||||||
|
@ -5104,6 +5128,15 @@
|
||||||
"@types/react": "*"
|
"@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": {
|
"@types/sinon": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.3.3.tgz",
|
||||||
|
@ -7402,7 +7435,8 @@
|
||||||
"clone": {
|
"clone": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
|
||||||
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
|
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"clone-deep": {
|
"clone-deep": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
|
@ -7448,21 +7482,29 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color": {
|
"color": {
|
||||||
"version": "0.11.3",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/color/-/color-0.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/color/-/color-3.1.0.tgz",
|
||||||
"integrity": "sha1-S60dDVJJndANvW8IaEQkZ+STlOY=",
|
"integrity": "sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"clone": "^1.0.2",
|
"color-convert": "^1.9.1",
|
||||||
"color-convert": "^1.3.0",
|
"color-string": "^1.5.2"
|
||||||
"color-string": "^0.3.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "1.9.1",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
"requires": {
|
"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",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
|
||||||
"integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
|
"integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "^1.0.0"
|
"color-name": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
@ -7494,6 +7537,28 @@
|
||||||
"color": "^0.11.0",
|
"color": "^0.11.0",
|
||||||
"css-color-names": "0.0.4",
|
"css-color-names": "0.0.4",
|
||||||
"has": "^1.0.1"
|
"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": {
|
"colors": {
|
||||||
|
@ -7853,6 +7918,26 @@
|
||||||
"integrity": "sha1-tQS9BYabOSWd0MXvw12EMXbczEo=",
|
"integrity": "sha1-tQS9BYabOSWd0MXvw12EMXbczEo=",
|
||||||
"dev": true
|
"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": {
|
"debug": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
@ -15239,6 +15324,28 @@
|
||||||
"postcss": "^5.0.4",
|
"postcss": "^5.0.4",
|
||||||
"postcss-message-helpers": "^2.0.0",
|
"postcss-message-helpers": "^2.0.0",
|
||||||
"reduce-function-call": "^1.0.1"
|
"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": {
|
"postcss-color-hex-alpha": {
|
||||||
|
@ -16732,11 +16839,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-transition-group": {
|
"react-transition-group": {
|
||||||
"version": "2.5.3",
|
"version": "2.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
|
||||||
"integrity": "sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==",
|
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"dom-helpers": "^3.3.1",
|
"dom-helpers": "^3.4.0",
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react-lifecycles-compat": "^3.0.4"
|
"react-lifecycles-compat": "^3.0.4"
|
||||||
|
@ -16759,11 +16866,6 @@
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"react-is": "^16.8.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=",
|
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||||
"dev": true
|
"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": {
|
"sinon": {
|
||||||
"version": "5.0.7",
|
"version": "5.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.7.tgz",
|
||||||
|
|
|
@ -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"
|
"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": {
|
"devDependencies": {
|
||||||
|
"@types/color": "^3.0.0",
|
||||||
"@types/enzyme": "^3.1.9",
|
"@types/enzyme": "^3.1.9",
|
||||||
"@types/enzyme-to-json": "^1.5.1",
|
"@types/enzyme-to-json": "^1.5.1",
|
||||||
"@types/es6-promise": "^3.3.0",
|
"@types/es6-promise": "^3.3.0",
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
"@types/react-intl": "^2.3.7",
|
"@types/react-intl": "^2.3.7",
|
||||||
"@types/react-test-renderer": "^16.0.1",
|
"@types/react-test-renderer": "^16.0.1",
|
||||||
"@types/react-text-mask": "^5.4.2",
|
"@types/react-text-mask": "^5.4.2",
|
||||||
|
"@types/react-transition-group": "^2.9.0",
|
||||||
"@types/sinon": "^4.3.3",
|
"@types/sinon": "^4.3.3",
|
||||||
"@types/validator": "^9.4.1",
|
"@types/validator": "^9.4.1",
|
||||||
"@types/velocity-animate": "^1.2.33",
|
"@types/velocity-animate": "^1.2.33",
|
||||||
|
@ -87,7 +89,7 @@
|
||||||
"attr-binder": "0.3.1",
|
"attr-binder": "0.3.1",
|
||||||
"aws-sdk": "^2.402.0",
|
"aws-sdk": "^2.402.0",
|
||||||
"chart.js": "2.1.4",
|
"chart.js": "2.1.4",
|
||||||
"color": "0.11.3",
|
"color": "^3.1.0",
|
||||||
"commons.css": "0.1.8",
|
"commons.css": "0.1.8",
|
||||||
"cookie": "0.3.1",
|
"cookie": "0.3.1",
|
||||||
"cropperjs": "1.0.0-beta.2",
|
"cropperjs": "1.0.0-beta.2",
|
||||||
|
@ -138,6 +140,7 @@
|
||||||
"react-dom": "^16.3.1",
|
"react-dom": "^16.3.1",
|
||||||
"react-intl": "^2.4.0",
|
"react-intl": "^2.4.0",
|
||||||
"react-text-mask": "^5.3.0",
|
"react-text-mask": "^5.3.0",
|
||||||
|
"react-transition-group": "^2.9.0",
|
||||||
"shuffle-array": "1.0.1",
|
"shuffle-array": "1.0.1",
|
||||||
"snabbdom": "0.3.0",
|
"snabbdom": "0.3.0",
|
||||||
"snake-case": "2.1.0",
|
"snake-case": "2.1.0",
|
||||||
|
|
Loading…
Reference in a new issue