diff --git a/.eslintrc b/.eslintrc index b3caa59e110484e128762039cca9c1c5c0645099..be0050216f5198f54da4da5beabf49284873554e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -26,6 +26,8 @@ "sort-keys": ["error", "asc", { "caseSensitive": false, "natural": false - }] + }], + "jsx-a11y/click-events-have-key-events": "off", + "jsx-a11y/no-static-element-interactions": "off" } } diff --git a/__tests__/AnnotationCreation.test.js b/__tests__/AnnotationCreation.test.js index 5f79a8291da2447385a5c2ff82ac5120400d13bf..d0a355d746333ab1330cbdc119c99fa262a45b2e 100644 --- a/__tests__/AnnotationCreation.test.js +++ b/__tests__/AnnotationCreation.test.js @@ -10,7 +10,7 @@ function createWrapper(props) { return shallow( <AnnotationCreation id="x" - config={{}} + config={{ annotation: {} }} receiveAnnotation={jest.fn()} windowId="abc" {...props} diff --git a/package.json b/package.json index 86c75e456435d93170471817b9e1607adb09a5e9..221eb8060d5cf145b92e471e47866b71434ce3d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirador-annotations", - "version": "0.4.0", + "version": "0.5.0", "description": "mirador-annotations React component", "main": "lib/index.js", "module": "es/index.js", @@ -21,8 +21,8 @@ "test:watch": "jest --watch" }, "dependencies": { - "@psychobolt/react-paperjs": "< 1.0", - "@psychobolt/react-paperjs-editor": "0.0.11", + "@psychobolt/react-paperjs": "^1.0.0", + "@psychobolt/react-paperjs-editor": "^0.0.14", "draft-js": "^0.11.6", "draft-js-export-html": "^1.4.1", "draft-js-import-html": "^1.4.1", @@ -37,8 +37,8 @@ "lodash": "^4.17.11", "mirador": "^3.0.0-rc.5", "prop-types": "^15.7.2", - "react": "^16.0", - "react-dom": "^16.0", + "react": "^17.0", + "react-dom": "^17.0", "uuid": "^8.0.0" }, "devDependencies": { @@ -48,14 +48,14 @@ "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.56", + "@wojtekmaj/enzyme-adapter-react-17": "^0.6.0", "babel-eslint": "^10.1.0", "canvas": "^2.6.1", "enzyme": "^3.11.0", - "enzyme-adapter-react-16": "^1.15.2", - "eslint": "^6.8.0", + "eslint": "^7.2", "eslint-config-airbnb": "^18.2.0", - "eslint-config-react-app": "^5.2.1", - "eslint-plugin-flowtype": "^4.7.0", + "eslint-config-react-app": "^6.0.0", + "eslint-plugin-flowtype": "^5.6.0", "eslint-plugin-import": "^2.22.0", "eslint-plugin-jest": "^23.18.0", "eslint-plugin-jsx-a11y": "^6.3.1", @@ -66,8 +66,8 @@ "mirador": "^3.0.0-rc.5", "nwb": "^0.24.7", "prop-types": "^15.7.2", - "react": "^16.14.0", - "react-dom": "^16.14.0", + "react": "^17.0", + "react-dom": "^17.0", "uuid": "^8.2.0" }, "author": "", diff --git a/setupJest.js b/setupJest.js index 7d1129afe68e71199c666cbfa37874c8e7d81121..25d5721d83fa403fc0304a6bed6fb88cc5b1cea3 100644 --- a/setupJest.js +++ b/setupJest.js @@ -1,4 +1,4 @@ import Enzyme from 'enzyme'; // eslint-disable-line import/no-extraneous-dependencies -import Adapter from 'enzyme-adapter-react-16'; // eslint-disable-line import/no-extraneous-dependencies +import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; // eslint-disable-line import/no-extraneous-dependencies Enzyme.configure({ adapter: new Adapter() }); diff --git a/src/AnnotationCreation.js b/src/AnnotationCreation.js index 53f4c7c53dcf9623567f38da5e0ec6c64fbd9540..4b5a275f24206fff8bf32e60bafca0c54d5c0516 100644 --- a/src/AnnotationCreation.js +++ b/src/AnnotationCreation.js @@ -95,21 +95,28 @@ class AnnotationCreation extends Component { // // start/end time } - this.state = { + + const toolState = { activeTool: 'cursor', - annoBody: '', closedMode: 'closed', - colorPopoverOpen: false, currentColorType: false, fillColor: null, + strokeColor: '#00BFFF', + strokeWidth: 3, + ...(props.config.annotation.defaults || {}), + }; + + this.state = { + ...toolState, + annoBody: '', + colorPopoverOpen: false, lineWeightPopoverOpen: false, popoverAnchorEl: null, popoverLineWeightAnchorEl: null, - strokeColor: '#00BFFF', - strokeWidth: 1, svg: null, tend: '', tstart: '', + textEditorStateBustingKey: 0, xywh: null, ...annoState, }; @@ -184,10 +191,10 @@ class AnnotationCreation extends Component { submitForm(e) { e.preventDefault(); const { - annotation, canvases, closeCompanionWindow, receiveAnnotation, config, + annotation, canvases, receiveAnnotation, config, } = this.props; const { - annoBody, tags, xywh, svg, tstart, tend, + annoBody, tags, xywh, svg, tstart, tend, textEditorStateBustingKey, } = this.state; let fsel = xywh; if (tstart && tend) { @@ -214,10 +221,13 @@ class AnnotationCreation extends Component { }); } }); + this.setState({ - activeTool: null, + annoBody: '', + svg: null, + textEditorStateBustingKey: textEditorStateBustingKey + 1, + xywh: null, }); - closeCompanionWindow(); } /** */ @@ -261,7 +271,7 @@ class AnnotationCreation extends Component { const { activeTool, colorPopoverOpen, currentColorType, fillColor, popoverAnchorEl, strokeColor, popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth, closedMode, annoBody, svg, - tstart, tend, + tstart, tend, textEditorStateBustingKey, } = this.state; return ( @@ -280,7 +290,7 @@ class AnnotationCreation extends Component { updateGeometry={this.updateGeometry} windowId={windowId} /> - <form onSubmit={this.submitForm}> + <form onSubmit={this.submitForm} className={classes.section}> <Grid container> <Grid item xs={12}> <Typography variant="overline"> @@ -405,6 +415,7 @@ class AnnotationCreation extends Component { </Grid> <Grid item xs={12}> <TextEditor + key={textEditorStateBustingKey} annoHtml={annoBody} updateAnnotationBody={this.updateBody} /> @@ -423,12 +434,15 @@ class AnnotationCreation extends Component { > <Paper> <ClickAwayListener onClickAway={this.handleCloseLineWeight}> - <MenuList> + <MenuList autoFocus role="listbox"> {[1, 3, 5, 10, 50].map((option, index) => ( <MenuItem key={option} onClick={this.handleLineWeightSelect} value={option} + selected={option == strokeWidth} + role="option" + aria-selected={option == strokeWidth} > {option} </MenuItem> @@ -472,6 +486,12 @@ const styles = (theme) => ({ display: 'flex', flexWrap: 'wrap', }, + section: { + paddingBottom: theme.spacing(1), + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(1), + paddingTop: theme.spacing(2), + }, }); AnnotationCreation.propTypes = { @@ -485,6 +505,11 @@ AnnotationCreation.propTypes = { config: PropTypes.shape({ annotation: PropTypes.shape({ adapter: PropTypes.func, + defaults: PropTypes.objectOf( + PropTypes.oneOfType( + [PropTypes.bool, PropTypes.func, PropTypes.number, PropTypes.string] + ) + ), }), }).isRequired, id: PropTypes.string.isRequired, diff --git a/src/TextEditor.js b/src/TextEditor.js index 536ba33b5bfb1236f44d200ec84e4190a3a8bd74..3dcaee93331711730837351c78e6bc8794bd7f62 100644 --- a/src/TextEditor.js +++ b/src/TextEditor.js @@ -20,6 +20,16 @@ class TextEditor extends Component { this.onChange = this.onChange.bind(this); this.handleKeyCommand = this.handleKeyCommand.bind(this); this.handleFormating = this.handleFormating.bind(this); + this.handleFocus = this.handleFocus.bind(this); + this.editorRef = React.createRef(); + } + + /** + * This is a kinda silly hack (but apparently recommended approach) to + * making sure the whole visible editor area is clickable, not just the first line. + */ + handleFocus() { + if (this.editorRef.current) this.editorRef.current.focus(); } /** */ @@ -58,6 +68,7 @@ class TextEditor extends Component { const { classes } = this.props; const { editorState } = this.state; const currentStyle = editorState.getCurrentInlineStyle(); + return ( <div> <ToggleButtonGroup @@ -77,11 +88,13 @@ class TextEditor extends Component { <ItalicIcon /> </ToggleButton> </ToggleButtonGroup> - <div className={classes.editorRoot}> + + <div className={classes.editorRoot} onClick={this.handleFocus}> <Editor editorState={editorState} handleKeyCommand={this.handleKeyCommand} onChange={this.onChange} + ref={this.editorRef} /> </div> </div>