diff --git a/app/components/ProgramSequenceView.tsx b/app/components/ProgramSequenceView.tsx index 4903f11..ece2ab3 100644 --- a/app/components/ProgramSequenceView.tsx +++ b/app/components/ProgramSequenceView.tsx @@ -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"; import "@app/styles/ProgramSequenceView"; +const Handle = SortableHandle(() => ); + @observer class ProgramSequenceItem extends React.Component<{ sequenceItem: ProgramItem, sections: Section[], onChange?: (newItem: ProgramItem) => void, @@ -21,17 +25,15 @@ class ProgramSequenceItem extends React.Component<{ if (editing) { return ( - + @@ -48,11 +50,12 @@ class ProgramSequenceItem extends React.Component<{ } render() { + const editing = this.props.onChange != null; return ( - - +
  • + {editing ? : } {this.renderContent()} - +
  • ); } @@ -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 ( + + ); + }); + return
      {listItems}
    ; +}), { 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 ; - }); - return {sequenceItems}; + const onChange = editing ? this.changeItem : undefined; + return ( + + ); } - 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; diff --git a/app/styles/DurationView.scss b/app/styles/DurationView.scss index 0a2d838..b204e80 100644 --- a/app/styles/DurationView.scss +++ b/app/styles/DurationView.scss @@ -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; + } } -} +} \ No newline at end of file diff --git a/app/styles/ProgramSequenceView.scss b/app/styles/ProgramSequenceView.scss index 62d19aa..061f058 100644 --- a/app/styles/ProgramSequenceView.scss +++ b/app/styles/ProgramSequenceView.scss @@ -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; + } +} \ No newline at end of file diff --git a/app/styles/SectionChooser.scss b/app/styles/SectionChooser.scss index 8f95232..3376746 100644 --- a/app/styles/SectionChooser.scss +++ b/app/styles/SectionChooser.scss @@ -1,5 +1,7 @@ .sectionChooser { .ui.selection.dropdown { - min-width: 14em; + min-width: 10em; + max-width: 100%; + width: 14em !important; } } diff --git a/package.json b/package.json index fbeaad1..6b00d33 100644 --- a/package.json +++ b/package.json @@ -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 @@ "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", diff --git a/yarn.lock b/yarn.lock index f7d7327..3a7e1ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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: 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: 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: 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: 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: 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"