refactor: [UEPR-55] updated react-intl from v2 to v6

This commit is contained in:
MiroslavDionisiev 2024-09-20 15:39:22 +03:00
parent 5f12985de8
commit fed5087e9d
13 changed files with 476 additions and 343 deletions
package-lock.jsonpackage.json
src
components
color-picker
coming-soon
fixed-tools
mode-tools
paint-editor
tool-select-base
containers
lib
playground/reducers
test/__mocks__
webpack.config.js

206
package-lock.json generated
View file

@ -54,7 +54,7 @@
"raf": "3.4.1", "raf": "3.4.1",
"react": "16.14.0", "react": "16.14.0",
"react-dom": "16.14.0", "react-dom": "16.14.0",
"react-intl": "2.9.0", "react-intl": "^6.6.8",
"react-intl-redux": "2.4.1", "react-intl-redux": "2.4.1",
"react-popover": "0.5.10", "react-popover": "0.5.10",
"react-redux": "5.1.2", "react-redux": "5.1.2",
@ -83,7 +83,7 @@
"peerDependencies": { "peerDependencies": {
"react": "^16", "react": "^16",
"react-dom": "^16", "react-dom": "^16",
"react-intl": "^2", "react-intl": "^6",
"react-intl-redux": "^0.7 || ^2.0.0", "react-intl-redux": "^0.7 || ^2.0.0",
"react-popover": "^0.5", "react-popover": "^0.5",
"react-redux": "^5", "react-redux": "^5",
@ -2829,6 +2829,100 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@formatjs/ecma402-abstract": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz",
"integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==",
"dev": true,
"dependencies": {
"@formatjs/intl-localematcher": "0.5.4",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/fast-memoize": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz",
"integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==",
"dev": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/icu-messageformat-parser": {
"version": "2.7.8",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz",
"integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==",
"dev": true,
"dependencies": {
"@formatjs/ecma402-abstract": "2.0.0",
"@formatjs/icu-skeleton-parser": "1.8.2",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/icu-skeleton-parser": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz",
"integrity": "sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==",
"dev": true,
"dependencies": {
"@formatjs/ecma402-abstract": "2.0.0",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/intl": {
"version": "2.10.4",
"resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.10.4.tgz",
"integrity": "sha512-56483O+HVcL0c7VucAS2tyH020mt9XTozZO67cwtGg0a7KWDukS/FzW3OnvaHmTHDuYsoPIzO+ZHVfU6fT/bJw==",
"dev": true,
"dependencies": {
"@formatjs/ecma402-abstract": "2.0.0",
"@formatjs/fast-memoize": "2.2.0",
"@formatjs/icu-messageformat-parser": "2.7.8",
"@formatjs/intl-displaynames": "6.6.8",
"@formatjs/intl-listformat": "7.5.7",
"intl-messageformat": "10.5.14",
"tslib": "^2.4.0"
},
"peerDependencies": {
"typescript": "^4.7 || 5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@formatjs/intl-displaynames": {
"version": "6.6.8",
"resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.6.8.tgz",
"integrity": "sha512-Lgx6n5KxN16B3Pb05z3NLEBQkGoXnGjkTBNCZI+Cn17YjHJ3fhCeEJJUqRlIZmJdmaXQhjcQVDp6WIiNeRYT5g==",
"dev": true,
"dependencies": {
"@formatjs/ecma402-abstract": "2.0.0",
"@formatjs/intl-localematcher": "0.5.4",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/intl-listformat": {
"version": "7.5.7",
"resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.5.7.tgz",
"integrity": "sha512-MG2TSChQJQT9f7Rlv+eXwUFiG24mKSzmF144PLb8m8OixyXqn4+YWU+5wZracZGCgVTVmx8viCf7IH3QXoiB2g==",
"dev": true,
"dependencies": {
"@formatjs/ecma402-abstract": "2.0.0",
"@formatjs/intl-localematcher": "0.5.4",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/intl-localematcher": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
"integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==",
"dev": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.14", "version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@ -5482,6 +5576,16 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz",
"integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==",
"dev": true,
"dependencies": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/istanbul-lib-coverage": { "node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@ -5565,6 +5669,22 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/prop-types": {
"version": "15.7.12",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
"dev": true
},
"node_modules/@types/react": {
"version": "18.3.6",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.6.tgz",
"integrity": "sha512-CnGaRYNu2iZlkGXGrOYtdg5mLK8neySj0woZ4e2wF/eli2E6Sazmq5X+Nrj6OBrrFVQfJWTUFeqAzoRhWQXYvg==",
"dev": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/stack-utils": { "node_modules/@types/stack-utils": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
@ -9183,6 +9303,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"dev": true
},
"node_modules/cyclist": { "node_modules/cyclist": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz",
@ -14965,21 +15091,16 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/intl-format-cache": {
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/intl-format-cache/-/intl-format-cache-2.2.9.tgz",
"integrity": "sha512-Zv/u8wRpekckv0cLkwpVdABYST4hZNTDaX7reFetrYTJwxExR2VyTqQm+l0WmL0Qo8Mjb9Tf33qnfj0T7pjxdQ==",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/intl-messageformat": { "node_modules/intl-messageformat": {
"version": "2.2.0", "version": "10.5.14",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-2.2.0.tgz", "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz",
"integrity": "sha512-I+tSvHnXqJYjDfNmY95tpFMj30yoakC6OXAo+wu/wTMy6tA/4Fd4mvV7Uzs4cqK/Ap29sHhwjcY+78a8eifcXw==", "integrity": "sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==",
"dev": true, "dev": true,
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"intl-messageformat-parser": "1.4.0" "@formatjs/ecma402-abstract": "2.0.0",
"@formatjs/fast-memoize": "2.2.0",
"@formatjs/icu-messageformat-parser": "2.7.8",
"tslib": "^2.4.0"
} }
}, },
"node_modules/intl-messageformat-parser": { "node_modules/intl-messageformat-parser": {
@ -14990,25 +15111,6 @@
"dev": true, "dev": true,
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/intl-messageformat/node_modules/intl-messageformat-parser": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz",
"integrity": "sha512-/XkqFHKezO6UcF4Av2/Lzfrez18R0jyw7kRFhSeB/YRakdrgSc9QfFZUwNJI9swMwMoNPygK1ArC5wdFSjPw+A==",
"deprecated": "We've written a new parser that's 6x faster and is backwards compatible. Please use @formatjs/icu-messageformat-parser",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/intl-relativeformat": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/intl-relativeformat/-/intl-relativeformat-2.2.0.tgz",
"integrity": "sha512-4bV/7kSKaPEmu6ArxXf9xjv1ny74Zkwuey8Pm01NH4zggPP7JHwg2STk8Y3JdspCKRDriwIyLRfEXnj2ZLr4Bw==",
"deprecated": "This package has been deprecated, please see migration guide at 'https://github.com/formatjs/formatjs/tree/master/packages/intl-relativeformat#migration-guide'",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"intl-messageformat": "^2.0.0"
}
},
"node_modules/into-stream": { "node_modules/into-stream": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz",
@ -26408,21 +26510,30 @@
} }
}, },
"node_modules/react-intl": { "node_modules/react-intl": {
"version": "2.9.0", "version": "6.6.8",
"resolved": "https://registry.npmjs.org/react-intl/-/react-intl-2.9.0.tgz", "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.8.tgz",
"integrity": "sha512-27jnDlb/d2A7mSJwrbOBnUgD+rPep+abmoJE511Tf8BnoONIAUehy/U1zZCHGO17mnOwMWxqN4qC0nW11cD6rA==", "integrity": "sha512-M0pkhzcgV31h++2901BiRXWl69hp2zPyLxRrSwRjd1ErXbNoubz/f4M6DrRTd4OiSUrT4ajRQzrmtS5plG4FtA==",
"dev": true, "dev": true,
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"hoist-non-react-statics": "^3.3.0", "@formatjs/ecma402-abstract": "2.0.0",
"intl-format-cache": "^2.0.5", "@formatjs/icu-messageformat-parser": "2.7.8",
"intl-messageformat": "^2.1.0", "@formatjs/intl": "2.10.4",
"intl-relativeformat": "^2.1.0", "@formatjs/intl-displaynames": "6.6.8",
"invariant": "^2.1.1" "@formatjs/intl-listformat": "7.5.7",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/react": "16 || 17 || 18",
"hoist-non-react-statics": "^3.3.2",
"intl-messageformat": "10.5.14",
"tslib": "^2.4.0"
}, },
"peerDependencies": { "peerDependencies": {
"prop-types": "^15.5.4", "react": "^16.6.0 || 17 || 18",
"react": "^0.14.9 || ^15.0.0 || ^16.0.0" "typescript": "^4.7 || 5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
} }
}, },
"node_modules/react-intl-redux": { "node_modules/react-intl-redux": {
@ -26430,7 +26541,6 @@
"resolved": "https://registry.npmjs.org/react-intl-redux/-/react-intl-redux-2.4.1.tgz", "resolved": "https://registry.npmjs.org/react-intl-redux/-/react-intl-redux-2.4.1.tgz",
"integrity": "sha512-EYTNmHJTnTam4phQj1nTdJvcdVjz+F56nLl6JtpqWsKzG5ZnQh/hoqLLJUjP0dgeNKSESIcjhYsTyBWDUwjo0A==", "integrity": "sha512-EYTNmHJTnTam4phQj1nTdJvcdVjz+F56nLl6JtpqWsKzG5ZnQh/hoqLLJUjP0dgeNKSESIcjhYsTyBWDUwjo0A==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.17.9", "@babel/runtime": "^7.17.9",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
@ -31912,6 +32022,12 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/tslib": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"dev": true
},
"node_modules/tty-browserify": { "node_modules/tty-browserify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",

View file

@ -35,7 +35,7 @@
"peerDependencies": { "peerDependencies": {
"react": "^16", "react": "^16",
"react-dom": "^16", "react-dom": "^16",
"react-intl": "^2", "react-intl": "^6",
"react-intl-redux": "^0.7 || ^2.0.0", "react-intl-redux": "^0.7 || ^2.0.0",
"react-popover": "^0.5", "react-popover": "^0.5",
"react-redux": "^5", "react-redux": "^5",
@ -81,7 +81,7 @@
"raf": "3.4.1", "raf": "3.4.1",
"react": "16.14.0", "react": "16.14.0",
"react-dom": "16.14.0", "react-dom": "16.14.0",
"react-intl": "2.9.0", "react-intl": "^6.6.8",
"react-intl-redux": "2.4.1", "react-intl-redux": "2.4.1",
"react-popover": "0.5.10", "react-popover": "0.5.10",
"react-redux": "5.1.2", "react-redux": "5.1.2",
@ -121,7 +121,10 @@
"moduleNameMapper": { "moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test/__mocks__/fileMock.js", "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js" "\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js"
} },
"transformIgnorePatterns": [
"/node_modules/(?!intl-messageformat|intl-messageformat-parser).+\\.js$"
]
}, },
"jest-junit": { "jest-junit": {
"outputDirectory": "./test/results" "outputDirectory": "./test/results"

View file

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl'; import {defineMessages, FormattedMessage, injectIntl} from 'react-intl';
import intlShape from '../../lib/intl-shape.js';
import classNames from 'classnames'; import classNames from 'classnames';
import parseColor from 'parse-color'; import parseColor from 'parse-color';

View file

@ -4,7 +4,8 @@ See #13 */
import bindAll from 'lodash.bindall'; import bindAll from 'lodash.bindall';
import classNames from 'classnames'; import classNames from 'classnames';
import {defineMessages, injectIntl, intlShape, FormattedMessage} from 'react-intl'; import {defineMessages, injectIntl, FormattedMessage} from 'react-intl';
import intlShape from '../../lib/intl-shape.js';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import ReactTooltip from 'react-tooltip'; import ReactTooltip from 'react-tooltip';

View file

@ -11,7 +11,7 @@ import BufferedInputHOC from '../forms/buffered-input-hoc.jsx';
import Button from '../button/button.jsx'; import Button from '../button/button.jsx';
import ButtonGroup from '../button-group/button-group.jsx'; import ButtonGroup from '../button-group/button-group.jsx';
import Dropdown from '../dropdown/dropdown.jsx'; import Dropdown from '../dropdown/dropdown.jsx';
import {defineMessages, injectIntl, intlShape} from 'react-intl'; import {defineMessages, useIntl} from 'react-intl';
import Formats, {isVector} from '../../lib/format'; import Formats, {isVector} from '../../lib/format';
import Input from '../forms/input.jsx'; import Input from '../forms/input.jsx';
import InputGroup from '../input-group/input-group.jsx'; import InputGroup from '../input-group/input-group.jsx';
@ -87,13 +87,14 @@ const messages = defineMessages({
const FixedToolsComponent = props => { const FixedToolsComponent = props => {
const redoDisabled = !props.canRedo(); const redoDisabled = !props.canRedo();
const undoDisabled = !props.canUndo(); const undoDisabled = !props.canUndo();
const intl = useIntl();
return ( return (
<div className={styles.row}> <div className={styles.row}>
{/* Name field */} {/* Name field */}
<InputGroup> <InputGroup>
<MediaQuery minWidth={layout.fullSizeEditorMinWidth}> <MediaQuery minWidth={layout.fullSizeEditorMinWidth}>
<Label text={props.intl.formatMessage(messages.costume)}> <Label text={intl.formatMessage(messages.costume)}>
<BufferedInput <BufferedInput
className={styles.costumeInput} className={styles.costumeInput}
type="text" type="text"
@ -128,7 +129,7 @@ const FixedToolsComponent = props => {
onClick={props.onUndo} onClick={props.onUndo}
> >
<img <img
alt={props.intl.formatMessage(messages.undo)} alt={intl.formatMessage(messages.undo)}
className={classNames( className={classNames(
styles.buttonGroupButtonIcon, styles.buttonGroupButtonIcon,
styles.undoIcon styles.undoIcon
@ -150,7 +151,7 @@ const FixedToolsComponent = props => {
onClick={props.onRedo} onClick={props.onRedo}
> >
<img <img
alt={props.intl.formatMessage(messages.redo)} alt={intl.formatMessage(messages.redo)}
className={styles.buttonGroupButtonIcon} className={styles.buttonGroupButtonIcon}
draggable={false} draggable={false}
src={redoIcon} src={redoIcon}
@ -164,16 +165,16 @@ const FixedToolsComponent = props => {
<InputGroup className={styles.modDashedBorder}> <InputGroup className={styles.modDashedBorder}>
<LabeledIconButton <LabeledIconButton
disabled={!shouldShowGroup()} disabled={!shouldShowGroup()}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={groupIcon} imgSrc={groupIcon}
title={props.intl.formatMessage(messages.group)} title={intl.formatMessage(messages.group)}
onClick={props.onGroup} onClick={props.onGroup}
/> />
<LabeledIconButton <LabeledIconButton
disabled={!shouldShowUngroup()} disabled={!shouldShowUngroup()}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={ungroupIcon} imgSrc={ungroupIcon}
title={props.intl.formatMessage(messages.ungroup)} title={intl.formatMessage(messages.ungroup)}
onClick={props.onUngroup} onClick={props.onUngroup}
/> />
</InputGroup> : null </InputGroup> : null
@ -184,16 +185,16 @@ const FixedToolsComponent = props => {
<InputGroup className={styles.modDashedBorder}> <InputGroup className={styles.modDashedBorder}>
<LabeledIconButton <LabeledIconButton
disabled={!shouldShowBringForward()} disabled={!shouldShowBringForward()}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={sendForwardIcon} imgSrc={sendForwardIcon}
title={props.intl.formatMessage(messages.forward)} title={intl.formatMessage(messages.forward)}
onClick={props.onSendForward} onClick={props.onSendForward}
/> />
<LabeledIconButton <LabeledIconButton
disabled={!shouldShowSendBackward()} disabled={!shouldShowSendBackward()}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={sendBackwardIcon} imgSrc={sendBackwardIcon}
title={props.intl.formatMessage(messages.backward)} title={intl.formatMessage(messages.backward)}
onClick={props.onSendBackward} onClick={props.onSendBackward}
/> />
</InputGroup> : null </InputGroup> : null
@ -204,16 +205,16 @@ const FixedToolsComponent = props => {
<InputGroup className={styles.row}> <InputGroup className={styles.row}>
<LabeledIconButton <LabeledIconButton
disabled={!shouldShowBringForward()} disabled={!shouldShowBringForward()}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={sendFrontIcon} imgSrc={sendFrontIcon}
title={props.intl.formatMessage(messages.front)} title={intl.formatMessage(messages.front)}
onClick={props.onSendToFront} onClick={props.onSendToFront}
/> />
<LabeledIconButton <LabeledIconButton
disabled={!shouldShowSendBackward()} disabled={!shouldShowSendBackward()}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={sendBackIcon} imgSrc={sendBackIcon}
title={props.intl.formatMessage(messages.back)} title={intl.formatMessage(messages.back)}
onClick={props.onSendToBack} onClick={props.onSendToBack}
/> />
</InputGroup> </InputGroup>
@ -252,7 +253,7 @@ const FixedToolsComponent = props => {
draggable={false} draggable={false}
src={sendFrontIcon} src={sendFrontIcon}
/> />
<span>{props.intl.formatMessage(messages.front)}</span> <span>{intl.formatMessage(messages.front)}</span>
</Button> </Button>
<Button <Button
className={classNames(styles.modMenuItem, { className={classNames(styles.modMenuItem, {
@ -266,7 +267,7 @@ const FixedToolsComponent = props => {
draggable={false} draggable={false}
src={sendBackIcon} src={sendBackIcon}
/> />
<span>{props.intl.formatMessage(messages.back)}</span> <span>{intl.formatMessage(messages.back)}</span>
</Button> </Button>
{/* To be rotation point */} {/* To be rotation point */}
@ -285,7 +286,7 @@ const FixedToolsComponent = props => {
} }
tipSize={.01} tipSize={.01}
> >
{props.intl.formatMessage(messages.more)} {intl.formatMessage(messages.more)}
</Dropdown> </Dropdown>
</InputGroup> </InputGroup>
</MediaQuery> : null </MediaQuery> : null
@ -298,7 +299,6 @@ FixedToolsComponent.propTypes = {
canRedo: PropTypes.func.isRequired, canRedo: PropTypes.func.isRequired,
canUndo: PropTypes.func.isRequired, canUndo: PropTypes.func.isRequired,
format: PropTypes.oneOf(Object.keys(Formats)), format: PropTypes.oneOf(Object.keys(Formats)),
intl: intlShape,
name: PropTypes.string, name: PropTypes.string,
onGroup: PropTypes.func.isRequired, onGroup: PropTypes.func.isRequired,
onRedo: PropTypes.func.isRequired, onRedo: PropTypes.func.isRequired,
@ -321,4 +321,4 @@ const mapStateToProps = state => ({
export default connect( export default connect(
mapStateToProps mapStateToProps
)(injectIntl(FixedToolsComponent)); )(FixedToolsComponent);

View file

@ -12,7 +12,7 @@ import {setShapesFilled} from '../../reducers/fill-bitmap-shapes';
import FontDropdown from '../../containers/font-dropdown.jsx'; import FontDropdown from '../../containers/font-dropdown.jsx';
import LiveInputHOC from '../forms/live-input-hoc.jsx'; import LiveInputHOC from '../forms/live-input-hoc.jsx';
import Label from '../forms/label.jsx'; import Label from '../forms/label.jsx';
import {defineMessages, injectIntl, intlShape} from 'react-intl'; import {defineMessages, useIntl} from 'react-intl';
import Input from '../forms/input.jsx'; import Input from '../forms/input.jsx';
import InputGroup from '../input-group/input-group.jsx'; import InputGroup from '../input-group/input-group.jsx';
import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx'; import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
@ -43,6 +43,7 @@ import {MAX_STROKE_WIDTH} from '../../reducers/stroke-width';
const LiveInput = LiveInputHOC(Input); const LiveInput = LiveInputHOC(Input);
const ModeToolsComponent = props => { const ModeToolsComponent = props => {
const intl = useIntl();
const messages = defineMessages({ const messages = defineMessages({
brushSize: { brushSize: {
defaultMessage: 'Size', defaultMessage: 'Size',
@ -122,7 +123,7 @@ const ModeToolsComponent = props => {
<div className={classNames(props.className, styles.modeTools)}> <div className={classNames(props.className, styles.modeTools)}>
<div> <div>
<img <img
alt={props.intl.formatMessage(currentMessage)} alt={intl.formatMessage(currentMessage)}
className={styles.modeToolsIcon} className={styles.modeToolsIcon}
draggable={false} draggable={false}
src={currentIcon} src={currentIcon}
@ -151,7 +152,7 @@ const ModeToolsComponent = props => {
<div className={classNames(props.className, styles.modeTools)}> <div className={classNames(props.className, styles.modeTools)}>
<div> <div>
<img <img
alt={props.intl.formatMessage(messages.eraserSize)} alt={intl.formatMessage(messages.eraserSize)}
className={styles.modeToolsIcon} className={styles.modeToolsIcon}
draggable={false} draggable={false}
src={currentIcon} src={currentIcon}
@ -175,24 +176,24 @@ const ModeToolsComponent = props => {
<InputGroup className={classNames(styles.modDashedBorder, styles.modLabeledIconHeight)}> <InputGroup className={classNames(styles.modDashedBorder, styles.modLabeledIconHeight)}>
<LabeledIconButton <LabeledIconButton
disabled={!props.hasSelectedUncurvedPoints} disabled={!props.hasSelectedUncurvedPoints}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={curvedPointIcon} imgSrc={curvedPointIcon}
title={props.intl.formatMessage(messages.curved)} title={intl.formatMessage(messages.curved)}
onClick={props.onCurvePoints} onClick={props.onCurvePoints}
/> />
<LabeledIconButton <LabeledIconButton
disabled={!props.hasSelectedUnpointedPoints} disabled={!props.hasSelectedUnpointedPoints}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={straightPointIcon} imgSrc={straightPointIcon}
title={props.intl.formatMessage(messages.pointed)} title={intl.formatMessage(messages.pointed)}
onClick={props.onPointPoints} onClick={props.onPointPoints}
/> />
</InputGroup> </InputGroup>
<InputGroup className={classNames(styles.modLabeledIconHeight)}> <InputGroup className={classNames(styles.modLabeledIconHeight)}>
<LabeledIconButton <LabeledIconButton
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={deleteIcon} imgSrc={deleteIcon}
title={props.intl.formatMessage(messages.delete)} title={intl.formatMessage(messages.delete)}
onClick={props.onDelete} onClick={props.onDelete}
/> />
</InputGroup> </InputGroup>
@ -205,38 +206,38 @@ const ModeToolsComponent = props => {
<div className={classNames(props.className, styles.modeTools)}> <div className={classNames(props.className, styles.modeTools)}>
<InputGroup className={classNames(styles.modDashedBorder, styles.modLabeledIconHeight)}> <InputGroup className={classNames(styles.modDashedBorder, styles.modLabeledIconHeight)}>
<LabeledIconButton <LabeledIconButton
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={copyIcon} imgSrc={copyIcon}
title={props.intl.formatMessage(messages.copy)} title={intl.formatMessage(messages.copy)}
onClick={props.onCopyToClipboard} onClick={props.onCopyToClipboard}
/> />
<LabeledIconButton <LabeledIconButton
disabled={!(props.clipboardItems.length > 0)} disabled={!(props.clipboardItems.length > 0)}
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={pasteIcon} imgSrc={pasteIcon}
title={props.intl.formatMessage(messages.paste)} title={intl.formatMessage(messages.paste)}
onClick={props.onPasteFromClipboard} onClick={props.onPasteFromClipboard}
/> />
</InputGroup> </InputGroup>
<InputGroup className={classNames(styles.modDashedBorder, styles.modLabeledIconHeight)}> <InputGroup className={classNames(styles.modDashedBorder, styles.modLabeledIconHeight)}>
<LabeledIconButton <LabeledIconButton
hideLabel={hideLabel(props.intl.locale)} hideLabel={hideLabel(intl.locale)}
imgSrc={deleteIcon} imgSrc={deleteIcon}
title={props.intl.formatMessage(messages.delete)} title={intl.formatMessage(messages.delete)}
onClick={props.onDelete} onClick={props.onDelete}
/> />
</InputGroup> </InputGroup>
<InputGroup className={classNames(styles.modLabeledIconHeight)}> <InputGroup className={classNames(styles.modLabeledIconHeight)}>
<LabeledIconButton <LabeledIconButton
hideLabel={props.intl.locale !== 'en'} hideLabel={intl.locale !== 'en'}
imgSrc={flipHorizontalIcon} imgSrc={flipHorizontalIcon}
title={props.intl.formatMessage(messages.flipHorizontal)} title={intl.formatMessage(messages.flipHorizontal)}
onClick={props.onFlipHorizontal} onClick={props.onFlipHorizontal}
/> />
<LabeledIconButton <LabeledIconButton
hideLabel={props.intl.locale !== 'en'} hideLabel={intl.locale !== 'en'}
imgSrc={flipVerticalIcon} imgSrc={flipVerticalIcon}
title={props.intl.formatMessage(messages.flipVertical)} title={intl.formatMessage(messages.flipVertical)}
onClick={props.onFlipVertical} onClick={props.onFlipVertical}
/> />
</InputGroup> </InputGroup>
@ -266,7 +267,7 @@ const ModeToolsComponent = props => {
<LabeledIconButton <LabeledIconButton
highlighted={props.fillBitmapShapes} highlighted={props.fillBitmapShapes}
imgSrc={fillIcon} imgSrc={fillIcon}
title={props.intl.formatMessage(messages.filled)} title={intl.formatMessage(messages.filled)}
onClick={props.onFillShapes} onClick={props.onFillShapes}
/> />
</InputGroup> </InputGroup>
@ -274,13 +275,13 @@ const ModeToolsComponent = props => {
<LabeledIconButton <LabeledIconButton
highlighted={!props.fillBitmapShapes} highlighted={!props.fillBitmapShapes}
imgSrc={outlineIcon} imgSrc={outlineIcon}
title={props.intl.formatMessage(messages.outlined)} title={intl.formatMessage(messages.outlined)}
onClick={props.onOutlineShapes} onClick={props.onOutlineShapes}
/> />
</InputGroup> </InputGroup>
{props.fillBitmapShapes ? null : ( {props.fillBitmapShapes ? null : (
<InputGroup> <InputGroup>
<Label text={props.intl.formatMessage(messages.thickness)}> <Label text={intl.formatMessage(messages.thickness)}>
<LiveInput <LiveInput
range range
small small
@ -315,7 +316,6 @@ ModeToolsComponent.propTypes = {
format: PropTypes.oneOf(Object.keys(Formats)), format: PropTypes.oneOf(Object.keys(Formats)),
hasSelectedUncurvedPoints: PropTypes.bool, hasSelectedUncurvedPoints: PropTypes.bool,
hasSelectedUnpointedPoints: PropTypes.bool, hasSelectedUnpointedPoints: PropTypes.bool,
intl: intlShape.isRequired,
mode: PropTypes.string.isRequired, mode: PropTypes.string.isRequired,
onBitBrushSliderChange: PropTypes.func.isRequired, onBitBrushSliderChange: PropTypes.func.isRequired,
onBitEraserSliderChange: PropTypes.func.isRequired, onBitEraserSliderChange: PropTypes.func.isRequired,
@ -367,4 +367,4 @@ const mapDispatchToProps = dispatch => ({
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(injectIntl(ModeToolsComponent)); )(ModeToolsComponent);

View file

@ -1,6 +1,6 @@
import paper from '@scratch/paper'; import paper from '@scratch/paper';
import classNames from 'classnames'; import classNames from 'classnames';
import {defineMessages, injectIntl, intlShape} from 'react-intl'; import {defineMessages, useIntl} from 'react-intl';
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -55,56 +55,29 @@ const messages = defineMessages({
} }
}); });
const PaintEditorComponent = props => ( const PaintEditorComponent = props => {
<div const intl = useIntl();
className={styles.editorContainer} return (
dir={props.rtl ? 'rtl' : 'ltr'} <div
> className={styles.editorContainer}
{props.canvas !== null ? ( // eslint-disable-line no-negated-condition dir={props.rtl ? 'rtl' : 'ltr'}
<div className={styles.editorContainerTop}> >
{/* First row */} {props.canvas !== null ? ( // eslint-disable-line no-negated-condition
<div className={styles.row}> <div className={styles.editorContainerTop}>
<FixedToolsContainer {/* First row */}
canRedo={props.canRedo}
canUndo={props.canUndo}
name={props.name}
onRedo={props.onRedo}
onUndo={props.onUndo}
onUpdateImage={props.onUpdateImage}
onUpdateName={props.onUpdateName}
/>
</div>
{/* Second Row */}
{isVector(props.format) ?
<div className={styles.row}> <div className={styles.row}>
<InputGroup <FixedToolsContainer
className={classNames( canRedo={props.canRedo}
styles.row, canUndo={props.canUndo}
styles.modDashedBorder, name={props.name}
styles.modLabeledIconHeight onRedo={props.onRedo}
)} onUndo={props.onUndo}
> onUpdateImage={props.onUpdateImage}
{/* fill */} onUpdateName={props.onUpdateName}
<FillColorIndicatorComponent />
className={styles.modMarginAfter} </div>
onUpdateImage={props.onUpdateImage} {/* Second Row */}
/> {isVector(props.format) ?
{/* stroke */}
<StrokeColorIndicatorComponent
onUpdateImage={props.onUpdateImage}
/>
{/* stroke width */}
<StrokeWidthIndicatorComponent
onUpdateImage={props.onUpdateImage}
/>
</InputGroup>
<InputGroup className={styles.modModeTools}>
<ModeToolsContainer
onUpdateImage={props.onUpdateImage}
/>
</InputGroup>
</div> :
isBitmap(props.format) ?
<div className={styles.row}> <div className={styles.row}>
<InputGroup <InputGroup
className={classNames( className={classNames(
@ -118,136 +91,151 @@ const PaintEditorComponent = props => (
className={styles.modMarginAfter} className={styles.modMarginAfter}
onUpdateImage={props.onUpdateImage} onUpdateImage={props.onUpdateImage}
/> />
{/* stroke */}
<StrokeColorIndicatorComponent
onUpdateImage={props.onUpdateImage}
/>
{/* stroke width */}
<StrokeWidthIndicatorComponent
onUpdateImage={props.onUpdateImage}
/>
</InputGroup> </InputGroup>
<InputGroup className={styles.modModeTools}> <InputGroup className={styles.modModeTools}>
<ModeToolsContainer <ModeToolsContainer
onUpdateImage={props.onUpdateImage} onUpdateImage={props.onUpdateImage}
/> />
</InputGroup> </InputGroup>
</div> : null </div> :
}
</div>
) : null}
<div className={styles.topAlignRow}>
{/* Modes */}
{props.canvas !== null && isVector(props.format) ? ( // eslint-disable-line no-negated-condition
<div className={styles.modeSelector}>
<SelectMode
onUpdateImage={props.onUpdateImage}
/>
<ReshapeMode
onUpdateImage={props.onUpdateImage}
/>
<BrushMode
onUpdateImage={props.onUpdateImage}
/>
<EraserMode
onUpdateImage={props.onUpdateImage}
/>
<FillMode
onUpdateImage={props.onUpdateImage}
/>
<TextMode
textArea={props.textArea}
onUpdateImage={props.onUpdateImage}
/>
<LineMode
onUpdateImage={props.onUpdateImage}
/>
<OvalMode
onUpdateImage={props.onUpdateImage}
/>
<RectMode
onUpdateImage={props.onUpdateImage}
/>
</div>
) : null}
{props.canvas !== null && isBitmap(props.format) ? ( // eslint-disable-line no-negated-condition
<div className={styles.modeSelector}>
<BitBrushMode
onUpdateImage={props.onUpdateImage}
/>
<BitLineMode
onUpdateImage={props.onUpdateImage}
/>
<BitOvalMode
onUpdateImage={props.onUpdateImage}
/>
<BitRectMode
onUpdateImage={props.onUpdateImage}
/>
<TextMode
isBitmap
textArea={props.textArea}
onUpdateImage={props.onUpdateImage}
/>
<BitFillMode
onUpdateImage={props.onUpdateImage}
/>
<BitEraserMode
onUpdateImage={props.onUpdateImage}
/>
<BitSelectMode
onUpdateImage={props.onUpdateImage}
/>
</div>
) : null}
<div className={styles.controlsContainer}>
{/* Canvas */}
<ScrollableCanvas
canvas={props.canvas}
hideScrollbars={props.isEyeDropping}
style={styles.canvasContainer}
>
<PaperCanvas
canvasRef={props.setCanvas}
image={props.image}
imageFormat={props.imageFormat}
imageId={props.imageId}
rotationCenterX={props.rotationCenterX}
rotationCenterY={props.rotationCenterY}
zoomLevelId={props.zoomLevelId}
onUpdateImage={props.onUpdateImage}
/>
<textarea
className={styles.textArea}
ref={props.setTextArea}
spellCheck={false}
/>
{props.isEyeDropping &&
props.colorInfo !== null &&
!props.colorInfo.hideLoupe ? (
<Box className={styles.colorPickerWrapper}>
<Loupe
colorInfo={props.colorInfo}
pixelRatio={paper.project.view.pixelRatio}
/>
</Box>
) : null
}
</ScrollableCanvas>
<div className={styles.canvasControls}>
{isVector(props.format) ?
<Button
className={styles.bitmapButton}
onClick={props.onSwitchToBitmap}
>
<img
className={styles.bitmapButtonIcon}
draggable={false}
src={bitmapIcon}
/>
<span className={styles.buttonText}>
{props.intl.formatMessage(messages.bitmap)}
</span>
</Button> :
isBitmap(props.format) ? isBitmap(props.format) ?
<div className={styles.row}>
<InputGroup
className={classNames(
styles.row,
styles.modDashedBorder,
styles.modLabeledIconHeight
)}
>
{/* fill */}
<FillColorIndicatorComponent
className={styles.modMarginAfter}
onUpdateImage={props.onUpdateImage}
/>
</InputGroup>
<InputGroup className={styles.modModeTools}>
<ModeToolsContainer
onUpdateImage={props.onUpdateImage}
/>
</InputGroup>
</div> : null
}
</div>
) : null}
<div className={styles.topAlignRow}>
{/* Modes */}
{props.canvas !== null && isVector(props.format) ? ( // eslint-disable-line no-negated-condition
<div className={styles.modeSelector}>
<SelectMode
onUpdateImage={props.onUpdateImage}
/>
<ReshapeMode
onUpdateImage={props.onUpdateImage}
/>
<BrushMode
onUpdateImage={props.onUpdateImage}
/>
<EraserMode
onUpdateImage={props.onUpdateImage}
/>
<FillMode
onUpdateImage={props.onUpdateImage}
/>
<TextMode
textArea={props.textArea}
onUpdateImage={props.onUpdateImage}
/>
<LineMode
onUpdateImage={props.onUpdateImage}
/>
<OvalMode
onUpdateImage={props.onUpdateImage}
/>
<RectMode
onUpdateImage={props.onUpdateImage}
/>
</div>
) : null}
{props.canvas !== null && isBitmap(props.format) ? ( // eslint-disable-line no-negated-condition
<div className={styles.modeSelector}>
<BitBrushMode
onUpdateImage={props.onUpdateImage}
/>
<BitLineMode
onUpdateImage={props.onUpdateImage}
/>
<BitOvalMode
onUpdateImage={props.onUpdateImage}
/>
<BitRectMode
onUpdateImage={props.onUpdateImage}
/>
<TextMode
isBitmap
textArea={props.textArea}
onUpdateImage={props.onUpdateImage}
/>
<BitFillMode
onUpdateImage={props.onUpdateImage}
/>
<BitEraserMode
onUpdateImage={props.onUpdateImage}
/>
<BitSelectMode
onUpdateImage={props.onUpdateImage}
/>
</div>
) : null}
<div className={styles.controlsContainer}>
{/* Canvas */}
<ScrollableCanvas
canvas={props.canvas}
hideScrollbars={props.isEyeDropping}
style={styles.canvasContainer}
>
<PaperCanvas
canvasRef={props.setCanvas}
image={props.image}
imageFormat={props.imageFormat}
imageId={props.imageId}
rotationCenterX={props.rotationCenterX}
rotationCenterY={props.rotationCenterY}
zoomLevelId={props.zoomLevelId}
onUpdateImage={props.onUpdateImage}
/>
<textarea
className={styles.textArea}
ref={props.setTextArea}
spellCheck={false}
/>
{props.isEyeDropping &&
props.colorInfo !== null &&
!props.colorInfo.hideLoupe ? (
<Box className={styles.colorPickerWrapper}>
<Loupe
colorInfo={props.colorInfo}
pixelRatio={paper.project.view.pixelRatio}
/>
</Box>
) : null
}
</ScrollableCanvas>
<div className={styles.canvasControls}>
{isVector(props.format) ?
<Button <Button
className={styles.bitmapButton} className={styles.bitmapButton}
onClick={props.onSwitchToVector} onClick={props.onSwitchToBitmap}
> >
<img <img
className={styles.bitmapButtonIcon} className={styles.bitmapButtonIcon}
@ -255,53 +243,68 @@ const PaintEditorComponent = props => (
src={bitmapIcon} src={bitmapIcon}
/> />
<span className={styles.buttonText}> <span className={styles.buttonText}>
{props.intl.formatMessage(messages.vector)} {intl.formatMessage(messages.bitmap)}
</span> </span>
</Button> : null </Button> :
} isBitmap(props.format) ?
{/* Zoom controls */} <Button
<InputGroup className={styles.zoomControls}> className={styles.bitmapButton}
<ButtonGroup> onClick={props.onSwitchToVector}
<Button >
className={styles.buttonGroupButton} <img
onClick={props.onZoomOut} className={styles.bitmapButtonIcon}
> draggable={false}
<img src={bitmapIcon}
alt="Zoom Out" />
className={styles.buttonGroupButtonIcon} <span className={styles.buttonText}>
draggable={false} {intl.formatMessage(messages.vector)}
src={zoomOutIcon} </span>
/> </Button> : null
</Button> }
<Button {/* Zoom controls */}
className={styles.buttonGroupButton} <InputGroup className={styles.zoomControls}>
onClick={props.onZoomReset} <ButtonGroup>
> <Button
<img className={styles.buttonGroupButton}
alt="Zoom Reset" onClick={props.onZoomOut}
className={styles.buttonGroupButtonIcon} >
draggable={false} <img
src={zoomResetIcon} alt="Zoom Out"
/> className={styles.buttonGroupButtonIcon}
</Button> draggable={false}
<Button src={zoomOutIcon}
className={styles.buttonGroupButton} />
onClick={props.onZoomIn} </Button>
> <Button
<img className={styles.buttonGroupButton}
alt="Zoom In" onClick={props.onZoomReset}
className={styles.buttonGroupButtonIcon} >
draggable={false} <img
src={zoomInIcon} alt="Zoom Reset"
/> className={styles.buttonGroupButtonIcon}
</Button> draggable={false}
</ButtonGroup> src={zoomResetIcon}
</InputGroup> />
</Button>
<Button
className={styles.buttonGroupButton}
onClick={props.onZoomIn}
>
<img
alt="Zoom In"
className={styles.buttonGroupButtonIcon}
draggable={false}
src={zoomInIcon}
/>
</Button>
</ButtonGroup>
</InputGroup>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> );
); };
PaintEditorComponent.propTypes = { PaintEditorComponent.propTypes = {
canRedo: PropTypes.func.isRequired, canRedo: PropTypes.func.isRequired,
@ -315,7 +318,6 @@ PaintEditorComponent.propTypes = {
]), ]),
imageFormat: PropTypes.string, imageFormat: PropTypes.string,
imageId: PropTypes.string, imageId: PropTypes.string,
intl: intlShape,
isEyeDropping: PropTypes.bool, isEyeDropping: PropTypes.bool,
name: PropTypes.string, name: PropTypes.string,
onRedo: PropTypes.func.isRequired, onRedo: PropTypes.func.isRequired,
@ -336,4 +338,4 @@ PaintEditorComponent.propTypes = {
zoomLevelId: PropTypes.string zoomLevelId: PropTypes.string
}; };
export default injectIntl(PaintEditorComponent); export default PaintEditorComponent;

View file

@ -1,31 +1,34 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {injectIntl, intlShape} from 'react-intl'; import {useIntl} from 'react-intl';
import Button from '../button/button.jsx'; import Button from '../button/button.jsx';
import styles from './tool-select-base.css'; import styles from './tool-select-base.css';
const ToolSelectComponent = props => ( const ToolSelectComponent = props => {
<Button const intl = useIntl();
className={ return (
classNames(props.className, styles.modToolSelect, { <Button
[styles.isSelected]: props.isSelected className={
}) classNames(props.className, styles.modToolSelect, {
} [styles.isSelected]: props.isSelected
disabled={props.disabled} })
title={props.intl.formatMessage(props.imgDescriptor)} }
onClick={props.onMouseDown} disabled={props.disabled}
> title={intl.formatMessage(props.imgDescriptor)}
<img onClick={props.onMouseDown}
alt={props.intl.formatMessage(props.imgDescriptor)} >
className={styles.toolSelectIcon} <img
draggable={false} alt={intl.formatMessage(props.imgDescriptor)}
src={props.imgSrc} className={styles.toolSelectIcon}
/> draggable={false}
</Button> src={props.imgSrc}
); />
</Button>
);
};
ToolSelectComponent.propTypes = { ToolSelectComponent.propTypes = {
className: PropTypes.string, className: PropTypes.string,
@ -36,9 +39,8 @@ ToolSelectComponent.propTypes = {
id: PropTypes.string id: PropTypes.string
}).isRequired, }).isRequired,
imgSrc: PropTypes.string.isRequired, imgSrc: PropTypes.string.isRequired,
intl: intlShape.isRequired,
isSelected: PropTypes.bool.isRequired, isSelected: PropTypes.bool.isRequired,
onMouseDown: PropTypes.func.isRequired onMouseDown: PropTypes.func.isRequired
}; };
export default injectIntl(ToolSelectComponent); export default ToolSelectComponent;

View file

@ -2,7 +2,8 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import bindAll from 'lodash.bindall'; import bindAll from 'lodash.bindall';
import parseColor from 'parse-color'; import parseColor from 'parse-color';
import {injectIntl, intlShape} from 'react-intl'; import {injectIntl} from 'react-intl';
import intlShape from '../lib/intl-shape.js';
import {getSelectedLeafItems} from '../helper/selection'; import {getSelectedLeafItems} from '../helper/selection';
import Formats, {isBitmap} from '../lib/format'; import Formats, {isBitmap} from '../lib/format';

10
src/lib/intl-shape.js Normal file
View file

@ -0,0 +1,10 @@
import PropTypes from 'prop-types';
// intlShape was removed in react-intl@3 and replaced with a TypeScript interface.
// These are some of the commonly used properties from the intl object.
const intlShape = PropTypes.shape({
locale: PropTypes.string.isRequired,
formatMessage: PropTypes.func.isRequired
});
export default intlShape;

View file

@ -1,15 +1,8 @@
import {addLocaleData} from 'react-intl';
import {updateIntl as superUpdateIntl} from 'react-intl-redux'; import {updateIntl as superUpdateIntl} from 'react-intl-redux';
import {IntlProvider, intlReducer} from 'react-intl-redux'; import {IntlProvider, intlReducer} from 'react-intl-redux';
import localeData from 'scratch-l10n';
import paintMessages from 'scratch-l10n/locales/paint-editor-msgs'; import paintMessages from 'scratch-l10n/locales/paint-editor-msgs';
Object.keys(localeData).forEach(locale => {
// TODO: will need to handle locales not in the default intl - see www/custom-locales
addLocaleData(localeData[locale].localeData);
});
const intlInitialState = { const intlInitialState = {
intl: { intl: {
defaultLocale: 'en', defaultLocale: 'en',

View file

@ -11,7 +11,6 @@ const intl = {
formatRelative: ({defaultMessage}) => defaultMessage, formatRelative: ({defaultMessage}) => defaultMessage,
formatNumber: ({defaultMessage}) => defaultMessage, formatNumber: ({defaultMessage}) => defaultMessage,
formatPlural: ({defaultMessage}) => defaultMessage, formatPlural: ({defaultMessage}) => defaultMessage,
formatHTMLMessage: ({defaultMessage}) => defaultMessage,
now: () => 0 now: () => 0
}; };

View file

@ -17,7 +17,12 @@ const base = {
rules: [{ rules: [{
test: /\.jsx?$/, test: /\.jsx?$/,
loader: 'babel-loader', loader: 'babel-loader',
include: path.resolve(__dirname, 'src'), include: [
path.resolve(__dirname, 'src'),
path.join(__dirname, 'node_modules/react-intl'),
path.join(__dirname, 'node_modules/intl-messageformat'),
path.join(__dirname, 'node_modules/intl-messageformat-parser')
],
options: { options: {
plugins: ['transform-object-rest-spread'], plugins: ['transform-object-rest-spread'],
presets: [ presets: [