diff --git a/cypress/e2e/layers.cy.ts b/cypress/e2e/layers.cy.ts index 26813dd1..90b61950 100644 --- a/cypress/e2e/layers.cy.ts +++ b/cypress/e2e/layers.cy.ts @@ -606,7 +606,8 @@ describe("layers", () => { id: "c", type: "background", }); - when.dragAndDrop(get.elementByTestId("layer-list-item:" + firstId), get.elementByTestId("layer-list-item:" + thirdId)); + + when.dragAndDropWithWait("layer-list-item:" + firstId, "layer-list-item:" + thirdId); then(get.styleFromLocalStorage()).shouldDeepNestedInclude({ layers: [ diff --git a/cypress/e2e/maputnik-cypress-helper.ts b/cypress/e2e/maputnik-cypress-helper.ts index ecabbc8d..9edc9ec5 100644 --- a/cypress/e2e/maputnik-cypress-helper.ts +++ b/cypress/e2e/maputnik-cypress-helper.ts @@ -1,4 +1,6 @@ +/// import { CypressHelper } from "@shellygo/cypress-test-utils"; +import 'cypress-real-events/support'; export default class MaputnikCypressHelper { private helper = new CypressHelper({ defaultDataAttribute: "data-wd-key" }); @@ -12,6 +14,13 @@ export default class MaputnikCypressHelper { }; public when = { + dragAndDropWithWait: (element: string, targetElement: string) => { + this.helper.get.elementByTestId(element).realMouseDown({ button: "left", position: "center" }); + this.helper.get.elementByTestId(element).realMouseMove(0, 10, { position: "center" }); + this.helper.get.elementByTestId(targetElement).realMouseMove(0, 0, { position: "center" }) + this.helper.when.wait(1); + this.helper.get.elementByTestId(targetElement).realMouseUp(); + }, ...this.helper.when, }; diff --git a/package-lock.json b/package-lock.json index 1b7d0cd8..0cac119b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,16 +46,15 @@ "ol-mapbox-style": "^13.1.0", "pmtiles": "^4.3.0", "prop-types": "^15.8.1", - "react": "^18.2.0", + "react": "^19.1.1", "react-accessible-accordion": "^5.0.1", "react-aria-menubutton": "^7.0.3", "react-aria-modal": "^5.0.2", "react-collapse": "^5.1.1", "react-color": "^2.19.3", - "react-dom": "^18.2.0", + "react-dom": "^19.1.1", "react-file-reader-input": "^2.0.0", "react-i18next": "^15.7.3", - "react-icon-base": "^2.1.2", "react-icons": "^5.5.0", "reconnecting-websocket": "^4.4.0", "slugify": "^1.6.6", @@ -81,14 +80,13 @@ "@types/lodash.isequal": "^4.5.8", "@types/lodash.throttle": "^4.1.9", "@types/randomcolor": "^0.5.9", - "@types/react": "^18.2.67", + "@types/react": "^19.1.12", "@types/react-aria-menubutton": "^6.2.14", "@types/react-aria-modal": "^5.0.0", "@types/react-collapse": "^5.0.4", "@types/react-color": "^3.0.13", - "@types/react-dom": "^18.2.22", + "@types/react-dom": "^19.1.9", "@types/react-file-reader-input": "^2.0.4", - "@types/react-icon-base": "^2.1.6", "@types/string-hash": "^1.1.3", "@types/uuid": "^10.0.0", "@types/wicg-file-system-access": "^2023.10.6", @@ -2785,56 +2783,6 @@ "cypress": ">=12.17.3" } }, - "node_modules/@shellygo/cypress-test-utils/node_modules/@types/react": { - "version": "19.1.8", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", - "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.0.2" - } - }, - "node_modules/@shellygo/cypress-test-utils/node_modules/@types/react-dom": { - "version": "19.1.9", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", - "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.0.0" - } - }, - "node_modules/@shellygo/cypress-test-utils/node_modules/react": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", - "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@shellygo/cypress-test-utils/node_modules/react-dom": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", - "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "scheduler": "^0.26.0" - }, - "peerDependencies": { - "react": "^19.1.0" - } - }, - "node_modules/@shellygo/cypress-test-utils/node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "dev": true, - "license": "MIT" - }, "node_modules/@simonsmith/cypress-image-snapshot": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/@simonsmith/cypress-image-snapshot/-/cypress-image-snapshot-9.1.0.tgz", @@ -3128,12 +3076,6 @@ "@types/node": "*" } }, - "node_modules/@types/prop-types": { - "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "dev": true - }, "node_modules/@types/randomcolor": { "version": "0.5.9", "resolved": "https://registry.npmjs.org/@types/randomcolor/-/randomcolor-0.5.9.tgz", @@ -3147,13 +3089,12 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.20", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", - "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", + "version": "19.1.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz", + "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==", "dev": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.0.2" } }, @@ -3200,12 +3141,13 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.22", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", - "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", + "version": "19.1.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", + "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", "dev": true, - "dependencies": { - "@types/react": "*" + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" } }, "node_modules/@types/react-file-reader-input": { @@ -3217,15 +3159,6 @@ "@types/react": "*" } }, - "node_modules/@types/react-icon-base": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@types/react-icon-base/-/react-icon-base-2.1.6.tgz", - "integrity": "sha512-ebbN1JjCm6RxBd3HdI1+8VCdiOI4qMjnl9DIHWJFrB/eYLF4mzIgdL34PIqCJBLY3vlwil9v6IHQvzsa8vgMsg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/reactcss": { "version": "1.2.12", "resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.12.tgz", @@ -10716,13 +10649,10 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } @@ -10789,16 +10719,15 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.26.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.1.1" } }, "node_modules/react-file-reader-input": { @@ -10874,15 +10803,6 @@ } } }, - "node_modules/react-icon-base": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/react-icon-base/-/react-icon-base-2.1.2.tgz", - "integrity": "sha512-NRlRo0RPxWRMQT7osj8UCBSSXsGOxhF1pre84ildhuft5S2U382NOs7tg29osWSjbO90L2a3VTCqadA/LnAzHQ==", - "peerDependencies": { - "prop-types": "*", - "react": "*" - } - }, "node_modules/react-icons": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", @@ -11440,13 +11360,10 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" }, "node_modules/semver": { "version": "7.7.1", diff --git a/package.json b/package.json index 4f1362c2..11f5be18 100644 --- a/package.json +++ b/package.json @@ -61,16 +61,15 @@ "ol-mapbox-style": "^13.1.0", "pmtiles": "^4.3.0", "prop-types": "^15.8.1", - "react": "^18.2.0", + "react": "^19.1.1", "react-accessible-accordion": "^5.0.1", "react-aria-menubutton": "^7.0.3", "react-aria-modal": "^5.0.2", "react-collapse": "^5.1.1", "react-color": "^2.19.3", - "react-dom": "^18.2.0", + "react-dom": "^19.1.1", "react-file-reader-input": "^2.0.0", "react-i18next": "^15.7.3", - "react-icon-base": "^2.1.2", "react-icons": "^5.5.0", "reconnecting-websocket": "^4.4.0", "slugify": "^1.6.6", @@ -113,14 +112,13 @@ "@types/lodash.isequal": "^4.5.8", "@types/lodash.throttle": "^4.1.9", "@types/randomcolor": "^0.5.9", - "@types/react": "^18.2.67", + "@types/react": "^19.1.12", "@types/react-aria-menubutton": "^6.2.14", "@types/react-aria-modal": "^5.0.0", "@types/react-collapse": "^5.0.4", "@types/react-color": "^3.0.13", - "@types/react-dom": "^18.2.22", + "@types/react-dom": "^19.1.9", "@types/react-file-reader-input": "^2.0.4", - "@types/react-icon-base": "^2.1.6", "@types/string-hash": "^1.1.3", "@types/uuid": "^10.0.0", "@types/wicg-file-system-access": "^2023.10.6", diff --git a/src/components/App.tsx b/src/components/App.tsx index 992d9b6d..252e4773 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -696,7 +696,7 @@ export default class App extends React.Component { {...mapProps} onChange={this.onMapChange} debugToolbox={this.state.openlayersDebugOptions.debugToolbox} - onLayerSelect={this.onLayerSelect} + onLayerSelect={(layerId) => this.onLayerSelect(+layerId)} /> } else { diff --git a/src/components/AppMessagePanel.tsx b/src/components/AppMessagePanel.tsx index e31a4141..2e7df6b4 100644 --- a/src/components/AppMessagePanel.tsx +++ b/src/components/AppMessagePanel.tsx @@ -7,7 +7,7 @@ type AppMessagePanelInternalProps = { errors?: unknown[] infos?: string[] mapStyle?: StyleSpecification - onLayerSelect?(...args: unknown[]): unknown + onLayerSelect?(index: number): void; currentLayer?: LayerSpecification selectedLayerIndex?: number } & WithTranslation; diff --git a/src/components/Block.tsx b/src/components/Block.tsx index 193812e0..90052e77 100644 --- a/src/components/Block.tsx +++ b/src/components/Block.tsx @@ -88,7 +88,7 @@ export default class Block extends React.Component {
{this.props.action}
-
this._blockEl = el}> +
{this._blockEl = el}}> {this.props.children}
{this.props.fieldSpec && diff --git a/src/components/FieldDocLabel.tsx b/src/components/FieldDocLabel.tsx index e32fc21e..7bd34b58 100644 --- a/src/components/FieldDocLabel.tsx +++ b/src/components/FieldDocLabel.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { JSX } from 'react' import {MdInfoOutline, MdHighlightOff} from 'react-icons/md' type FieldDocLabelProps = { diff --git a/src/components/IconBackground.tsx b/src/components/IconBackground.tsx index c822bba1..e0960034 100644 --- a/src/components/IconBackground.tsx +++ b/src/components/IconBackground.tsx @@ -1,13 +1,10 @@ -import React from 'react' -import IconBase from 'react-icon-base' +import React, { type CSSProperties } from 'react' +import { BsDiamondFill } from 'react-icons/bs'; - -export default class IconBackground extends React.Component { - render() { - return ( - - - - ) - } +const IconBackground: React.FC<{style: CSSProperties | undefined}> = (props) => { + return ( + + ) } + +export default IconBackground; diff --git a/src/components/IconCircle.tsx b/src/components/IconCircle.tsx index cb7af8f5..302a0450 100644 --- a/src/components/IconCircle.tsx +++ b/src/components/IconCircle.tsx @@ -1,13 +1,9 @@ -import React from 'react' -import IconBase from 'react-icon-base' +import React, { type CSSProperties } from 'react' +import {MdOutlineCircle} from 'react-icons/md' - -export default class IconCircle extends React.Component { - render() { - return ( - - - - ) - } +const IconCircle: React.FC<{style: CSSProperties | undefined}> = (props) => { + return ( + + ) } +export default IconCircle; diff --git a/src/components/IconFill.tsx b/src/components/IconFill.tsx index 4aee10d4..b766b95f 100644 --- a/src/components/IconFill.tsx +++ b/src/components/IconFill.tsx @@ -1,13 +1,10 @@ -import React from 'react' -import IconBase from 'react-icon-base' +import React, { type CSSProperties } from 'react' +import { BsDiamond } from 'react-icons/bs'; -export default class IconFill extends React.Component { - render() { - return ( - - - - ) - } +const IconFill: React.FC<{style: CSSProperties | undefined}> = (props) => { + return ( + + ) } +export default IconFill; diff --git a/src/components/IconLayer.tsx b/src/components/IconLayer.tsx index ba0980dc..f8691449 100644 --- a/src/components/IconLayer.tsx +++ b/src/components/IconLayer.tsx @@ -6,27 +6,28 @@ import IconSymbol from './IconSymbol' import IconBackground from './IconBackground' import IconCircle from './IconCircle' import IconMissing from './IconMissing' +import type {CSSProperties} from 'react' type IconLayerProps = { type: string - style?: object + style?: CSSProperties className?: string }; -export default class IconLayer extends React.Component { - render() { - const iconProps = { style: this.props.style } - switch(this.props.type) { - case 'fill-extrusion': return - case 'raster': return - case 'hillshade': return - case 'heatmap': return - case 'fill': return - case 'background': return - case 'line': return - case 'symbol': return - case 'circle': return - default: return - } +const IconLayer: React.FC = (props) => { + const iconProps = { style: props.style } + switch(props.type) { + case 'fill-extrusion': return + case 'raster': return + case 'hillshade': return + case 'heatmap': return + case 'fill': return + case 'background': return + case 'line': return + case 'symbol': return + case 'circle': return + default: return } } + +export default IconLayer; diff --git a/src/components/IconLine.tsx b/src/components/IconLine.tsx index 62d1fd8c..0284b674 100644 --- a/src/components/IconLine.tsx +++ b/src/components/IconLine.tsx @@ -1,13 +1,11 @@ -import React from 'react' -import IconBase from 'react-icon-base' +import React, { type CSSProperties } from 'react' +import { IoAnalyticsOutline } from 'react-icons/io5'; -export default class IconLine extends React.Component { - render() { - return ( - - - - ) - } +const IconLine: React.FC<{style: CSSProperties | undefined}> = (props) => { + return ( + + ) } + +export default IconLine; diff --git a/src/components/IconMissing.tsx b/src/components/IconMissing.tsx index 0ac5f7d7..f119fd7d 100644 --- a/src/components/IconMissing.tsx +++ b/src/components/IconMissing.tsx @@ -1,11 +1,9 @@ -import React from 'react' +import React, { type CSSProperties } from 'react' import {MdPriorityHigh} from 'react-icons/md' - -export default class IconMissing extends React.Component { - render() { - return ( - - ) - } +const IconMissing: React.FC<{style: CSSProperties | undefined}> = (props) => { + return ( + + ) } +export default IconMissing; diff --git a/src/components/IconSymbol.tsx b/src/components/IconSymbol.tsx index 8bc3add6..f2f29120 100644 --- a/src/components/IconSymbol.tsx +++ b/src/components/IconSymbol.tsx @@ -1,15 +1,10 @@ -import React from 'react' -import IconBase from 'react-icon-base' +import React, { type CSSProperties } from 'react' +import { BsFonts } from 'react-icons/bs'; -export default class IconSymbol extends React.Component { - render() { - return ( - - - - - - ) - } +const IconSymbol: React.FC<{style: CSSProperties | undefined}> = (props) => { + return ( + + ) } +export default IconSymbol; diff --git a/src/components/InputColor.tsx b/src/components/InputColor.tsx index d40284d5..c3e3ab27 100644 --- a/src/components/InputColor.tsx +++ b/src/components/InputColor.tsx @@ -122,7 +122,7 @@ export default class InputColor extends React.Component { spellCheck="false" autoComplete="off" className="maputnik-color" - ref={(input) => this.colorInput = input} + ref={(input) => {this.colorInput = input}} onClick={this.togglePicker} style={this.props.style} name={this.props.name} diff --git a/src/components/InputJson.tsx b/src/components/InputJson.tsx index 08174cd4..55e9e1e6 100644 --- a/src/components/InputJson.tsx +++ b/src/components/InputJson.tsx @@ -173,7 +173,7 @@ class InputJsonInternal extends React.Component
this._el = el} + ref={(el) => {this._el = el}} style={style} />
diff --git a/src/components/InputUrl.tsx b/src/components/InputUrl.tsx index 7353e2e3..af7456ab 100644 --- a/src/components/InputUrl.tsx +++ b/src/components/InputUrl.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { JSX } from 'react' import InputString from './InputString' import SmallError from './SmallError' import { Trans, WithTranslation, withTranslation } from 'react-i18next'; diff --git a/src/components/LayerList.tsx b/src/components/LayerList.tsx index dc382526..edc13d80 100644 --- a/src/components/LayerList.tsx +++ b/src/components/LayerList.tsx @@ -28,7 +28,7 @@ type LayerListContainerProps = { layers: LayerSpecification[] selectedLayerIndex: number onLayersChange(layers: LayerSpecification[]): unknown - onLayerSelect(...args: unknown[]): unknown + onLayerSelect(index: number): void; onLayerDestroy?(...args: unknown[]): unknown onLayerCopy(...args: unknown[]): unknown onLayerVisibilityToggle(...args: unknown[]): unknown @@ -50,7 +50,7 @@ class LayerListContainerInternal extends React.Component {}, } selectedItemRef: React.RefObject; - scrollContainerRef: React.RefObject; + scrollContainerRef: React.RefObject; constructor(props: LayerListContainerInternalProps) { super(props); @@ -276,6 +276,7 @@ class LayerListContainerInternal extends React.Component = (props) => {
} diff --git a/src/components/MapOpenLayers.tsx b/src/components/MapOpenLayers.tsx index ddf723df..ad8eb2a1 100644 --- a/src/components/MapOpenLayers.tsx +++ b/src/components/MapOpenLayers.tsx @@ -29,7 +29,7 @@ type MapOpenLayersInternalProps = { mapStyle: object accessToken?: string style?: object - onLayerSelect(...args: unknown[]): unknown + onLayerSelect(layerId: string): void debugToolbox: boolean replaceAccessTokens(...args: unknown[]): unknown onChange(...args: unknown[]): unknown @@ -156,7 +156,7 @@ class MapOpenLayersInternal extends React.Component
this.popupContainer = x} + ref={x => {this.popupContainer = x}} style={{background: "black"}} className="maputnik-popup" > @@ -193,7 +193,7 @@ class MapOpenLayersInternal extends React.Component this.container = x} + ref={x => {this.container = x}} role="region" aria-label={t("Map view")} style={{