@pie-element/drawing-response 10.1.0 → 10.2.0-mui-update.0

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 (89) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/configure/CHANGELOG.md +66 -0
  3. package/configure/lib/__tests__/image-container.test.js +176 -0
  4. package/configure/lib/__tests__/index.test.js +53 -0
  5. package/configure/lib/__tests__/root.test.js +84 -0
  6. package/configure/lib/button.js +24 -48
  7. package/configure/lib/button.js.map +1 -1
  8. package/configure/lib/defaults.js +3 -4
  9. package/configure/lib/defaults.js.map +1 -1
  10. package/configure/lib/image-container.js +239 -328
  11. package/configure/lib/image-container.js.map +1 -1
  12. package/configure/lib/index.js +116 -183
  13. package/configure/lib/index.js.map +1 -1
  14. package/configure/lib/root.js +195 -261
  15. package/configure/lib/root.js.map +1 -1
  16. package/configure/package.json +9 -7
  17. package/configure/src/__tests__/index.test.js +10 -4
  18. package/configure/src/button.jsx +14 -24
  19. package/configure/src/image-container.jsx +73 -77
  20. package/configure/src/index.js +12 -2
  21. package/configure/src/root.jsx +24 -25
  22. package/controller/CHANGELOG.md +24 -0
  23. package/controller/lib/__tests__/index.test.js +177 -0
  24. package/controller/lib/defaults.js +3 -4
  25. package/controller/lib/defaults.js.map +1 -1
  26. package/controller/lib/index.js +40 -66
  27. package/controller/lib/index.js.map +1 -1
  28. package/controller/package.json +1 -1
  29. package/docs/demo/pie.manifest.json +11 -0
  30. package/lib/__tests__/drawing-index-test.js +36 -0
  31. package/lib/drawing-response/__tests__/container.test.js +66 -0
  32. package/lib/drawing-response/__tests__/drawable-helper.test.js +23 -0
  33. package/lib/drawing-response/__tests__/drawing-main.test.js +684 -0
  34. package/lib/drawing-response/__tests__/factory.test.js +15 -0
  35. package/lib/drawing-response/button.js +36 -61
  36. package/lib/drawing-response/button.js.map +1 -1
  37. package/lib/drawing-response/constants.js +3 -4
  38. package/lib/drawing-response/constants.js.map +1 -1
  39. package/lib/drawing-response/container.js +271 -352
  40. package/lib/drawing-response/container.js.map +1 -1
  41. package/lib/drawing-response/drawable-circle.js +66 -105
  42. package/lib/drawing-response/drawable-circle.js.map +1 -1
  43. package/lib/drawing-response/drawable-eraser.js +51 -87
  44. package/lib/drawing-response/drawable-eraser.js.map +1 -1
  45. package/lib/drawing-response/drawable-free-path.js +57 -98
  46. package/lib/drawing-response/drawable-free-path.js.map +1 -1
  47. package/lib/drawing-response/drawable-helper.js +17 -29
  48. package/lib/drawing-response/drawable-helper.js.map +1 -1
  49. package/lib/drawing-response/drawable-image.js +31 -50
  50. package/lib/drawing-response/drawable-image.js.map +1 -1
  51. package/lib/drawing-response/drawable-line.js +61 -100
  52. package/lib/drawing-response/drawable-line.js.map +1 -1
  53. package/lib/drawing-response/drawable-main.js +274 -346
  54. package/lib/drawing-response/drawable-main.js.map +1 -1
  55. package/lib/drawing-response/drawable-palette.js +124 -167
  56. package/lib/drawing-response/drawable-palette.js.map +1 -1
  57. package/lib/drawing-response/drawable-rectangle.js +66 -105
  58. package/lib/drawing-response/drawable-rectangle.js.map +1 -1
  59. package/lib/drawing-response/drawable-text.js +202 -314
  60. package/lib/drawing-response/drawable-text.js.map +1 -1
  61. package/lib/drawing-response/drawable-transformer.js +37 -80
  62. package/lib/drawing-response/drawable-transformer.js.map +1 -1
  63. package/lib/drawing-response/factory.js +7 -20
  64. package/lib/drawing-response/factory.js.map +1 -1
  65. package/lib/drawing-response/icon.js +9 -25
  66. package/lib/drawing-response/icon.js.map +1 -1
  67. package/lib/drawing-response/index.js +75 -117
  68. package/lib/drawing-response/index.js.map +1 -1
  69. package/lib/index.js +52 -103
  70. package/lib/index.js.map +1 -1
  71. package/package.json +13 -11
  72. package/src/drawing-response/button.jsx +23 -34
  73. package/src/drawing-response/container.jsx +39 -40
  74. package/src/drawing-response/drawable-image.jsx +17 -20
  75. package/src/drawing-response/drawable-main.jsx +67 -60
  76. package/src/drawing-response/drawable-palette.jsx +48 -54
  77. package/src/drawing-response/drawable-text.jsx +26 -38
  78. package/src/drawing-response/index.jsx +21 -20
  79. package/src/index.js +17 -2
  80. package/LICENSE.md +0 -5
  81. package/configure/node_modules/debug/CHANGELOG.md +0 -395
  82. package/configure/node_modules/debug/LICENSE +0 -19
  83. package/configure/node_modules/debug/README.md +0 -437
  84. package/configure/node_modules/debug/node.js +0 -1
  85. package/configure/node_modules/debug/package.json +0 -51
  86. package/configure/node_modules/debug/src/browser.js +0 -180
  87. package/configure/node_modules/debug/src/common.js +0 -249
  88. package/configure/node_modules/debug/src/index.js +0 -12
  89. package/configure/node_modules/debug/src/node.js +0 -177
