scratch-paint 0.2.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.circleci/config.yml +113 -0
  2. package/.editorconfig +1 -1
  3. package/.gitattributes +1 -0
  4. package/.husky/.gitattributes +1 -0
  5. package/.husky/commit-msg +4 -0
  6. package/CHANGELOG.md +81 -0
  7. package/commitlint.config.js +4 -0
  8. package/dist/scratch-paint.js +2650 -4086
  9. package/dist/scratch-paint.js.map +1 -1
  10. package/pack/scratch-paint-1.0.2.tgz +0 -0
  11. package/package.json +62 -42
  12. package/release.config.js +13 -0
  13. package/renovate.json5 +7 -0
  14. package/src/.eslintrc.js +3 -1
  15. package/src/components/color-picker/color-picker.jsx +11 -1
  16. package/src/components/fixed-tools/fixed-tools.jsx +1 -2
  17. package/src/components/forms/slider.jsx +21 -4
  18. package/src/components/mode-tools/mode-tools.jsx +1 -2
  19. package/src/components/paint-editor/paint-editor.jsx +1 -2
  20. package/src/containers/color-indicator.jsx +1 -2
  21. package/src/containers/fixed-tools.jsx +1 -2
  22. package/src/containers/line-mode.jsx +1 -2
  23. package/src/containers/mode-tools.jsx +1 -2
  24. package/src/containers/paint-editor.jsx +4 -5
  25. package/src/containers/paper-canvas.jsx +5 -2
  26. package/src/containers/stroke-color-indicator.jsx +1 -2
  27. package/src/containers/stroke-width-indicator.jsx +4 -4
  28. package/src/helper/bit-tools/brush-tool.js +1 -2
  29. package/src/helper/bit-tools/line-tool.js +1 -2
  30. package/src/helper/bitmap.js +7 -3
  31. package/src/helper/selection-tools/move-tool.js +6 -6
  32. package/src/helper/style-path.js +2 -4
  33. package/src/helper/tools/fill-tool.js +11 -1
  34. package/src/helper/undo.js +1 -2
  35. package/src/hocs/copy-paste-hoc.jsx +1 -2
  36. package/src/hocs/keyboard-shortcuts-hoc.jsx +1 -2
  37. package/src/hocs/undo-hoc.jsx +4 -3
  38. package/src/hocs/update-image-hoc.jsx +6 -6
  39. package/src/playground/playground.jsx +3 -0
  40. package/webpack.config.js +1 -3
  41. package/.travis.yml +0 -80
Binary file
package/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "scratch-paint",
3
- "version": "0.2.0",
3
+ "version": "1.0.2",
4
4
  "description": "Graphical User Interface for the Scratch 3.0 paint editor, which is used to make and edit sprites for use in projects.",
5
5
  "main": "./dist/scratch-paint.js",
6
6
  "browser": "./src/index.js",
7
7
  "scripts": {
8
8
  "build": "npm run clean && webpack --progress --colors --bail",
9
9
  "clean": "rimraf ./dist && mkdirp dist && rimraf ./playground && mkdirp playground",
10
- "deploy": "touch playground/.nojekyll && gh-pages -t -d playground -m \"Build for $(git log --pretty=format:%H -n1)\"",
10
+ "deploy": "touch playground/.nojekyll && gh-pages -t -d playground -m \"[skip ci] Build for $(git log --pretty=format:%H -n1)\"",
11
11
  "i18n:push": "tx-push-src scratch-editor paint-editor ./translations/en.json",
12
12
  "i18n:src": "rimraf ./translations/messages && babel src > tmp.js && rimraf tmp.js && ./scripts/build-i18n-source.js ./translations/messages/ ./translations/",
13
13
  "lint": "eslint . --ext .js,.jsx",
14
+ "prepare": "husky install",
14
15
  "start": "webpack-dev-server",
15
16
  "test": "npm run lint && npm run unit && NODE_ENV=production npm run build",
16
- "unit": "jest",
17
+ "unit": "jest --reporters=default",
17
18
  "watch": "webpack --progress --colors --watch"
18
19
  },
19
20
  "author": "Massachusetts Institute of Technology",
@@ -21,7 +22,7 @@
21
22
  "homepage": "https://github.com/LLK/scratch-paint#readme",
22
23
  "repository": {
23
24
  "type": "git",
24
- "url": "git+ssh://git@github.com/LLK/scratch-paint.git"
25
+ "url": "https://github.com/LLK/scratch-paint.git"
25
26
  },
