diff --git a/fronts-client/README.md b/fronts-client/README.md index 6b11bde3b04..793ebb66fa8 100644 --- a/fronts-client/README.md +++ b/fronts-client/README.md @@ -181,15 +181,3 @@ At the moment, we normalise on the client. This introduces a degree of complexit In normalising on the server, we have an additional advantage -- if the persistence model changes, for example if in the future we move to an RDS to store collection data, we can swap out the models without disturbing the client, avoiding concerns with overlapping versions etc. -### Use a third party library for Drag and Drop - -We currently have a custom-made npm module - [Guration](https://www.npmjs.com/package/@guardian/guration) - implementing Drag and Drop specially for the Fronts Tool. - -This module was written by the team in 2018 and is not maintained by anyone else. It covers the complex area of drag and drop, working with the tricky HTML spec. - -If this module breaks the Fronts tool is basically non-functional and it will take work to figure out what is going on inside Guration. - -The problem it was written to solve (lists within lists - ie sublinks) is now solved by other npm modules that have a big user-base and are properly maintained. (eg. [React Beautiful DnD](https://www.npmjs.com/package/react-beautiful-dnd).) - -By switching to a more popular module with good documentation, it will be easier for new developers to pick up. We already use React Beautiful DnD for small interactions on the menu so it won’t add extra weight. - diff --git a/fronts-client/babel.config.js b/fronts-client/babel.config.js index 0c556b69229..14d1b60b5bb 100644 --- a/fronts-client/babel.config.js +++ b/fronts-client/babel.config.js @@ -4,15 +4,16 @@ module.exports = { '@babel/env', { useBuiltIns: 'usage', + corejs: '2.x', targets: { - browsers: ['chrome >= 49', 'firefox >= 48', 'safari >= 10'] - } - } + browsers: ['chrome >= 49', 'firefox >= 48', 'safari >= 10'], + }, + }, ], - '@babel/react' + '@babel/react', ], plugins: [ '@babel/plugin-proposal-object-rest-spread', - 'transform-class-properties' - ] + 'transform-class-properties', + ], }; diff --git a/fronts-client/jest.config.js b/fronts-client/jest.config.js index 703f799d36c..198d3097700 100644 --- a/fronts-client/jest.config.js +++ b/fronts-client/jest.config.js @@ -1,11 +1,11 @@ module.exports = { moduleFileExtensions: ['ts', 'tsx', 'js'], transform: { - '^.+\\.(ts|tsx|js)$': 'ts-jest' + '^.+\\.(ts|tsx|js)$': 'ts-jest', }, testMatch: ['/src/**/*.spec.+(ts|tsx|js)'], transformIgnorePatterns: [ - '/node_modules/(?!(panda-session|grid-util-js)/)' + '/node_modules/(?!(panda-session|grid-util-js)/)', ], setupTestFrameworkScriptFile: './node_modules/jest-enzyme/lib/index.js', setupFiles: ['./config/setupTest.js'], @@ -13,6 +13,6 @@ module.exports = { moduleNameMapper: { '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/mocks/fileMock.js', - '\\.css$': '/mocks/styleMock.js' - } + '\\.css$': '/mocks/styleMock.js', + }, }; diff --git a/fronts-client/package.json b/fronts-client/package.json index 9a0514e295d..0c9a68c0d34 100644 --- a/fronts-client/package.json +++ b/fronts-client/package.json @@ -19,13 +19,13 @@ "run-checks": "yarn test && yarn lint && yarn test-integration" }, "devDependencies": { - "@babel/cli": "^7.0.0-beta.44", - "@babel/core": "^7.0.0-beta.44", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.44", - "@babel/polyfill": "^7.0.0-beta.44", - "@babel/preset-env": "^7.0.0-beta.44", - "@babel/preset-react": "^7.0.0-beta.44", - "@babel/register": "^7.0.0-beta.44", + "@babel/cli": "^7.23.0", + "@babel/core": "^7.23.2", + "@babel/plugin-proposal-object-rest-spread": "^7.20.7", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.23.2", + "@babel/preset-react": "^7.22.15", + "@babel/register": "^7.22.15", "@types/enzyme": "^3.1.14", "@types/enzyme-adapter-react-16": "^1.0.3", "@types/fetch-mock": "^6.0.4", @@ -43,20 +43,18 @@ "@types/styled-components": "^4.1.18", "@types/webpack-env": "^1.13.6", "babel-core": "^7.0.0-0", - "babel-jest": "^22.4.3", - "babel-loader": "^8.0.0-beta", "babel-plugin-styled-components": "^1.10.0", "babel-plugin-transform-class-properties": "^6.24.1", "circular-dependency-plugin": "^5.2.0", - "css-loader": "^2.0.1", + "css-loader": "^3.6.0", "eslint": "^5.12.0", "eslint-plugin-prettier": "^3.0.1", - "express": "^4.16.4", + "express": "^4.18.2", "fast-check": "^1.20.1", "fetch-mock": "^6.4.2", - "file-loader": "^1.1.11", + "file-loader": "^6.2.0", "fork-ts-checker-webpack-plugin": "^0.5.2", - "jest": "^23.6.0", + "jest": "^26.6.3", "jest-dom": "^2.1.0", "markdown-toc": "^1.2.0", "prettier": "^2.0.2", @@ -66,8 +64,8 @@ "redux-mock-store": "^1.5.3", "style-loader": "^0.23.1", "testcafe": "^1.1.4", - "ts-jest": "^23.10.4", - "ts-loader": "^6.1.0", + "ts-jest": "^26.5.6", + "ts-loader": "^8.4.0", "tsconfig-paths-webpack-plugin": "^3.2.0", "tslint": "^5.11.0", "tslint-config-prettier": "^1.15.0", @@ -82,29 +80,19 @@ "whatwg-fetch": "^3.0.0" }, "dependencies": { - "@guardian/guration": "^3.0.1", + "@babel/runtime": "^7.0.0", "@types/lodash": "^4.14.117", "@types/lodash.throttle": "^4.1.4", "@types/mousetrap": "^1.6.1", - "@types/prosemirror-commands": "^1.0.1", - "@types/prosemirror-history": "^1.0.1", - "@types/prosemirror-inputrules": "^1.0.2", - "@types/prosemirror-keymap": "^1.0.1", - "@types/prosemirror-menu": "^1.0.1", - "@types/prosemirror-model": "^1.7.2", - "@types/prosemirror-schema-basic": "^1.0.1", - "@types/prosemirror-schema-list": "^1.0.1", - "@types/prosemirror-state": "^1.2.3", - "@types/prosemirror-view": "^1.11.2", "@types/react-beautiful-dnd": "^11.0.3", - "@types/react-dates": "^17.1.5", + "@types/react-dates": "^21.8.0", "@types/react-test-renderer": "^16.0.3", - "@types/recharts": "^1.1.20", + "@types/recharts": "^1.8.26", "@types/redux-thunk": "^2.1.0", "@types/shallowequal": "^1.1.1", "@types/uuid": "^3.4.4", "babel-polyfill": "^6.26.0", - "body-parser": "^1.18.3", + "body-parser": "^1.20.2", "date-fns": "^1.29.0", "downshift": "^3.1.7", "enzyme": "^3.7.0", @@ -113,36 +101,38 @@ "grid-util-js": "^1.1.0", "history": "^4.7.2", "jest-enzyme": "^6.0.0", - "lodash": "^4.17.13", + "lodash": "^4.17.21", "lodash.throttle": "^4.1.1", - "moment": "^2.23.0", + "moment": "^2.29.4", "mousetrap": "^1.6.2", "normalise-with-fields": "1.2.0", "panda-session": "^0.1.6", "prop-types": "^15.6.1", - "prosemirror-commands": "^1.1.0", - "prosemirror-inputrules": "^1.1.0", - "prosemirror-keymap": "^1.1.0", - "prosemirror-menu": "^1.0.5", - "prosemirror-model": "^1.7.4", - "prosemirror-schema-basic": "^1.0.1", - "prosemirror-schema-list": "^1.0.4", - "prosemirror-state": "^1.2.4", - "prosemirror-view": "^1.11.7", + "prosemirror-commands": "^1.5.2", + "prosemirror-inputrules": "^1.2.0", + "prosemirror-keymap": "^1.2.2", + "prosemirror-menu": "^1.2.4", + "prosemirror-model": "^1.19.3", + "prosemirror-schema-basic": "^1.2.2", + "prosemirror-schema-list": "^1.3.0", + "prosemirror-state": "^1.4.3", + "prosemirror-view": "^1.32.1", "raven": "^2.5.0", "raven-js": "^3.24.1", "react": "^16.13.0", "react-beautiful-dnd": "^11.0.5", - "react-dates": "^18.3.1", + "react-dates": "^21.8.0", "react-dom": "^16.13.0", "react-icons": "^3.4.0", + "react-is": "16.8.0", "react-modal": "^3.6.1", "react-redux": "^5.0.7", "react-router": "^4.2.0", "react-router-dom": "^4.2.2", "react-router-redux": "^4.0.8", "react-transition-group": "^2.6.0", - "recharts": "^1.6.2", + "react-with-direction": "1.3.0", + "recharts": "^2.9.0", "redux": "^4.0.1", "redux-batched-actions": "^0.4.1", "redux-form": "^8.2.4", diff --git a/fronts-client/src/components/Clipboard.tsx b/fronts-client/src/components/Clipboard.tsx index fc4383074ea..47b21242ecc 100644 --- a/fronts-client/src/components/Clipboard.tsx +++ b/fronts-client/src/components/Clipboard.tsx @@ -181,7 +181,9 @@ class Clipboard extends React.Component { <> this.handleArticleFocus(e, card)} + onFocus={(e: React.FocusEvent) => + this.handleArticleFocus(e, card) + } area="clipboard" onBlur={this.handleBlur} uuid={card.uuid} diff --git a/fronts-client/src/components/CollectionDisplay.tsx b/fronts-client/src/components/CollectionDisplay.tsx index 69ab4e03f10..d9d5b16ed65 100644 --- a/fronts-client/src/components/CollectionDisplay.tsx +++ b/fronts-client/src/components/CollectionDisplay.tsx @@ -270,10 +270,10 @@ class CollectionDisplay extends React.Component { data-testid="rename-front-input" value={displayName} autoFocus - onChange={(e) => { + onChange={(e: React.ChangeEvent) => { this.setState({ displayName: e.target.value }); }} - onKeyDown={(e) => { + onKeyDown={(e: React.KeyboardEvent) => { if (e.key === 'Enter') { this.setName(); } diff --git a/fronts-client/src/components/CollectionNotification.tsx b/fronts-client/src/components/CollectionNotification.tsx index c1a141c0975..2ad60ea0de4 100644 --- a/fronts-client/src/components/CollectionNotification.tsx +++ b/fronts-client/src/components/CollectionNotification.tsx @@ -71,7 +71,7 @@ class CollectionNotification extends React.Component<   { + onClick={(e: React.MouseEvent) => { e.stopPropagation(); return this.setState({ showFrontDetails: !this.state.showFrontDetails, diff --git a/fronts-client/src/components/FocusWrapper.tsx b/fronts-client/src/components/FocusWrapper.tsx index 1bfd0b38fd4..538109da3e6 100644 --- a/fronts-client/src/components/FocusWrapper.tsx +++ b/fronts-client/src/components/FocusWrapper.tsx @@ -20,4 +20,6 @@ const mapStateToProps = ( isSelected: selectFocusedArticle(state, `${area}Article`) === uuid, }); -export default connect(mapStateToProps)(Wrapper); +const FocusWrapper = connect(mapStateToProps)(Wrapper); + +export default FocusWrapper; diff --git a/fronts-client/src/components/FrontsCAPIInterface/FeedItem.tsx b/fronts-client/src/components/FrontsCAPIInterface/FeedItem.tsx index 727de945d5e..9ec2dfc8a03 100644 --- a/fronts-client/src/components/FrontsCAPIInterface/FeedItem.tsx +++ b/fronts-client/src/components/FrontsCAPIInterface/FeedItem.tsx @@ -161,7 +161,7 @@ class FeedItem extends React.Component { e.preventDefault()} + onClick={(e: React.MouseEvent) => e.preventDefault()} aria-disabled blur={shouldObscureFeed} > diff --git a/fronts-client/src/components/FrontsEdit/CardFormInline.tsx b/fronts-client/src/components/FrontsEdit/CardFormInline.tsx index e055b862af2..7a401e48148 100644 --- a/fronts-client/src/components/FrontsEdit/CardFormInline.tsx +++ b/fronts-client/src/components/FrontsEdit/CardFormInline.tsx @@ -357,7 +357,7 @@ const RenderSlideshow = ({ type="text" value={fields.get(slideshowIndex).caption ?? ''} invalid={isInvalidCaptionLength(slideshowIndex)} - onChange={(event) => + onChange={(event: React.ChangeEvent) => change(`slideshow[${slideshowIndex}].caption`, event.target.value) } /> diff --git a/fronts-client/src/components/FrontsEdit/Collection.tsx b/fronts-client/src/components/FrontsEdit/Collection.tsx index d1033f9bb26..922dfee3e33 100644 --- a/fronts-client/src/components/FrontsEdit/Collection.tsx +++ b/fronts-client/src/components/FrontsEdit/Collection.tsx @@ -160,7 +160,7 @@ class CollectionContext extends React.Component< tabIndex={0} area="collection" onBlur={() => handleBlur()} - onFocus={(e) => + onFocus={(e: React.FocusEvent) => handleArticleFocus(e, group.uuid, card, frontId) } uuid={card.uuid} diff --git a/fronts-client/src/components/FrontsEdit/CollectionComponents/DragToAddSnap.tsx b/fronts-client/src/components/FrontsEdit/CollectionComponents/DragToAddSnap.tsx index ed4710d0990..e3a6762af99 100644 --- a/fronts-client/src/components/FrontsEdit/CollectionComponents/DragToAddSnap.tsx +++ b/fronts-client/src/components/FrontsEdit/CollectionComponents/DragToAddSnap.tsx @@ -61,7 +61,9 @@ const DragToAddTextSnap = () => { handleDragStart(e, ref.current)} + onDragStart={(e: React.DragEvent) => + handleDragStart(e, ref.current) + } draggable={true} > Drag to add a text card diff --git a/fronts-client/src/components/FrontsEdit/CollectionOverview.tsx b/fronts-client/src/components/FrontsEdit/CollectionOverview.tsx index 2e390d31c6c..c5d03a044c4 100644 --- a/fronts-client/src/components/FrontsEdit/CollectionOverview.tsx +++ b/fronts-client/src/components/FrontsEdit/CollectionOverview.tsx @@ -111,7 +111,7 @@ const CollectionOverview = ({ }: FrontCollectionOverviewProps) => collection ? ( { + onClick={(e: React.MouseEvent) => { e.preventDefault(); events.overviewItemClicked(frontId); const el = document.getElementById( diff --git a/fronts-client/src/components/FrontsEdit/FrontContent.tsx b/fronts-client/src/components/FrontsEdit/FrontContent.tsx index 651f979e45d..a976d28f876 100644 --- a/fronts-client/src/components/FrontsEdit/FrontContent.tsx +++ b/fronts-client/src/components/FrontsEdit/FrontContent.tsx @@ -198,7 +198,9 @@ class FrontContent extends React.Component { return ( (this.collectionContainerElement = ref)} + ref={(ref: HTMLDivElement | null) => + (this.collectionContainerElement = ref) + } > {({ width }) => ( @@ -206,7 +208,9 @@ class FrontContent extends React.Component { {front.collections.map((collectionId) => ( (this.collectionElements[collectionId] = ref)} + ref={(ref: HTMLDivElement | null) => + (this.collectionElements[collectionId] = ref) + } > {isEditingLocked && ( diff --git a/fronts-client/src/components/FrontsEdit/FrontSection.tsx b/fronts-client/src/components/FrontsEdit/FrontSection.tsx index d1a4cd2933d..5c156d0c440 100644 --- a/fronts-client/src/components/FrontsEdit/FrontSection.tsx +++ b/fronts-client/src/components/FrontsEdit/FrontSection.tsx @@ -188,10 +188,10 @@ class FrontSection extends React.Component< data-testid="rename-front-input" value={frontNameValue} autoFocus - onChange={(e) => + onChange={(e: React.ChangeEvent) => this.setState({ frontNameValue: e.target.value }) } - onKeyDown={(e) => { + onKeyDown={(e: React.KeyboardEvent) => { if (e.key === 'Enter') { this.setName(); } diff --git a/fronts-client/src/components/article/Article.tsx b/fronts-client/src/components/article/Article.tsx index 748a0821386..1416d7a22ba 100644 --- a/fronts-client/src/components/article/Article.tsx +++ b/fronts-client/src/components/article/Article.tsx @@ -119,7 +119,7 @@ class ArticleComponent extends React.Component { onDragStart={onDragStart} onDragOver={onDragOver} onDrop={onDrop} - onClick={(e) => { + onClick={(e: React.MouseEvent) => { if (isLoading || !article) { return; } diff --git a/fronts-client/src/components/card/CardMetaContainer.tsx b/fronts-client/src/components/card/CardMetaContainer.tsx index 082d0a1d5b7..5e4d2550382 100644 --- a/fronts-client/src/components/card/CardMetaContainer.tsx +++ b/fronts-client/src/components/card/CardMetaContainer.tsx @@ -11,13 +11,17 @@ const metaContainerSizeWidthMap = { small: 60, } as { [Sizes in CardSizes]: number }; -const MetaContainer = styled.div<{ size?: CardSizes }>` +interface MetaContainerProps { + size?: CardSizes; +} +const MetaContainer = styled.div` position: relative; flex-shrink: 0; /* If we have a size property, use that. */ - width: ${({ size }) => size && `${metaContainerSizeWidthMap[size]}px`}; + width: ${({ size }: MetaContainerProps) => + size && `${metaContainerSizeWidthMap[size]}px`}; /* If we don't, fall back to media queries. */ - ${({ size }) => + ${({ size }: MetaContainerProps) => !size && media.large` width: ${metaContainerSizeWidthMap.small}px; diff --git a/fronts-client/src/components/inputs/Dropdown.tsx b/fronts-client/src/components/inputs/Dropdown.tsx index 871e6a77e6c..d9615c4564a 100644 --- a/fronts-client/src/components/inputs/Dropdown.tsx +++ b/fronts-client/src/components/inputs/Dropdown.tsx @@ -30,7 +30,9 @@ const Dropdown = ({ }: DropdownProps) => (