@@ -1,22 +1,24 @@
1
1
  {
2
2
  "name": "@pie-element/drawing-response-configure",
3
3
  "private": true,
4
- "version": "9.1.0",
4
+ "version": "9.2.0",
5
5
  "description": "",
6
6
  "main": "lib/index.js",
7
7
  "module": "src/index.js",
8
8
  "author": "",
9
9
  "dependencies": {
10
- "@material-ui/core": "^3.9.2",
10
+ "@emotion/react": "^11.14.0",
11
+ "@emotion/style": "^0.8.0",
12
+ "@mui/icons-material": "^7.3.4",
13
+ "@mui/material": "^7.3.4",
11
14
  "@pie-framework/pie-configure-events": "^1.3.0",
12
- "@pie-lib/config-ui": "^11.25.0",
13
- "@pie-lib/editable-html": "^11.17.0",
14
- "classnames": "^2.2.6",
15
+ "@pie-lib/config-ui": "11.41.0-mui-update.0",
16
+ "@pie-lib/editable-html": "11.33.0-mui-update.0",
15
17
  "debug": "^3.1.0",
16
18
  "lodash": "^4.17.15",
17
19
  "prop-types": "^15.7.2",
18
- "react": "^16.8.6",
19
- "react-dom": "^16.8.6"
20
+ "react": "18.2.0",
21
+ "react-dom": "18.2.0"
20
22
  },
21
23
  "license": "ISC"
22
24
  }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import ReactDOM from 'react-dom';
2
+ import { createRoot } from 'react-dom/client';
3
3
 