26
27
  "dependencies": {
27
28
  "@scratch/paper": "0.11.20200728195508",
@@ -31,8 +32,7 @@
31
32
  "lodash.omit": "4.5.0",
32
33
  "minilog": "3.1.0",
33
34
  "parse-color": "1.0.0",
34
- "prop-types": "^15.5.10",
35
- "scratch-svg-renderer": "0.2.0-prerelease.20200610220938"
35
+ "prop-types": "^15.5.10"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": "^16",
@@ -44,37 +44,42 @@
44
44
  "react-responsive": "^4",
45
45
  "react-style-proptype": "^3",
46
46
  "react-tooltip": "^3",
47
- "redux": "^3"
47
+ "redux": "^3",
48
+ "scratch-render-fonts": "^1.0.0-prerelease.20210401210003"
48
49
  },
49
50
  "devDependencies": {
51
+ "@commitlint/cli": "17.0.3",
52
+ "@commitlint/config-conventional": "17.0.3",
50
53
  "autoprefixer": "9.7.4",
51
54
  "babel-cli": "6.26.0",
52
- "babel-core": "^6.23.1",
53
- "babel-eslint": "^8.2.1",
54
- "babel-jest": "^23.0.1",
55
- "babel-loader": "^7.1.4",
55
+ "babel-core": "6.26.3",
56
+ "babel-eslint": "10.1.0",
57
+ "babel-jest": "23.6.0",
58
+ "babel-loader": "7.1.5",
56
59
  "babel-plugin-react-intl": "3.0.1",
57
- "babel-plugin-transform-object-rest-spread": "^6.22.0",
58
- "babel-preset-env": "^1.6.1",
59
- "babel-preset-react": "^6.22.0",
60
+ "babel-plugin-transform-object-rest-spread": "6.26.0",
61
+ "babel-preset-env": "1.7.0",
62
+ "babel-preset-react": "6.24.1",
60
63
  "css-loader": "3.4.0",
61
- "enzyme": "^3.6.0",
62
- "enzyme-adapter-react-16": "^1.5.0",
63
- "eslint": "^4.4.1",
64
- "eslint-config-import": "^0.13.0",
65
- "eslint-config-scratch": "^5.0.0",
66
- "eslint-plugin-import": "^2.18.2",
64
+ "enzyme": "3.11.0",
65
+ "enzyme-adapter-react-16": "1.15.6",
66
+ "eslint": "7.32.0",
67
+ "eslint-config-scratch": "7.0.0",
68
+ "eslint-plugin-import": "2.26.0",
67
69
  "eslint-plugin-react": "7.20.3",
68
- "gh-pages": "github:rschamp/gh-pages#publish-branch-to-subfolder",
70
+ "gh-pages": "3.2.3",
69
71
  "html-webpack-plugin": "3.2.0",
70
- "jest": "^22.2.2",
71
- "jest-canvas-mock": "^2.2.0",
72
+ "husky": "8.0.1",
73
+ "jest": "22.4.4",
74
+ "jest-canvas-mock": "2.3.1",
75
+ "jest-junit": "13.0.0",
76
+ "json": "9.0.6",
72
77
  "lodash.defaultsdeep": "4.6.1",
73
- "mkdirp": "^1.0.3",
74
- "postcss-import": "^12.0.0",
75
- "postcss-loader": "^3.0.0",
76
- "postcss-simple-vars": "^5.0.1",
77
- "raf": "^3.4.0",
78
+ "mkdirp": "1.0.4",
79
+ "postcss-import": "12.0.1",
80
+ "postcss-loader": "3.0.0",
81
+ "postcss-simple-vars": "5.0.2",
82
+ "raf": "3.4.1",
78
83
  "react": "16.2.0",
79
84
  "react-dom": "16.4.0",
80
85
  "react-intl": "2.9.0",
@@ -83,22 +88,29 @@
83
88
  "react-redux": "5.1.0",
84
89
  "react-responsive": "4.1.0",
85
90
  "react-style-proptype": "3.2.2",
86
- "react-test-renderer": "^16.0.0",
91
+ "react-test-renderer": "16.5.1",
87
92
  "react-tooltip": "3.8.4",
88
93
  "redux": "3.7.2",
89
- "redux-mock-store": "^1.2.3",
94
+ "redux-mock-store": "1.5.4",
90
95
  "redux-throttle": "0.1.1",
91
- "regenerator-runtime": "^0.13.3",
92
- "rimraf": "^2.6.1",
93
- "scratch-l10n": "3.1.20181129221712",
94
- "style-loader": "^1.0.0",
95
- "svg-url-loader": "^3.0.0",
96
- "tap": "^14.4.3",
97
- "uglifyjs-webpack-plugin": "^2.0.1",
98
- "url-loader": "^2.1.0",
99
- "webpack": "^4.8.0",
100
- "webpack-cli": "^3.1.0",
101
- "webpack-dev-server": "^3.1.9"
96
+ "regenerator-runtime": "0.13.9",
97
+ "rimraf": "2.7.1",
98
+ "scratch-l10n": "3.14.20220826031556",
99
+ "scratch-render-fonts": "1.0.0-prerelease.20210401210003",
100
+ "scratch-semantic-release-config": "1.0.4",
101
+ "style-loader": "1.3.0",
102
+ "svg-url-loader": "3.0.3",
103
+ "tap": "14.11.0",
104
+ "uglifyjs-webpack-plugin": "2.2.0",
105
+ "url-loader": "2.3.0",
106
+ "webpack": "4.46.0",
107
+ "webpack-cli": "3.3.12",
108
+ "webpack-dev-server": "3.11.2"
109
+ },
110
+ "config": {
111
+ "commitizen": {
112
+ "path": "cz-conventional-changelog"
113
+ }
102
114
  },
