Browse Source

Drag to reorder sections

update-deps
Alex Mikhalev 7 years ago
parent
commit
116c803ec7
  1. 74
      app/components/ProgramSequenceView.tsx
  2. 65
      app/styles/DurationView.scss
  3. 23
      app/styles/ProgramSequenceView.scss
  4. 4
      app/styles/SectionChooser.scss
  5. 2
      package.json
  6. 29
      yarn.lock

74
app/components/ProgramSequenceView.tsx

@ -1,7 +1,9 @@ @@ -1,7 +1,9 @@
import classNames = require("classnames");
import { observer } from "mobx-react";
import * as React from "react";
import { Form, List } from "semantic-ui-react";
import * as ReactDOM from "react-dom";
import { SortableContainer, SortableElement, SortableHandle, SortEnd, arrayMove } from "react-sortable-hoc";
import { Form, Icon, List } from "semantic-ui-react";
import { DurationView, SectionChooser } from "@app/components/index";
import { Duration } from "@common/Duration";
@ -9,6 +11,8 @@ import { ProgramItem, Section } from "@common/sprinklersRpc"; @@ -9,6 +11,8 @@ import { ProgramItem, Section } from "@common/sprinklersRpc";
import "@app/styles/ProgramSequenceView";
const Handle = SortableHandle(() => <Icon name="bars"/>);
@observer
class ProgramSequenceItem extends React.Component<{
sequenceItem: ProgramItem, sections: Section[], onChange?: (newItem: ProgramItem) => void,
@ -21,17 +25,15 @@ class ProgramSequenceItem extends React.Component<{ @@ -21,17 +25,15 @@ class ProgramSequenceItem extends React.Component<{
if (editing) {
return (
<Form.Group inline>
<Form.Group>
<SectionChooser
label="Section"
inline
sections={sections}
value={section}
onChange={this.onSectionChange}
/>
<DurationView
label="Duration"
inline
duration={duration}
onDurationChange={this.onDurationChange}
/>
@ -48,11 +50,12 @@ class ProgramSequenceItem extends React.Component<{ @@ -48,11 +50,12 @@ class ProgramSequenceItem extends React.Component<{
}
render() {
const editing = this.props.onChange != null;
return (
<List.Item>
<List.Icon name="caret right"/>
<li className="programSequence-item ui form">
{editing ? <Handle /> : <List.Icon name="caret right"/>}
<List.Content>{this.renderContent()}</List.Content>
</List.Item>
</li>
);
}
@ -75,22 +78,65 @@ class ProgramSequenceItem extends React.Component<{ @@ -75,22 +78,65 @@ class ProgramSequenceItem extends React.Component<{
}
}
const ProgramSequenceItemD = SortableElement(ProgramSequenceItem);
type ItemChangeHandler = (newItem: ProgramItem, index: number) => void;
const ProgramSequenceList = SortableContainer(observer(({ className, list, sections, onChange }: {
className: string,
list: ProgramItem[],
sections: Section[],
onChange?: ItemChangeHandler,
}) => {
const listItems = list.map((item, index) => {
const onChangeHandler = onChange ? (newItem: ProgramItem) => onChange(newItem, index) : undefined;
const key = `item-${index}`;
return (
<ProgramSequenceItemD
sequenceItem={item}
sections={sections}
key={key}
index={index}
onChange={onChangeHandler}
/>
);
});
return <ul className={className}>{listItems}</ul>;
}), { withRef: true });
@observer
export default class ProgramSequenceView extends React.Component<{
class ProgramSequenceView extends React.Component<{
sequence: ProgramItem[], sections: Section[], editing?: boolean,
}> {
render() {
const { sequence, sections } = this.props;
const editing = this.props.editing || false;
const className = classNames("programSequence", { editing });
const sequenceItems = sequence.map((item, index) => {
const onChange = editing ? (newItem: ProgramItem) => this.changeItem(newItem, index) : undefined;
return <ProgramSequenceItem sequenceItem={item} sections={sections} key={index} onChange={onChange}/>;
});
return <List className={className}>{sequenceItems}</List>;
const onChange = editing ? this.changeItem : undefined;
return (
<ProgramSequenceList
className={className}
useDragHandle
list={sequence}
sections={sections}
onChange={onChange}
onSortEnd={this.onSortEnd}
/>
);
}
private changeItem = (newItem: ProgramItem, index: number) => {
private changeItem: ItemChangeHandler = (newItem, index) => {
this.props.sequence[index] = newItem;
}
private onSortEnd = ({oldIndex, newIndex}: SortEnd) => {
const { sequence: array } = this.props;
if (newIndex >= array.length) {
return;
}
array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
}
}
const ProgramSequenceViewD = SortableContainer(ProgramSequenceView);
export default ProgramSequenceViewD;

65
app/styles/DurationView.scss

@ -1,49 +1,42 @@ @@ -1,49 +1,42 @@
$durationInput-spacing: 1.0em;
$durationInput-inputWidth: 4em;
$durationInput-labelWidth: 2.5em;
.durationInputs {
display: flex;
// max-width: 100%;
.field .durationInputs {
display: flex; // max-width: 100%;
justify-content: start;
flex-wrap: wrap;
margin: -$durationInput-spacing / 2;
&.inline {
min-width: 20em;
.ui.input.durationInput {
>input {
width: 0 !important;
}
}
}
}
$durationInput-inputWidth: 4em;
$durationInput-labelWidth: 2.5em;
.ui.form .field .ui.input.durationInput {
padding: $durationInput-spacing / 2;
max-width: 100%;
width: auto;
flex-basis: auto;
flex-shrink: 0;
flex-grow: 1;
> input {
min-width: $durationInput-inputWidth;
width: auto;
flex-basis: $durationInput-inputWidth;
flex-grow: 1;
flex-shrink: 0;
.ui.input.durationInput>input {
width: 0 !important;
}
> .label {
min-width: $durationInput-labelWidth;
width: $durationInput-labelWidth;
flex: $durationInput-labelWidth;
flex-grow: 0;
.ui.input.durationInput {
padding: $durationInput-spacing / 2;
max-width: 100%;
width: auto !important;
flex-basis: auto;
flex-shrink: 0;
text-align: center;
flex-grow: 1;
>input {
min-width: $durationInput-inputWidth;
width: auto;
flex-basis: $durationInput-inputWidth;
flex-grow: 1;
flex-shrink: 0;
}
>.label {
min-width: $durationInput-labelWidth;
width: $durationInput-labelWidth;
flex: $durationInput-labelWidth;
flex-grow: 0;
flex-shrink: 0;
text-align: center;
}
}
}

23
app/styles/ProgramSequenceView.scss

@ -1,3 +1,22 @@ @@ -1,3 +1,22 @@
.programSequence.editing .item .content {
width: 20em;
.programSequence {
&.editing .programSequence-item .content {
// width: 20em;
}
padding-left: 0;
}
.programSequence-item {
list-style-type: none;
z-index: 2000;
display: flex;
margin-bottom: .5em;
i.icon {
margin: .5rem;
}
.header {
font-weight: bold;
}
.durationInputs {
width: 20em;
}
}

4
app/styles/SectionChooser.scss

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
.sectionChooser {
.ui.selection.dropdown {
min-width: 14em;
min-width: 10em;
max-width: 100%;
width: 14em !important;
}
}

2
package.json

@ -72,6 +72,7 @@ @@ -72,6 +72,7 @@
"@types/react-dom": "16.0.6",
"@types/react-hot-loader": "^4.1.0",
"@types/react-router-dom": "^4.3.0",
"@types/react-sortable-hoc": "^0.6.3",
"@types/webpack-env": "^1.13.6",
"@types/ws": "^5.1.2",
"async": "^2.6.1",
@ -105,6 +106,7 @@ @@ -105,6 +106,7 @@
"react-hot-loader": "^4.3.3",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-sortable-hoc": "^0.8.3",
"sass-loader": "^7.0.3",
"semantic-ui-css": "^2.3.3",
"semantic-ui-react": "^0.82.1",

29
yarn.lock

@ -144,6 +144,12 @@ @@ -144,6 +144,12 @@
"@types/history" "*"
"@types/react" "*"
"@types/react-sortable-hoc@^0.6.3":
version "0.6.3"
resolved "https://registry.yarnpkg.com/@types/react-sortable-hoc/-/react-sortable-hoc-0.6.3.tgz#b9d034ab2728691ef3270ede5f4b4fd1cead52bd"
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@16.4.7":
version "16.4.7"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.7.tgz#f33f6d759a7e1833befa15224d68942d178a5a3f"
@ -641,6 +647,13 @@ babel-code-frame@6.26.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: @@ -641,6 +647,13 @@ babel-code-frame@6.26.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
esutils "^2.0.2"
js-tokens "^3.0.2"
babel-runtime@^6.11.6:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
@ -1442,7 +1455,7 @@ core-js@^1.0.0: @@ -1442,7 +1455,7 @@ core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
core-js@^2.5.7:
core-js@^2.4.0, core-js@^2.5.7:
version "2.5.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
@ -5624,7 +5637,7 @@ promise@^8.0.1: @@ -5624,7 +5637,7 @@ promise@^8.0.1:
dependencies:
asap "~2.0.3"
prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2:
prop-types@^15.5.7, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
dependencies:
@ -5858,6 +5871,14 @@ react-router@^4.3.1: @@ -5858,6 +5871,14 @@ react-router@^4.3.1:
prop-types "^15.6.1"
warning "^4.0.1"
react-sortable-hoc@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-0.8.3.tgz#8537e8ab8d6bad6829885755a0f847817ed78648"
dependencies:
babel-runtime "^6.11.6"
invariant "^2.2.1"
prop-types "^15.5.7"
react@16.4.1:
version "16.4.1"
resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32"
@ -5954,6 +5975,10 @@ regenerate@^1.2.1: @@ -5954,6 +5975,10 @@ regenerate@^1.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
regenerator-runtime@^0.11.0:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
regenerator-runtime@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.0.tgz#8052ac952d85b10f3425192cd0c53f45cf65c6cb"

Loading…
Cancel
Save