4
4
  jest.mock('@pie-lib/config-ui', () => ({
5
5
  choiceUtils: {
@@ -22,8 +22,13 @@ const model = () => ({
22
22
  },
23
23
  });
24
24
 
25
- jest.mock('react-dom', () => ({
26
- render: jest.fn(),
25
+ const mockRender = jest.fn();
26
+ const mockUnmount = jest.fn();
27
+ jest.mock('react-dom/client', () => ({
28
+ createRoot: jest.fn(() => ({
29
+ render: mockRender,
30
+ unmount: mockUnmount,
31
+ })),
27
32
  }));
28
33
 
29
34
  describe('index', () => {
@@ -44,7 +49,8 @@ describe('index', () => {
44
49
 
45
50
  describe('set model', () => {
46
51
  it('calls ReactDOM.render', () => {
47
- expect(ReactDOM.render).toHaveBeenCalled();
52
+ expect(createRoot).toHaveBeenCalled();
53
+ expect(mockRender).toHaveBeenCalled();
48
54
  });
49
55
  });
50
56
  });
@@ -1,43 +1,33 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { withStyles } from '@material-ui/core/styles';
4
- import classNames from 'classnames';
5
- import Button from '@material-ui/core/Button';
3
+ import { styled } from '@mui/material/styles';
4
+ import Button from '@mui/material/Button';
6
5
 
7
- const RawButton = ({ classes, className, label, onClick, disabled }) => (
8
- <Button
6
+ const StyledButton = styled(Button)({
7
+ marginLeft: 8,
8
+ });
9
+
10
+ const CustomButton = ({ label, onClick, disabled }) => (
11
+ <StyledButton
9
12
  onClick={onClick}
10
13
  disabled={disabled}
11
- className={classNames(classes.addButton, className)}
12
14
  size="small"
13
- variant="contained"
14
- color="default"
15
- >
15
+ variant="contained">
16
16
  {label}
17
- </Button>
17
+ </StyledButton>
18
18
  );
19
19
 
20
- RawButton.propTypes = {
21
- classes: PropTypes.object.isRequired,
22
- className: PropTypes.string,
20
+ CustomButton.propTypes = {
23
21
  disabled: PropTypes.bool,
24
22
  label: PropTypes.string,
25
23
  onClick: PropTypes.func,
26
24
  };
27
25
 
28
- RawButton.defaultProps = {
26
+ CustomButton.defaultProps = {
29
27
  className: '',
30
28
  disabled: false,
31
29
  label: 'Add',
32
- onClick: () => {},
30
+ onClick: () => { },
33
31
  };
34
32
 
35
- const styles = () => ({
36
- addButton: {
37
- marginLeft: 8,
38
- },
39
- });
40
-
41
- const ButtonStyled = withStyles(styles)(RawButton);
42
-
43
- export default ButtonStyled;
33
+ export default CustomButton;
@@ -1,6 +1,6 @@
1
1
  import React, { Component } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { withStyles } from '@material-ui/core/styles';
3
+ import { styled } from '@mui/material/styles';
4
4
 
5
5
  import Button from './button';
6
6
 
@@ -9,6 +9,61 @@ const isImage = (file) => {
9
9
  return file.type.match(imageType);
10
10
  };
11
11
 
12
+ const BaseContainer = styled('div')(({ theme }) => ({
13
+ marginTop: theme.spacing(1),
14
+ }));
15
+
16
+ const Box = styled('div')(({ active }) => ({
17
+ border: active ? '1px solid #0032C2' : '1px solid #E0E1E6',
18
+ borderRadius: '5px',
19
+ }));
20
+
21
+ const CenteredDiv = styled('div')({
22
+ alignItems: 'center',
23
+ display: 'flex',
24
+ flexDirection: 'column',
25
+ justifyContent: 'center',
26
+ });
27
+
28
+ const DrawableHeight = styled('div')({
29
+ minHeight: 350,
30
+ });
31
+
32
+ const Image = styled('img')({
33
+ alignItems: 'center',
34
+ display: 'flex',
35
+ justifyContent: 'center',
36
+ });
37
+
38
+ const StyledImageContainer = styled('div')({
39
+ position: 'relative',
40
+ width: 'fit-content',
41
+ });
42
+
43
+ const ResizeHandle = styled('div')({
44
+ borderBottom: '1px solid #727272',
45
+ borderRight: '1px solid #727272',
46
+ bottom: '-10px',
47
+ cursor: 'se-resize',
48
+ height: '10px',
49
+ position: 'absolute',
50
+ right: '-10px',
51
+ width: '10px',
52
+ });
53
+
54
+ const HiddenInput = styled('input')({
55
+ display: 'none',
56
+ });
57
+
58
+ const Toolbar = styled('div')({
59
+ backgroundColor: '#ECEDF1',
60
+ borderBottom: '1px solid #E0E1E6',
61
+ borderTopLeftRadius: '5px',
62
+ borderTopRightRadius: '5px',
63
+ display: 'flex',
64
+ padding: '12px 8px',
65
+ });
66
+
12
67
  export class ImageContainer extends Component {
13
68
 
14
69
  static propTypes = {
@@ -176,14 +231,11 @@ export class ImageContainer extends Component {
176
231
  };
177
232
 
178
233
  renderUploadControl(label) {
179
- const { classes } = this.props;
180
-
181
234
  return (
182
235
  <div>
183
236
  <Button label={label} onClick={this.handleInputClick} />
184
- <input
237
+ <HiddenInput
185
238
  accept="image/*"
186
- className={classes.input}
187
239
  onChange={this.handleUploadImage}
188
240
  ref={(ref) => {
189
241
  this.input = ref;
@@ -195,13 +247,13 @@ export class ImageContainer extends Component {
195
247
  }
196
248
 
197
249
  render() {
198
- const { classes, imageUrl, imageDimensions } = this.props;
250
+ const { imageUrl, imageDimensions } = this.props;
199
251
  const { dropzoneActive, dragEnabled, maxImageHeight, maxImageWidth } = this.state;
200
252
 
201
253
  return (
202
- <div className={classes.base}>
203
- <div
204
- className={`${classes.box} ${dropzoneActive ? classes.boxActive : ''}`}
254
+ <BaseContainer>
255
+ <Box
256
+ active={dropzoneActive}
205
257
  {...(dragEnabled
206
258
  ? {
207
259
  onDragExit: this.handleOnDragExit,
@@ -211,18 +263,16 @@ export class ImageContainer extends Component {
211
263
  }
212
264
  : {})}
213
265
  >
214
- <div className={classes.toolbar}>{this.renderUploadControl(imageUrl ? 'Replace Image' : 'Upload Image')}</div>
266
+ <Toolbar>{this.renderUploadControl(imageUrl ? 'Replace Image' : 'Upload Image')}</Toolbar>
215
267
 
216
- <div
268
+ <DrawableHeight
217
269
  ref={(ref) => {
218
270
  this.imageSection = ref;
219
271
  }}
220
- className={classes.drawableHeight}
221
272
  >
222
273
  {imageUrl ? (
223
- <div className={classes.imageContainer}>
224
- <img
225
- className={classes.image}
274
+ <StyledImageContainer>
275
+ <Image
226
276
  height="auto"
227
277
  onLoad={this.handleOnImageLoad}
228
278
  ref={(ref) => {
@@ -236,85 +286,31 @@ export class ImageContainer extends Component {
236
286
  }}
237
287
  alt=""
238
288
  />
239
- <div
289
+ <ResizeHandle
240
290
  ref={(ref) => {
241
291
  this.resize = ref;
242
292
  }}
243
- className={classes.resize}
244
293
  />
245
- </div>
294
+ </StyledImageContainer>
246
295
  ) : (
247
- <div className={`${classes.drawableHeight} ${classes.centered}`}>
296
+ <DrawableHeight as={CenteredDiv}>
248
297
  <label>Drag and drop or upload image from computer</label>
249
298
  <br />
250
299
  {this.renderUploadControl('Upload Image')}
251
- </div>
300
+ </DrawableHeight>
252
301
  )}
253
- </div>
254
- </div>
255
- </div>
302
+ </DrawableHeight>
303
+ </Box>
304
+ </BaseContainer>
256
305
  );
257
306
  }
258
307
  }
259
308
 
260
- const styles = (theme) => ({
261
- base: {
262
- marginTop: theme.spacing.unit,
263
- },
264
- box: {
265
- border: '1px solid #E0E1E6',
266
- borderRadius: '5px',
267
- },
268
- boxActive: {
269
- border: '1px solid #0032C2',
270
- },
271
- centered: {
272
- alignItems: 'center',
273
- display: 'flex',
274
- flexDirection: 'column',
275
- justifyContent: 'center',
276
- },
277
- drawableHeight: {
278
- minHeight: 350,
279
- },
280
- image: {
281
- alignItems: 'center',
282
- display: 'flex',
283
- justifyContent: 'center',
284
- },
285
- imageContainer: {
286
- position: 'relative',
287
- width: 'fit-content',
288
- },
289
- resize: {
290
- borderBottom: '1px solid #727272',
291
- borderRight: '1px solid #727272',
292
- bottom: '-10px',
293
- cursor: 'se-resize',
294
- height: '10px',
295
- position: 'absolute',
296
- right: '-10px',
297
- width: '10px',
298
- },
299
- input: {
300
- display: 'none',
301
- },
302
- toolbar: {
303
- backgroundColor: '#ECEDF1',
304
- borderBottom: '1px solid #E0E1E6',
305
- borderTopLeftRadius: '5px',
306
- borderTopRightRadius: '5px',
307
- display: 'flex',
308
- padding: '12px 8px',
309
- },
310
- });
311
-
312
309
  ImageContainer.propTypes = {
313
- classes: PropTypes.object.isRequired,
314
310
  imageUrl: PropTypes.string.isRequired,
315
311
  onImageUpload: PropTypes.func.isRequired,
316
312
  onUpdateImageDimension: PropTypes.func.isRequired,
317
313
  insertImage: PropTypes.func,
318
314
  };
319
315
 
320
- export default withStyles(styles)(ImageContainer);
316
+ export default ImageContainer;
@@ -7,7 +7,7 @@ import {
7
7
  } from '@pie-framework/pie-configure-events';
8
8
 
9
9
  import React from 'react';
10
- import ReactDOM from 'react-dom';
10
+ import { createRoot } from 'react-dom/client';
11
11
  import debug from 'debug';
12
12
 
13
13
  import Root from './root';
@@ -33,6 +33,7 @@ export default class DrawableResponseConfigure extends HTMLElement {
33
33
 
34
34
  constructor() {
35
35
  super();
36
+ this._root = null;
36
37
  this._configuration = sensibleDefaults.configuration;
37
38
 
38
39
  // if configuration.withRubric.forceEnabled is true, then we
@@ -152,6 +153,15 @@ export default class DrawableResponseConfigure extends HTMLElement {
152
153
  delete: this.onDeleteSound.bind(this),
153
154
  },
154
155
  });
155
- ReactDOM.render(element, this);
156
+ if (!this._root) {
157
+ this._root = createRoot(this);
158
+ }
159
+ this._root.render(element);
160
+ }
161
+
162
+ disconnectedCallback() {
163
+ if (this._root) {
164
+ this._root.unmount();
165
+ }
156
166
  }
157
167
  }
@@ -2,14 +2,27 @@ import React from 'react';
2
2
  import { settings, layout, InputContainer } from '@pie-lib/config-ui';
3
3
  import PropTypes from 'prop-types';
4
4
  import EditableHtml from '@pie-lib/editable-html';
5
- import Typography from '@material-ui/core/Typography';
6
- import { withStyles } from '@material-ui/core/styles';
5
+ import Typography from '@mui/material/Typography';
6
+ import { styled } from '@mui/material/styles';
7
7
 
8
8
  import ImageContainer from './image-container';
9
9
  import cloneDeep from 'lodash/cloneDeep';
10
10
 
11
11
  const { Panel, toggle, dropdown } = settings;
12
12
 
13
+ const PromptHolder = styled(InputContainer)(({ theme }) => ({
14
+ paddingTop: theme.spacing(1),
15
+ marginTop: theme.spacing(2),
16
+ marginBottom: theme.spacing(1),
17
+ width: '100%',
18
+ }));
19
+
20
+ const ErrorText = styled('div')(({ theme }) => ({
21
+ fontSize: theme.typography.fontSize - 2,
22
+ color: theme.palette.error.main,
23
+ paddingTop: theme.spacing(1),
24
+ }));
25
+
13
26
  export class Root extends React.Component {
14
27
  onPromptChanged = (prompt) => {
15
28
  const { model, onModelChanged } = this.props;
@@ -37,7 +50,7 @@ export class Root extends React.Component {
37
50
  };
38
51
 
39
52
  render() {
40
- const { classes, configuration, imageSupport, model, onConfigurationChanged, onModelChanged, uploadSoundSupport } =
53
+ const { configuration, imageSupport, model, onConfigurationChanged, onModelChanged, uploadSoundSupport } =
41
54
  this.props;
42
55
  const {
43
56
  baseInputConfiguration = {},
@@ -109,7 +122,7 @@ export class Root extends React.Component {
109
122
  }
110
123
  >
111
124
  {teacherInstructionsEnabled && (
112
- <InputContainer label={teacherInstructions.label} className={classes.promptHolder}>
125
+ <PromptHolder label={teacherInstructions.label}>
113
126
  <EditableHtml
114
127
  markup={model.teacherInstructions || ''}
115
128
  onChange={this.onTeacherInstructionsChanged}
@@ -125,12 +138,12 @@ export class Root extends React.Component {
125
138
  languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
126
139
  mathMlOptions={mathMlOptions}
127
140
  />
128
- {teacherInstructionsError && <div className={classes.errorText}>{teacherInstructionsError}</div>}
129
- </InputContainer>
141
+ {teacherInstructionsError && <ErrorText>{teacherInstructionsError}</ErrorText>}
142
+ </PromptHolder>
130
143
  )}
131
144
 
132
145
  {promptEnabled && (
133
- <InputContainer label="Item Stem" className={classes.promptHolder}>
146
+ <PromptHolder label="Item Stem">
134
147
  <EditableHtml
135
148
  markup={model.prompt}
136
149
  onChange={this.onPromptChanged}
@@ -145,13 +158,13 @@ export class Root extends React.Component {
145
158
  languageCharactersProps={[{ language: 'spanish' }, { language: 'special' }]}
146
159
  mathMlOptions={mathMlOptions}
147
160
  />
148
- {promptError && <div className={classes.errorText}>{promptError}</div>}
149
- </InputContainer>
161
+ {promptError && <ErrorText>{promptError}</ErrorText>}
162
+ </PromptHolder>
150
163
  )}
151
164
 
152
165
  {backgroundImageEnabled && (
153
166
  <React.Fragment>
154
- <Typography variant="subheading">Define Background Image</Typography>
167
+ <Typography variant="h6">Define Background Image</Typography>
155
168
 
156
169
  <ImageContainer
157
170
  imageUrl={model.imageUrl}
@@ -167,21 +180,7 @@ export class Root extends React.Component {
167
180
  }
168
181
  }
169
182
 
170
- const styles = (theme) => ({
171
- promptHolder: {
172
- paddingTop: theme.spacing.unit * 2,
173
- marginBottom: theme.spacing.unit * 2,
174
- width: '100%',
175
- },
176
- errorText: {
177
- fontSize: theme.typography.fontSize - 2,
178
- color: theme.palette.error.main,
179
- paddingTop: theme.spacing.unit,
180
- },
181
- });
182
-
183
183
  Root.propTypes = {
184
- classes: PropTypes.object.isRequired,
185
184
  configuration: PropTypes.object,
186
185
  model: PropTypes.object.isRequired,
187
186
  imageSupport: PropTypes.shape({
@@ -196,4 +195,4 @@ Root.propTypes = {
196
195
  onConfigurationChanged: PropTypes.func.isRequired,
197
196
  };
198
197
 
199
- export default withStyles(styles)(Root);
198
+ export default Root;
@@ -3,6 +3,30 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [4.2.1](https://github.com/pie-framework/pie-elements/compare/@pie-element/drawing-response-controller@4.1.1...@pie-element/drawing-response-controller@4.2.1) (2025-10-16)
7
+
8
+ **Note:** Version bump only for package @pie-element/drawing-response-controller
9
+
10
+
11
+
12
+
13
+
14
+ # [4.2.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/drawing-response-controller@4.1.1...@pie-element/drawing-response-controller@4.2.0) (2025-10-15)
15
+
16
+ **Note:** Version bump only for package @pie-element/drawing-response-controller
17
+
18
+
19
+
20
+
21
+
22
+ ## [4.1.1](https://github.com/pie-framework/pie-elements/compare/@pie-element/drawing-response-controller@4.0.1...@pie-element/drawing-response-controller@4.1.1) (2025-10-10)
23
+
24
+ **Note:** Version bump only for package @pie-element/drawing-response-controller
25
+
26
+
27
+
28
+
29
+
6
30
  # [4.1.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/drawing-response-controller@4.0.0...@pie-element/drawing-response-controller@4.1.0) (2025-10-07)
7
31
 
8
32
  **Note:** Version bump only for package @pie-element/drawing-response-controller