103
115
  "jest": {
104
116
  "setupFiles": [
@@ -111,5 +123,13 @@
111
123
  "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test/__mocks__/fileMock.js",
112
124
  "\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js"
113
125
  }
114
- }
126
+ },
127
+ "jest-junit": {
128
+ "outputDirectory": "./test/results"
129
+ },
130
+ "browserslist": [
131
+ "last 3 versions",
132
+ "Safari >= 8",
133
+ "iOS >= 8"
134
+ ]
115
135
  }
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ extends: 'scratch-semantic-release-config',
3
+ branches: [
4
+ {
5
+ name: 'develop'
6
+ // default channel
7
+ },
8
+ {
9
+ name: 'hotfix/*',
10
+ channel: 'hotfix'
11
+ }
12
+ ]
13
+ };
package/renovate.json5 ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+
4
+ "extends": [
5
+ "github>LLK/scratch-renovate-config:conservative"
6
+ ]
7
+ }
package/src/.eslintrc.js CHANGED
@@ -1,6 +1,8 @@
1
+ /* eslint-disable import/no-commonjs */
1
2
  module.exports = {
3
+ /* eslint-enable import/no-commonjs */
2
4
  root: true,
3
- extends: ['scratch', 'scratch/es6', 'scratch/react', 'import'],
5
+ extends: ['scratch', 'scratch/es6', 'scratch/react', 'plugin:import/recommended'],
4
6
  env: {
5
7
  browser: true
6
8
  },
@@ -5,7 +5,7 @@ import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-int
5
5
  import classNames from 'classnames';
6
6
  import parseColor from 'parse-color';
7
7
 
8
- import Slider from '../forms/slider.jsx';
8
+ import Slider, {CONTAINER_WIDTH, HANDLE_WIDTH} from '../forms/slider.jsx';
9
9
  import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
10
10
  import styles from './color-picker.css';
11
11
  import GradientTypes from '../../lib/gradient-types';
@@ -53,6 +53,16 @@ class ColorPickerComponent extends React.Component {
53
53
  throw new Error(`Unknown channel for color sliders: ${channel}`);
54
54
  }
55
55
  }
56
+
57
+ // The sliders are a rounded capsule shape, and the slider handles are circles. As a consequence, when the
58
+ // slider handle is fully to one side, its center is actually moved away from the start/end of the slider by
59
+ // the slider handle's radius, meaning that the effective range of the slider excludes the rounded caps.
60
+ // To compensate for this, position the first stop to where the rounded cap ends, and position the last stop
61
+ // to where the rounded cap begins.
62
+ const halfHandleWidth = HANDLE_WIDTH / 2;
63
+ stops[0] += ` 0 ${halfHandleWidth}px`;
64
+ stops[stops.length - 1] += ` ${CONTAINER_WIDTH - halfHandleWidth}px 100%`;
65
+
56
66
  return `linear-gradient(to left, ${stops.join(',')})`;
57
67
  }
