diff --git a/components/Carbon.js b/components/Carbon.js index 7bdbd1e..a06b3a4 100644 --- a/components/Carbon.js +++ b/components/Carbon.js @@ -265,11 +265,7 @@ class Carbon extends React.PureComponent { } const modesLoaded = new Set() -function CarbonContainer(props, ref) { - const [selectedLines, setSelected] = React.useState({}) - const editorRef = React.useRef(null) - const prevLine = React.useRef(null) - +function useModeLoader() { React.useEffect(() => { LANGUAGES.filter(language => language.mode !== 'auto' && language.mode !== 'text').forEach( language => { @@ -282,49 +278,61 @@ function CarbonContainer(props, ref) { } ) }, []) +} - function onGutterClick(editor, lineNumber, gutter, e) { - setSelected(currState => { - const newState = {} - - if (e.shiftKey && prevLine.current != null) { - for ( - let i = Math.min(prevLine.current, lineNumber); - i < Math.max(prevLine.current, lineNumber) + 1; - i++ - ) { - newState[i] = currState[prevLine.current] - } - - return { ...currState, ...newState } - } +function selectedLinesReducer({ prevLine, selected }, { type, lineNumber, numLines }) { + const newState = {} - for (let i = 0; i < editor.display.view.length; i++) { - if (i != lineNumber) { - if (prevLine.current == null) { - newState[i] = false - } - } else { - newState[lineNumber] = currState[lineNumber] === true ? false : true + if (type === 'GROUP' && prevLine) { + for (let i = Math.min(prevLine, lineNumber); i < Math.max(prevLine, lineNumber) + 1; i++) { + newState[i] = selected[prevLine] + } + } else { + for (let i = 0; i < numLines; i++) { + if (i != lineNumber) { + if (prevLine == null) { + newState[i] = false } + } else { + newState[lineNumber] = selected[lineNumber] === true ? false : true } + } + } - return { ...currState, ...newState } - }) + return { + selected: { ...selected, ...newState }, + prevLine: lineNumber + } +} + +function CarbonContainer(props, ref) { + useModeLoader() - prevLine.current = lineNumber + const [state, dispatch] = React.useReducer(selectedLinesReducer, { + prevLine: null, + selected: {} + }) + + function onGutterClick(editor, lineNumber, gutter, e) { + const numLines = editor.display.view.length + if (e.shiftKey) { + dispatch({ type: 'GROUP', lineNumber, numLines }) + } else { + dispatch({ type: 'LINE', lineNumber, numLines }) + } } + const editorRef = React.useRef(null) React.useEffect(() => { if (editorRef.current) { editorRef.current.editor.display.view.forEach((line, i) => { if (line.text && line.gutter) { - line.text.style.opacity = selectedLines[i] === false ? 0.5 : 1 - line.gutter.style.opacity = selectedLines[i] === false ? 0.5 : 1 + line.text.style.opacity = state.selected[i] === false ? 0.5 : 1 + line.gutter.style.opacity = state.selected[i] === false ? 0.5 : 1 } }) } - }, [selectedLines, props.children, props.config]) + }, [state.selected, props.children, props.config]) return }