58
68
  render () {
@@ -12,12 +12,11 @@ import Button from '../button/button.jsx';
12
12
  import ButtonGroup from '../button-group/button-group.jsx';
13
13
  import Dropdown from '../dropdown/dropdown.jsx';
14
14
  import {defineMessages, injectIntl, intlShape} from 'react-intl';
15
- import Formats from '../../lib/format';
15
+ import Formats, {isVector} from '../../lib/format';
16
16
  import Input from '../forms/input.jsx';
17
17
  import InputGroup from '../input-group/input-group.jsx';
18
18
  import Label from '../forms/label.jsx';
19
19
  import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
20
- import {isVector} from '../../lib/format';
21
20
  import layout from '../../lib/layout-constants';
22
21
  import {hideLabel} from '../../lib/hide-label';
23
22
  import styles from './fixed-tools.css';
@@ -17,15 +17,21 @@ class SliderComponent extends React.Component {
17
17
  'handleMouseUp',
18
18
  'handleMouseMove',
19
19
  'handleClickBackground',
20
- 'setBackground'
20
+ 'setBackground',
21
+ 'setHandle'
21
22
  ]);
23
+
24
+ // Distance from the left edge of the slider handle to the mouse down/click event
25
+ this.handleClickOffset = 0;
22
26
  }
23
27
 
24
- handleMouseDown () {
28
+ handleMouseDown (event) {
25
29
  document.addEventListener('mousemove', this.handleMouseMove);
26
30
  document.addEventListener('mouseup', this.handleMouseUp);
27
31
  document.addEventListener('touchmove', this.handleMouseMove, {passive: false});
28
32
  document.addEventListener('touchend', this.handleMouseUp);
33
+
34
+ this.handleClickOffset = getEventXY(event).x - this.handle.getBoundingClientRect().left;
29
35
  }
30
36
 
31
37
  handleMouseUp () {
@@ -41,20 +47,29 @@ class SliderComponent extends React.Component {
41
47
  }
42
48
 
43
49
  handleClickBackground (event) {
50
+ // Because the slider handle is a child of the "background" element this handler is registered to, it calls this
51
+ // when clicked as well. We only want to change the slider value if the user clicked on the background itself.
52
+ if (event.target !== this.background) return;
53
+ // Move slider handle's center to the cursor
54
+ this.handleClickOffset = HANDLE_WIDTH / 2;
44
55
  this.props.onChange(this.scaleMouseToSliderPosition(event));
45
56
  }
46
57
 
47
58
  scaleMouseToSliderPosition (event){
48
59
  const {x} = getEventXY(event);
49
60
  const backgroundBBox = this.background.getBoundingClientRect();
50
- const scaledX = x - backgroundBBox.left;
51
- return Math.max(0, Math.min(100, 100 * scaledX / backgroundBBox.width));
61
+ const scaledX = x - backgroundBBox.left - this.handleClickOffset;
62
+ return Math.max(0, Math.min(100, 100 * scaledX / (backgroundBBox.width - HANDLE_WIDTH)));
52
63
  }
53
64
 
54
65
  setBackground (ref) {
55
66
  this.background = ref;
56
67
  }
57
68
 
69
+ setHandle (ref) {
70
+ this.handle = ref;
71
+ }
72
+
58
73
  render () {
59
74
  const halfHandleWidth = HANDLE_WIDTH / 2;
60
75
  const pixelMin = halfHandleWidth;
@@ -76,6 +91,7 @@ class SliderComponent extends React.Component {
76
91
  >
77
92
  <div
78
93
  className={styles.handle}
94
+ ref={this.setHandle}
79
95
  style={{
80
96
  left: `${handleOffset}px`
81
97
  }}
@@ -99,3 +115,4 @@ SliderComponent.defaultProps = {
99
115
  };
100
116
 
101
117
  export default SliderComponent;
118
+ export {CONTAINER_WIDTH, HANDLE_WIDTH};
@@ -17,8 +17,7 @@ import Input from '../forms/input.jsx';
17
17
  import InputGroup from '../input-group/input-group.jsx';
18
18
  import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
19
19
  import Modes from '../../lib/modes';
20
- import Formats from '../../lib/format';
21
- import {isBitmap, isVector} from '../../lib/format';
20
+ import Formats, {isBitmap, isVector} from '../../lib/format';
22
21
  import {hideLabel} from '../../lib/hide-label';
23
22
  import styles from './mode-tools.css';
24
23
 
@@ -34,8 +34,7 @@ import StrokeColorIndicatorComponent from '../../containers/stroke-color-indicat
34
34
  import StrokeWidthIndicatorComponent from '../../containers/stroke-width-indicator.jsx';
35
35
  import TextMode from '../../containers/text-mode.jsx';
36
36
 
37
- import Formats from '../../lib/format';
38
- import {isBitmap, isVector} from '../../lib/format';
37
+ import Formats, {isBitmap, isVector} from '../../lib/format';
39
38
  import styles from './paint-editor.css';
40
39
 
41
40
  import bitmapIcon from './icons/bitmap.svg';
@@ -5,8 +5,7 @@ import parseColor from 'parse-color';
5
5
  import {injectIntl, intlShape} from 'react-intl';
6
6
 
7
7
  import {getSelectedLeafItems} from '../helper/selection';
8
- import Formats from '../lib/format';
9
- import {isBitmap} from '../lib/format';
8
+ import Formats, {isBitmap} from '../lib/format';
10
9
  import GradientTypes from '../lib/gradient-types';
11
10
 
12
11
  import ColorIndicatorComponent from '../components/color-indicator.jsx';
@@ -15,8 +15,7 @@ import {getSelectedLeafItems} from '../helper/selection';
15
15
  import {bringToFront, sendBackward, sendToBack, bringForward} from '../helper/order';
16
16
  import {groupSelection, ungroupSelection} from '../helper/group';
17
17
 
18
- import Formats from '../lib/format';
19
- import {isBitmap} from '../lib/format';
18
+ import Formats, {isBitmap} from '../lib/format';
20
19
  import bindAll from 'lodash.bindall';
21
20
 
22
21
  class FixedTools extends React.Component {
@@ -8,12 +8,11 @@ import ColorStyleProptype from '../lib/color-style-proptype';
8
8
  import {clearSelection} from '../helper/selection';
9
9
  import {endPointHit, touching} from '../helper/snapping';
10
10
  import {drawHitPoint, removeHitPoint} from '../helper/guides';
11
- import {styleShape} from '../helper/style-path';
11
+ import {styleShape, MIXED} from '../helper/style-path';
12
12
  import {changeStrokeColor, clearStrokeGradient} from '../reducers/stroke-style';
13
13
  import {changeStrokeWidth} from '../reducers/stroke-width';
14
14
  import {changeMode} from '../reducers/modes';
15
15
  import {clearSelectedItems} from '../reducers/selected-items';
16
- import {MIXED} from '../helper/style-path';
17
16
  import {snapDeltaToAngle} from '../helper/math';
18
17
 
19
18
  import LineModeComponent from '../components/line-mode/line-mode.jsx';
@@ -18,8 +18,7 @@ import {
18
18
  import {HANDLE_RATIO, ensureClockwise} from '../helper/math';
19
19
  import {getRaster} from '../helper/layer';
20
20
  import {flipBitmapHorizontal, flipBitmapVertical, selectAllBitmap} from '../helper/bitmap';
21
- import {isBitmap} from '../lib/format';
22
- import Formats from '../lib/format';
21
+ import Formats, {isBitmap} from '../lib/format';
23
22
  import Modes from '../lib/modes';
24
23
 
25
24
  class ModeTools extends React.Component {
@@ -23,10 +23,8 @@ import {convertToBitmap, convertToVector} from '../helper/bitmap';
23
23
  import {resetZoom, zoomOnSelection, OUTERMOST_ZOOM_LEVEL} from '../helper/view';
24
24
  import EyeDropperTool from '../helper/tools/eye-dropper';
25
25
 
26
- import Modes from '../lib/modes';
27
- import {BitmapModes, VectorModes} from '../lib/modes';
28
- import Formats from '../lib/format';
29
- import {isBitmap, isVector} from '../lib/format';
26
+ import Modes, {BitmapModes, VectorModes} from '../lib/modes';
27
+ import Formats, {isBitmap, isVector} from '../lib/format';
30
28
  import bindAll from 'lodash.bindall';
31
29
 
32
30
  /**
@@ -129,7 +127,7 @@ class PaintEditor extends React.Component {
129
127
  if (this.props.format === Formats.VECTOR && isBitmap(prevProps.format)) {
130
128
  convertToVector(this.props.clearSelectedItems, this.props.onUpdateImage);
131
129
  } else if (isVector(prevProps.format) && this.props.format === Formats.BITMAP) {
132
- convertToBitmap(this.props.clearSelectedItems, this.props.onUpdateImage);
130
+ convertToBitmap(this.props.clearSelectedItems, this.props.onUpdateImage, this.props.fontInlineFn);
133
131
  }
134
132
  }
135
133
  componentWillUnmount () {
@@ -344,6 +342,7 @@ PaintEditor.propTypes = {
344
342
  changeMode: PropTypes.func.isRequired,
345
343
  clearSelectedItems: PropTypes.func.isRequired,
346
344
  format: PropTypes.oneOf(Object.keys(Formats)), // Internal, up-to-date data format
345
+ fontInlineFn: PropTypes.func,
347
346
  handleSwitchToBitmap: PropTypes.func.isRequired,
348
347
  handleSwitchToVector: PropTypes.func.isRequired,
349
348
  image: PropTypes.oneOfType([
@@ -11,8 +11,10 @@ import {undoSnapshot, clearUndoState} from '../reducers/undo';
11
11
  import {isGroup, ungroupItems} from '../helper/group';
12
12
  import {clearRaster, convertBackgroundGuideLayer, getRaster, setupLayers} from '../helper/layer';
13
13
  import {clearSelectedItems} from '../reducers/selected-items';
14
- import {ART_BOARD_WIDTH, ART_BOARD_HEIGHT, CENTER, MAX_WORKSPACE_BOUNDS} from '../helper/view';
15
- import {clampViewBounds, resetZoom, setWorkspaceBounds, zoomToFit, resizeCrosshair} from '../helper/view';
14
+ import {
15
+ ART_BOARD_WIDTH, ART_BOARD_HEIGHT, CENTER, MAX_WORKSPACE_BOUNDS,
16
+ clampViewBounds, resetZoom, setWorkspaceBounds, zoomToFit, resizeCrosshair
17
+ } from '../helper/view';
16
18
  import {ensureClockwise, scaleWithStrokes} from '../helper/math';
17
19
  import {clearHoveredItem} from '../reducers/hover';
18
20
  import {clearPasteOffset} from '../reducers/clipboard';
@@ -195,6 +197,7 @@ class PaperCanvas extends React.Component {
195
197
  const paperCanvas = this;
196
198
  // Pre-process SVG to prevent parsing errors (discussion from #213)
197
199
  // 1. Remove svg: namespace on elements.
200
+ // TODO: remove
198
201
  svg = svg.split(/<\s*svg:/).join('<');
199
202
  svg = svg.split(/<\/\s*svg:/).join('</');
200
203
  // 2. Add root svg namespace if it does not exist.
@@ -2,9 +2,8 @@ import {connect} from 'react-redux';
2
2
  import {defineMessages} from 'react-intl';
3
3
 
4
4
  import {changeColorIndex} from '../reducers/color-index';
5
- import {changeStrokeColor, changeStrokeColor2} from '../reducers/stroke-style';
5
+ import {changeStrokeColor, changeStrokeColor2, changeStrokeGradientType} from '../reducers/stroke-style';
6
6
  import {changeStrokeWidth} from '../reducers/stroke-width';
7
- import {changeStrokeGradientType} from '../reducers/stroke-style';
8
7
  import {openStrokeColor, closeStrokeColor} from '../reducers/modals';
9
8
  import {getSelectedLeafItems} from '../helper/selection';
10
9
  import {setSelectedItems} from '../reducers/selected-items';
@@ -7,12 +7,12 @@ import {changeStrokeColor, changeStrokeColor2, changeStrokeGradientType} from '.
7
7
  import {changeStrokeWidth} from '../reducers/stroke-width';
8
8
  import StrokeWidthIndicatorComponent from '../components/stroke-width-indicator.jsx';
9
9
  import {getSelectedLeafItems} from '../helper/selection';
10
- import {applyColorToSelection, applyStrokeWidthToSelection, getColorsFromSelection, MIXED}
11
- from '../helper/style-path';
10
+ import {
11
+ applyColorToSelection, applyStrokeWidthToSelection, getColorsFromSelection, MIXED
12
+ } from '../helper/style-path';
12
13
  import GradientTypes from '../lib/gradient-types';
13
14
  import Modes from '../lib/modes';
14
- import Formats from '../lib/format';
15
- import {isBitmap} from '../lib/format';
15
+ import Formats, {isBitmap} from '../lib/format';
16
16
 
17
17
  class StrokeWidthIndicator extends React.Component {
18
18
  constructor (props) {
@@ -1,7 +1,6 @@
1
1
  import paper from '@scratch/paper';
2
- import {getRaster} from '../layer';
2
+ import {getRaster, getGuideLayer} from '../layer';
3
3
  import {forEachLinePoint, getBrushMark} from '../bitmap';
4
- import {getGuideLayer} from '../layer';
5
4
 
6
5
  /**
7
6
  * Tool for drawing with the bitmap brush and eraser
@@ -1,7 +1,6 @@
1
1
  import paper from '@scratch/paper';
2
- import {getRaster} from '../layer';
2
+ import {getRaster, createCanvas, getGuideLayer} from '../layer';
3
3
  import {forEachLinePoint, getBrushMark} from '../bitmap';
4
- import {createCanvas, getGuideLayer} from '../layer';
5
4
  import {ART_BOARD_WIDTH, ART_BOARD_HEIGHT} from '../view';
6
5
 
7
6
  /**
@@ -3,8 +3,8 @@ import {createCanvas, clearRaster, getRaster, hideGuideLayers, showGuideLayers}
3
3
  import {getGuideColor} from './guides';
4
4
  import {clearSelection} from './selection';
5
5
  import {ART_BOARD_WIDTH, ART_BOARD_HEIGHT, CENTER, MAX_WORKSPACE_BOUNDS} from './view';
6
- import {inlineSvgFonts} from 'scratch-svg-renderer';
7
6
  import Formats from '../lib/format';
7
+ import log from '../log/log';
8
8
 
9
9
  const forEachLinePoint = function (point1, point2, callback) {
10
10
  // Bresenham line algorithm
@@ -404,7 +404,7 @@ const getTrimmedRaster = function (shouldInsert) {
404
404
  return trimmedRaster;
405
405
  };
406
406
 
407
- const convertToBitmap = function (clearSelectedItems, onUpdateImage) {
407
+ const convertToBitmap = function (clearSelectedItems, onUpdateImage, optFontInlineFn) {
408
408
  // @todo if the active layer contains only rasters, drawing them directly to the raster layer
409
409
  // would be more efficient.
410
410
 
@@ -424,7 +424,11 @@ const convertToBitmap = function (clearSelectedItems, onUpdateImage) {
424
424
  svg.setAttribute('shape-rendering', 'crispEdges');
425
425
 
426
426
  let svgString = (new XMLSerializer()).serializeToString(svg);
427
- svgString = inlineSvgFonts(svgString);
427
+ if (optFontInlineFn) {
428
+ svgString = optFontInlineFn(svgString);
429
+ } else {
430
+ log.error('Fonts may be converted to bitmap incorrectly if fontInlineFn prop is not set on PaintEditor.');
431
+ }
428
432
 
429
433
  // Put anti-aliased SVG into image, and dump image back into canvas
430
434
  const img = new Image();
@@ -1,12 +1,12 @@
1
1
  import paper from '@scratch/paper';
2
- import Modes from '../../lib/modes';
3
- import {BitmapModes} from '../../lib/modes';
2
+ import Modes, {BitmapModes} from '../../lib/modes';
4
3
  import {isGroup} from '../group';
5
4
  import {isCompoundPathItem, getRootItem} from '../item';
6
5
  import {checkPointsClose, snapDeltaToAngle} from '../math';
7
6
  import {getActionBounds, CENTER} from '../view';
8
- import {clearSelection, cloneSelection, getSelectedLeafItems, getSelectedRootItems, setItemSelection}
9
- from '../selection';
7
+ import {
8
+ clearSelection, cloneSelection, getSelectedLeafItems, getSelectedRootItems, setItemSelection
9
+ } from '../selection';
10
10
  import {getDragCrosshairLayer, CROSSHAIR_FULL_OPACITY} from '../layer';
11
11
 
12
12
  /** Snap to align selection center to rotation center within this distance */
@@ -128,7 +128,7 @@ class MoveTool {
128
128
 
129
129
  point.x = Math.max(actionBounds.left, Math.min(point.x, actionBounds.right));
130
130
  point.y = Math.max(actionBounds.top, Math.min(point.y, actionBounds.bottom));
131
-
131
+
132
132
  const dragVector = point.subtract(event.downPoint);
133
133
  let snapVector;
134
134
 
@@ -168,7 +168,7 @@ class MoveTool {
168
168
  bounds = item.bounds;
169
169
  }
170
170
  }
171
-
171
+
172
172
  if (this.firstDrag) {
173
173
  // Show the center crosshair above the selected item while dragging.
174
174
  getDragCrosshairLayer().visible = true;
@@ -1,8 +1,7 @@
1
1
  import paper from '@scratch/paper';
2
- import {getSelectedLeafItems} from './selection';
2
+ import {getSelectedLeafItems, getItems} from './selection';
3
3
  import {isPointTextItem} from './item';
4
4
  import {isGroup} from './group';
5
- import {getItems} from './selection';
6
5
  import GradientTypes from '../lib/gradient-types';
7
6
  import {DEFAULT_COLOR} from '../reducers/fill-style';
8
7
  import {isCompoundPathChild} from '../helper/compound-path';
@@ -634,8 +633,7 @@ const styleShape = function (path, options) {
634
633
  );
635
634
  }
636
635
  }
637
-
638
- if (options.hasOwnProperty('strokeWidth')) path.strokeWidth = options.strokeWidth;
636
+ if (Object.prototype.hasOwnProperty.call(options, 'strokeWidth')) path.strokeWidth = options.strokeWidth;
639
637
  };
640
638
 
641
639
  export {
@@ -21,6 +21,7 @@ class FillTool extends paper.Tool {
21
21
 
22
22
  // We have to set these functions instead of just declaring them because
23
23
  // paper.js tools hook up the listeners in the setter functions.
24
+ this.onMouseDown = this.handleMouseDown;
24
25
  this.onMouseMove = this.handleMouseMove;
25
26
  this.onMouseUp = this.handleMouseUp;
26
27
 
@@ -91,7 +92,7 @@ class FillTool extends paper.Tool {
91
92
  setPrevHoveredItemId (prevHoveredItemId) {
92
93
  this.prevHoveredItemId = prevHoveredItemId;
93
94
  }
94
- handleMouseMove (event) {
95
+ updateFillPreview (event) {
95
96
  const hoveredItem = getHoveredItem(event, this.getHitOptions(), true /* subselect */);
96
97
  if ((!hoveredItem && this.prevHoveredItemId) || // There is no longer a hovered item
97
98
  (hoveredItem && !this.prevHoveredItemId) || // There is now a hovered item
@@ -152,6 +153,15 @@ class FillTool extends paper.Tool {
152
153
  this._setFillItemColor(this.fillColor, this.fillColor2, this.gradientType, event.point);
153
154
  }
154
155
  }
156
+ handleMouseDown (event) {
157
+ // on touch, the user might touch-and-hold to preview what the fill tool would do
158
+ // if they don't move their finger at all after the "mouse down" event
159
+ // then this might be our only chance to give them a good preview
160
+ this.updateFillPreview(event);
161
+ }
162
+ handleMouseMove (event) {
163
+ this.updateFillPreview(event);
164
+ }
155
165
  handleMouseUp (event) {
156
166
  if (event.event.button > 0) return; // only first mouse button
157
167
  if (this.fillItem) {
@@ -3,8 +3,7 @@
3
3
  import paper from '@scratch/paper';
4
4
  import {hideGuideLayers, showGuideLayers, getRaster} from '../helper/layer';
5
5
  import {getSelectedLeafItems} from '../helper/selection';
6
- import Formats from '../lib/format';
7
- import {isVector, isBitmap} from '../lib/format';
6
+ import Formats, {isVector, isBitmap} from '../lib/format';
8
7
  import log from '../log/log';
9
8
 
10
9
  /**
@@ -12,8 +12,7 @@ import {
12
12
  getSelectedRootItems
13
13
  } from '../helper/selection';
14
14
  import {getTrimmedRaster} from '../helper/bitmap';
15
- import {isBitmap} from '../lib/format';
16
- import Formats from '../lib/format';
15
+ import Formats, {isBitmap} from '../lib/format';
17
16
  import Modes from '../lib/modes';
18
17
 
19
18
  import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items';
@@ -13,8 +13,7 @@ import {groupSelection, shouldShowGroup, ungroupSelection, shouldShowUngroup} fr
13
13
  import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items';
14
14
  import {changeMode} from '../reducers/modes';
15
15
 
16
- import {isBitmap} from '../lib/format';
17
- import Formats from '../lib/format';
16
+ import Formats, {isBitmap} from '../lib/format';
18
17
  import Modes from '../lib/modes';
19
18
 
20
19
  const KeyboardShortcutsHOC = function (WrappedComponent) {