@pie-lib/graphing 4.0.17 → 4.0.18
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.
- package/CHANGELOG.md +6 -0
- package/lib/mark-label.js +66 -21
- package/lib/mark-label.js.map +1 -1
- package/package.json +6 -6
- package/src/__tests__/graph.test.jsx +19 -0
- package/src/__tests__/mark-label.test.jsx +39 -8
- package/src/mark-label.jsx +63 -21
- package/src/tools/point/__tests__/component.test.jsx +17 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
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.0.18](https://github.com/pie-framework/pie-lib/compare/@pie-lib/graphing@4.0.17...@pie-lib/graphing@4.0.18) (2026-08-26)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **graphing:** hold the focus on a new label and save it on blur PIE-681 ([26c5f98](https://github.com/pie-framework/pie-lib/commit/26c5f9875b45f4495d76827633f28d82d93d8cb9))
|
|
11
|
+
|
|
6
12
|
## [4.0.17](https://github.com/pie-framework/pie-lib/compare/@pie-lib/graphing@4.0.16...@pie-lib/graphing@4.0.17) (2026-08-21)
|
|
7
13
|
|
|
8
14
|
### Bug Fixes
|
package/lib/mark-label.js
CHANGED
|
@@ -20,6 +20,11 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
20
20
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
21
21
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
22
22
|
var DEBOUNCE_DELAY = 500;
|
|
23
|
+
// A new label insists on the focus for this long: in the DNA env something moves the focus while the
|
|
24
|
+
// model save that creating the label triggered is handled, after the last render. Nothing typed yet
|
|
25
|
+
// is what tells that apart from the user leaving the label.
|
|
26
|
+
var INSIST_ON_FOCUS_FOR = 500;
|
|
27
|
+
var INSIST_AT = [0, 50, 120, 250, 400];
|
|
23
28
|
var StyledInputCorrect = (0, _styles.styled)('div')(function (_ref2) {
|
|
24
29
|
var theme = _ref2.theme;
|
|
25
30
|
return {
|
|
@@ -168,8 +173,7 @@ LabelInput.propTypes = {
|
|
|
168
173
|
onBlur: _propTypes["default"].func
|
|
169
174
|
};
|
|
170
175
|
var MarkLabel = exports.MarkLabel = function MarkLabel(props) {
|
|
171
|
-
// the
|
|
172
|
-
// once it has a size, the ref is what the focus is asserted on - it is never a render behind
|
|
176
|
+
// the state repositions the label once the input has a size, the ref is never a render behind
|
|
173
177
|
var inputNode = (0, _react.useRef)(null);
|
|
174
178
|
var _useState = (0, _react.useState)(null),
|
|
175
179
|
_useState2 = (0, _slicedToArray2["default"])(_useState, 2),
|
|
@@ -196,31 +200,48 @@ var MarkLabel = exports.MarkLabel = function MarkLabel(props) {
|
|
|
196
200
|
return !!inputNode.current && typeof document !== 'undefined' && document.activeElement === inputNode.current;
|
|
197
201
|
};
|
|
198
202
|
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
// because the tool that asked for the label can be remounted by the marks coming back from the
|
|
203
|
-
// host (async model save) before the input ever renders, and its autoFocus goes with it.
|
|
203
|
+
// an empty label with an enabled input is one the user just added: label mode has to be on and it
|
|
204
|
+
// always starts off. Read from the mark, not from autoFocus, because the tool that asked for the
|
|
205
|
+
// label can be remounted by the marks coming back from the host before the input renders.
|
|
204
206
|
var isNewLabel = (0, _react.useRef)(mark.label === '' && !disabled && !mark.disabled);
|
|
207
|
+
var insistUntil = (0, _react.useRef)(0);
|
|
208
|
+
var lastSaved = (0, _react.useRef)(mark.label);
|
|
209
|
+
var insisting = function insisting() {
|
|
210
|
+
return Date.now() < insistUntil.current && !(inputNode.current && inputNode.current.value);
|
|
211
|
+
};
|
|
205
212
|
var onChange = function onChange(e) {
|
|
206
213
|
return setLabel(e.target.value);
|
|
207
214
|
};
|
|
215
|
+
var saveLabel = function saveLabel(value) {
|
|
216
|
+
if (value === lastSaved.current) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
lastSaved.current = value;
|
|
220
|
+
props.onChange(value);
|
|
221
|
+
};
|
|
208
222
|
var handleBlur = (0, _react.useCallback)(function () {
|
|
223
|
+
// in the DNA env the focus is moved while the model is saved - not the user leaving the label
|
|
224
|
+
if (insisting()) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
209
227
|
isNewLabel.current = false;
|
|
210
228
|
if (label === '') {
|
|
211
229
|
props.onChange('');
|
|
230
|
+
} else if (label !== mark.label) {
|
|
231
|
+
// the debounce can still be pending, and once the focus is gone an echo of the model would
|
|
232
|
+
// overwrite what was typed before it fires
|
|
233
|
+
saveLabel(label);
|
|
212
234
|
}
|
|
213
235
|
|
|
214
236
|
// lets the tool know that this label is not being edited anymore, so it stops auto focusing it
|
|
215
237
|
if (props.onBlur) {
|
|
216
238
|
props.onBlur();
|
|
217
239
|
}
|
|
218
|
-
}, [label, props.onChange, props.onBlur]);
|
|
240
|
+
}, [label, mark.label, props.onChange, props.onBlur]);
|
|
219
241
|
var debouncedLabel = (0, _useDebounce.useDebounce)(label, DEBOUNCE_DELAY);
|
|
220
242
|
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
// (async) model save with an older label and that would overwrite the characters typed meanwhile.
|
|
243
|
+
// props to state, but not while focused: the mark can come back from an async model save with an
|
|
244
|
+
// older label and overwrite what was typed meanwhile
|
|
224
245
|
(0, _react.useEffect)(function () {
|
|
225
246
|
if (isFocused()) {
|
|
226
247
|
return;
|
|
@@ -231,21 +252,14 @@ var MarkLabel = exports.MarkLabel = function MarkLabel(props) {
|
|
|
231
252
|
// pick up the change to debouncedLabel and save it
|
|
232
253
|
(0, _react.useEffect)(function () {
|
|
233
254
|
if (typeof debouncedLabel === 'string' && debouncedLabel !== mark.label) {
|
|
234
|
-
|
|
255
|
+
saveLabel(debouncedLabel);
|
|
235
256
|
}
|
|
236
257
|
}, [debouncedLabel]);
|
|
237
|
-
|
|
238
|
-
// A label that has just been added has to be focused so that it can be typed into right away.
|
|
239
|
-
// This runs after every render on purpose - there is no reliable single moment to focus at:
|
|
240
|
-
// the input shows up whenever the mark comes back from the (async) model save, and a remount
|
|
241
|
-
// of the input (same save, replaced node) drops the focus without this component being told.
|
|
242
|
-
// Asserting the focus on every render is what makes it stick; it is a no-op once the input has
|
|
243
|
-
// it, so the caret the user placed is left alone.
|
|
244
|
-
(0, _react.useEffect)(function () {
|
|
258
|
+
var focusInput = function focusInput() {
|
|
245
259
|
var node = inputNode.current;
|
|
246
260
|
|
|
247
261
|
// node.disabled, not the disabled prop: a disabled input silently ignores focus()
|
|
248
|
-
if (!autoFocus && !isNewLabel.current || !node || node.disabled || isFocused()) {
|
|
262
|
+
if (!autoFocus && !isNewLabel.current && !insisting() || !node || node.disabled || isFocused()) {
|
|
249
263
|
return;
|
|
250
264
|
}
|
|
251
265
|
node.focus();
|
|
@@ -260,7 +274,32 @@ var MarkLabel = exports.MarkLabel = function MarkLabel(props) {
|
|
|
260
274
|
if (node.setSelectionRange) {
|
|
261
275
|
node.setSelectionRange(caret, caret);
|
|
262
276
|
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// after every render: the input can appear a render or more later (the mark comes back from an
|
|
280
|
+
// async model save) and a replaced node loses the focus without this component being told
|
|
281
|
+
(0, _react.useEffect)(function () {
|
|
282
|
+
return focusInput();
|
|
263
283
|
});
|
|
284
|
+
|
|
285
|
+
// and again on a timer, for the DNA env, where the focus is moved once the renders are over. The
|
|
286
|
+
// original code focused from a setTimeout, which is what let it survive that.
|
|
287
|
+
(0, _react.useEffect)(function () {
|
|
288
|
+
if (!autoFocus && !isNewLabel.current) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (!insistUntil.current) {
|
|
292
|
+
insistUntil.current = Date.now() + INSIST_ON_FOCUS_FOR;
|
|
293
|
+
}
|
|
294
|
+
var timers = INSIST_AT.map(function (delay) {
|
|
295
|
+
return setTimeout(focusInput, delay);
|
|
296
|
+
});
|
|
297
|
+
return function () {
|
|
298
|
+
return timers.forEach(function (t) {
|
|
299
|
+
return clearTimeout(t);
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
}, [autoFocus]);
|
|
264
303
|
var rect = input ? input.getBoundingClientRect() : {
|
|
265
304
|
width: 0,
|
|
266
305
|
height: 0
|
|
@@ -324,6 +363,12 @@ var MarkLabel = exports.MarkLabel = function MarkLabel(props) {
|
|
|
324
363
|
style: style
|
|
325
364
|
}, renderInput(studentInputStyle, label));
|
|
326
365
|
}
|
|
366
|
+
|
|
367
|
+
// an empty label that cannot be edited is just an empty box - the config draws the background
|
|
368
|
+
// marks into every correct answer graph too
|
|
369
|
+
if (disabledInput && !label) {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
327
372
|
return /*#__PURE__*/_react["default"].createElement("div", {
|
|
328
373
|
style: style
|
|
329
374
|
}, renderInput(getInputStyles(theme, disabled, mark.disabled), label));
|
package/lib/mark-label.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mark-label.js","names":["_react","_interopRequireWildcard","require","_propTypes","_interopRequireDefault","_styles","_reactInputAutosize","_useDebounce","_plot","_renderUi","_labelSvgIcon","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","_typeof","has","get","set","_t","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","ownKeys","keys","getOwnPropertySymbols","filter","enumerable","push","apply","_objectSpread","arguments","length","forEach","_defineProperty2","getOwnPropertyDescriptors","defineProperties","DEBOUNCE_DELAY","StyledInputCorrect","styled","_ref2","theme","padding","spacing","borderRadius","fontSize","backgroundColor","color","defaults","WHITE","CORRECT_WITH_ICON","border","concat","StyledInputIncorrect","_ref3","INCORRECT_WITH_ICON","StyledInputMissing","_ref4","MISSING_WITH_ICON","fontWeight","StyledIncorrect","getInputStyles","disabled","markDisabled","fontFamily","typography","PRIMARY_DARK","SECONDARY","WebkitOpacity","undefined","WebkitTextFillColor","getStudentInputStyles","position","exports","graphProps","mark","rect","width","height","scale","domain","range","shift","rightEdge","x","bottomEdge","y","h","max","v","min","coordinates","left","top","LabelInput","_ref5","_ref","externalInputRef","label","inputStyle","onChange","onBlur","createElement","inputRef","value","propTypes","PropTypes","func","string","bool","object","MarkLabel","props","inputNode","useRef","_useState","useState","_useState2","_slicedToArray2","input","setInput","useCallback","node","current","useTheme","autoFocus","_useState3","_useState4","setLabel","correctness","correctnesslabel","correctlabel","isFocused","document","activeElement","isNewLabel","target","handleBlur","debouncedLabel","useDebounce","useEffect","focus","caret","setSelectionRange","getBoundingClientRect","pos","leftTop","style","pointerEvents","display","alignItems","gap","secondLabelStyle","disabledInput","renderInput","labelValue","studentInputStyle","type","Fragment","marginLeft","types","GraphPropsType","_default"],"sources":["../src/mark-label.jsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport { styled, useTheme } from '@mui/material/styles';\nimport AutosizeInput from 'react-input-autosize';\nimport { useDebounce } from './use-debounce';\nimport { types } from '@pie-lib/plot';\nimport { color } from '@pie-lib/render-ui';\nimport SvgIcon from './label-svg-icon';\n\nconst DEBOUNCE_DELAY = 500;\n\nconst StyledInputCorrect = styled('div')(({ theme }) => ({\n float: 'right',\n padding: theme.spacing(0.5),\n borderRadius: '4px',\n fontSize: '10px',\n backgroundColor: color.defaults.WHITE,\n color: color.defaults.CORRECT_WITH_ICON,\n border: `solid 1px ${color.defaults.CORRECT_WITH_ICON}`,\n}));\n\nconst StyledInputIncorrect = styled('div')(({ theme }) => ({\n float: 'right',\n padding: theme.spacing(0.5),\n borderRadius: '4px',\n fontSize: '10px',\n backgroundColor: color.defaults.WHITE,\n color: color.defaults.INCORRECT_WITH_ICON,\n border: `solid 1px ${color.defaults.INCORRECT_WITH_ICON}`,\n}));\n\nconst StyledInputMissing = styled('div')(({ theme }) => ({\n float: 'right',\n padding: theme.spacing(0.5),\n borderRadius: '4px',\n fontSize: '10px',\n backgroundColor: color.defaults.WHITE,\n color: color.defaults.MISSING_WITH_ICON,\n border: `solid 1px ${color.defaults.MISSING_WITH_ICON}`,\n fontWeight: 'bold',\n}));\n\nconst StyledIncorrect = styled('div')(() => ({\n float: 'right',\n padding: 0,\n borderRadius: '4px',\n fontSize: '10px',\n backgroundColor: color.defaults.WHITE,\n color: color.defaults.INCORRECT_WITH_ICON,\n fontWeight: 'bold',\n}));\n\nconst getInputStyles = (theme, disabled, markDisabled) => ({\n float: 'right',\n padding: theme.spacing(0.5),\n fontFamily: theme.typography.fontFamily,\n fontSize: '10px',\n border: disabled\n ? `solid 1px ${color.defaults.PRIMARY_DARK}`\n : markDisabled\n ? `solid 1px ${color.disabled()}`\n : `solid 1px ${color.defaults.SECONDARY}`,\n borderRadius: '3px',\n color: markDisabled ? color.disabled() : color.defaults.PRIMARY_DARK,\n backgroundColor: color.defaults.WHITE,\n WebkitOpacity: disabled ? '1' : undefined,\n WebkitTextFillColor: markDisabled ? color.disabled() : undefined,\n});\n\nconst getStudentInputStyles = () => ({\n padding: '0',\n border: 'none',\n color: 'inherit',\n fontWeight: 'bold',\n});\n\nexport const position = (graphProps, mark, rect = { width: 0, height: 0 }) => {\n const { scale, domain, range } = graphProps;\n const shift = 5;\n\n const rightEdge = scale.x(mark.x) + rect.width + shift;\n const bottomEdge = scale.y(mark.y) + rect.height + shift;\n\n const h = rightEdge >= scale.x(domain.max) ? 'left' : 'right';\n const v = bottomEdge >= scale.y(range.min) ? 'top' : 'bottom';\n\n return `${v}-${h}`;\n};\n\nexport const coordinates = (graphProps, mark, rect = { width: 0, height: 0 }, position) => {\n const { scale } = graphProps;\n const shift = 5;\n\n switch (position) {\n case 'bottom-right':\n return { left: scale.x(mark.x) + shift, top: scale.y(mark.y) + shift };\n case 'bottom-left':\n return { left: scale.x(mark.x) - shift - rect.width, top: scale.y(mark.y) + shift };\n case 'top-left':\n return { left: scale.x(mark.x) - shift - rect.width, top: scale.y(mark.y) - shift - rect.height };\n case 'top-right':\n return { left: scale.x(mark.x) + shift, top: scale.y(mark.y) - shift - rect.height };\n default:\n return {};\n }\n};\n\nconst LabelInput = ({ _ref, externalInputRef, label, disabled, inputStyle, onChange, onBlur }) => (\n <AutosizeInput\n inputRef={(r) => {\n _ref(r);\n externalInputRef(r);\n }}\n disabled={disabled}\n inputStyle={inputStyle}\n value={label}\n onChange={onChange}\n onBlur={onBlur}\n />\n);\n\nLabelInput.propTypes = {\n _ref: PropTypes.func,\n externalInputRef: PropTypes.func,\n label: PropTypes.string,\n disabled: PropTypes.bool,\n inputStyle: PropTypes.object,\n onChange: PropTypes.func,\n onBlur: PropTypes.func,\n};\n\nexport const MarkLabel = (props) => {\n // the node is kept in a ref as well as in the state: the state is needed to reposition the label\n // once it has a size, the ref is what the focus is asserted on - it is never a render behind\n const inputNode = useRef(null);\n const [input, setInput] = useState(null);\n const _ref = useCallback((node) => {\n inputNode.current = node;\n setInput(node);\n }, []);\n const theme = useTheme();\n\n const { mark, graphProps, disabled, autoFocus, inputRef: externalInputRef } = props;\n\n const [label, setLabel] = useState(mark.label);\n const { correctness, correctnesslabel, correctlabel } = mark;\n\n const isFocused = () =>\n !!inputNode.current && typeof document !== 'undefined' && document.activeElement === inputNode.current;\n\n // A label that has just been added is empty and its input is enabled - label mode has to be on\n // for that to happen and it always starts off, so a mark that was loaded with an empty label\n // cannot grab the focus. This is read from the mark rather than taken from the autoFocus prop\n // because the tool that asked for the label can be remounted by the marks coming back from the\n // host (async model save) before the input ever renders, and its autoFocus goes with it.\n const isNewLabel = useRef(mark.label === '' && !disabled && !mark.disabled);\n\n const onChange = (e) => setLabel(e.target.value);\n\n const handleBlur = useCallback(() => {\n isNewLabel.current = false;\n\n if (label === '') {\n props.onChange('');\n }\n\n // lets the tool know that this label is not being edited anymore, so it stops auto focusing it\n if (props.onBlur) {\n props.onBlur();\n }\n }, [label, props.onChange, props.onBlur]);\n\n const debouncedLabel = useDebounce(label, DEBOUNCE_DELAY);\n\n // useState only sets the value once, to synch props to state need useEffect.\n // While this input has the focus we keep what the user typed: the mark can come back from an\n // (async) model save with an older label and that would overwrite the characters typed meanwhile.\n useEffect(() => {\n if (isFocused()) {\n return;\n }\n\n setLabel(mark.label);\n }, [mark.label]);\n\n // pick up the change to debouncedLabel and save it\n useEffect(() => {\n if (typeof debouncedLabel === 'string' && debouncedLabel !== mark.label) {\n props.onChange(debouncedLabel);\n }\n }, [debouncedLabel]);\n\n // A label that has just been added has to be focused so that it can be typed into right away.\n // This runs after every render on purpose - there is no reliable single moment to focus at:\n // the input shows up whenever the mark comes back from the (async) model save, and a remount\n // of the input (same save, replaced node) drops the focus without this component being told.\n // Asserting the focus on every render is what makes it stick; it is a no-op once the input has\n // it, so the caret the user placed is left alone.\n useEffect(() => {\n const node = inputNode.current;\n\n // node.disabled, not the disabled prop: a disabled input silently ignores focus()\n if ((!autoFocus && !isNewLabel.current) || !node || node.disabled || isFocused()) {\n return;\n }\n\n node.focus();\n\n // a new label is focused once, so it cannot fight over the focus with another one\n if (isFocused()) {\n isNewLabel.current = false;\n }\n\n // keep the caret at the end, otherwise typing continues in front of the existing label\n const caret = (node.value || '').length;\n\n if (node.setSelectionRange) {\n node.setSelectionRange(caret, caret);\n }\n });\n\n const rect = input ? input.getBoundingClientRect() : { width: 0, height: 0 };\n const pos = position(graphProps, mark, rect);\n const leftTop = coordinates(graphProps, mark, rect, pos);\n\n const style = {\n position: 'fixed',\n pointerEvents: 'auto',\n display: 'flex',\n alignItems: 'center',\n gap: '3px',\n ...leftTop,\n };\n\n const secondLabelStyle = {\n ...style,\n top: leftTop.top + 25,\n };\n\n const disabledInput = disabled || mark.disabled;\n\n const renderInput = (inputStyle, labelValue) => (\n <LabelInput\n _ref={_ref}\n externalInputRef={externalInputRef}\n label={labelValue}\n disabled={disabledInput}\n inputStyle={inputStyle}\n onChange={onChange}\n onBlur={handleBlur}\n />\n );\n\n const studentInputStyle = getStudentInputStyles();\n\n if (correctness === 'correct' && correctnesslabel === 'correct' && correctlabel) {\n return (\n <StyledInputCorrect style={style}>\n <SvgIcon type=\"correct\" />\n {renderInput(studentInputStyle, correctlabel)}\n </StyledInputCorrect>\n );\n }\n\n if (correctness === 'correct' && correctnesslabel === 'correct' && !correctlabel) {\n return null;\n }\n\n if (correctness === 'correct' && correctnesslabel === 'incorrect') {\n return (\n <>\n <StyledInputIncorrect style={style}>\n <SvgIcon type=\"incorrect\" />\n {label === '' ? (\n <SvgIcon type=\"empty\" style={{ marginLeft: '3px' }} />\n ) : (\n renderInput(studentInputStyle, label)\n )}\n </StyledInputIncorrect>\n <StyledInputMissing style={secondLabelStyle}>{renderInput(studentInputStyle, correctlabel)}</StyledInputMissing>\n </>\n );\n }\n\n if (correctness === 'missing') {\n return <StyledInputMissing style={style}>{renderInput(studentInputStyle, label)}</StyledInputMissing>;\n }\n\n if (correctness === 'incorrect') {\n return <StyledIncorrect style={style}>{renderInput(studentInputStyle, label)}</StyledIncorrect>;\n }\n\n return <div style={style}>{renderInput(getInputStyles(theme, disabled, mark.disabled), label)}</div>;\n};\n\nMarkLabel.propTypes = {\n autoFocus: PropTypes.bool,\n disabled: PropTypes.bool,\n onBlur: PropTypes.func,\n onChange: PropTypes.func,\n graphProps: types.GraphPropsType,\n inputRef: PropTypes.func,\n mark: PropTypes.object,\n};\n\nexport default MarkLabel;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"mark-label.js","names":["_react","_interopRequireWildcard","require","_propTypes","_interopRequireDefault","_styles","_reactInputAutosize","_useDebounce","_plot","_renderUi","_labelSvgIcon","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","_typeof","has","get","set","_t","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","ownKeys","keys","getOwnPropertySymbols","filter","enumerable","push","apply","_objectSpread","arguments","length","forEach","_defineProperty2","getOwnPropertyDescriptors","defineProperties","DEBOUNCE_DELAY","INSIST_ON_FOCUS_FOR","INSIST_AT","StyledInputCorrect","styled","_ref2","theme","padding","spacing","borderRadius","fontSize","backgroundColor","color","defaults","WHITE","CORRECT_WITH_ICON","border","concat","StyledInputIncorrect","_ref3","INCORRECT_WITH_ICON","StyledInputMissing","_ref4","MISSING_WITH_ICON","fontWeight","StyledIncorrect","getInputStyles","disabled","markDisabled","fontFamily","typography","PRIMARY_DARK","SECONDARY","WebkitOpacity","undefined","WebkitTextFillColor","getStudentInputStyles","position","exports","graphProps","mark","rect","width","height","scale","domain","range","shift","rightEdge","x","bottomEdge","y","h","max","v","min","coordinates","left","top","LabelInput","_ref5","_ref","externalInputRef","label","inputStyle","onChange","onBlur","createElement","inputRef","value","propTypes","PropTypes","func","string","bool","object","MarkLabel","props","inputNode","useRef","_useState","useState","_useState2","_slicedToArray2","input","setInput","useCallback","node","current","useTheme","autoFocus","_useState3","_useState4","setLabel","correctness","correctnesslabel","correctlabel","isFocused","document","activeElement","isNewLabel","insistUntil","lastSaved","insisting","Date","now","target","saveLabel","handleBlur","debouncedLabel","useDebounce","useEffect","focusInput","focus","caret","setSelectionRange","timers","map","delay","setTimeout","clearTimeout","getBoundingClientRect","pos","leftTop","style","pointerEvents","display","alignItems","gap","secondLabelStyle","disabledInput","renderInput","labelValue","studentInputStyle","type","Fragment","marginLeft","types","GraphPropsType","_default"],"sources":["../src/mark-label.jsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport { styled, useTheme } from '@mui/material/styles';\nimport AutosizeInput from 'react-input-autosize';\nimport { useDebounce } from './use-debounce';\nimport { types } from '@pie-lib/plot';\nimport { color } from '@pie-lib/render-ui';\nimport SvgIcon from './label-svg-icon';\n\nconst DEBOUNCE_DELAY = 500;\n// A new label insists on the focus for this long: in the DNA env something moves the focus while the\n// model save that creating the label triggered is handled, after the last render. Nothing typed yet\n// is what tells that apart from the user leaving the label.\nconst INSIST_ON_FOCUS_FOR = 500;\nconst INSIST_AT = [0, 50, 120, 250, 400];\n\nconst StyledInputCorrect = styled('div')(({ theme }) => ({\n float: 'right',\n padding: theme.spacing(0.5),\n borderRadius: '4px',\n fontSize: '10px',\n backgroundColor: color.defaults.WHITE,\n color: color.defaults.CORRECT_WITH_ICON,\n border: `solid 1px ${color.defaults.CORRECT_WITH_ICON}`,\n}));\n\nconst StyledInputIncorrect = styled('div')(({ theme }) => ({\n float: 'right',\n padding: theme.spacing(0.5),\n borderRadius: '4px',\n fontSize: '10px',\n backgroundColor: color.defaults.WHITE,\n color: color.defaults.INCORRECT_WITH_ICON,\n border: `solid 1px ${color.defaults.INCORRECT_WITH_ICON}`,\n}));\n\nconst StyledInputMissing = styled('div')(({ theme }) => ({\n float: 'right',\n padding: theme.spacing(0.5),\n borderRadius: '4px',\n fontSize: '10px',\n backgroundColor: color.defaults.WHITE,\n color: color.defaults.MISSING_WITH_ICON,\n border: `solid 1px ${color.defaults.MISSING_WITH_ICON}`,\n fontWeight: 'bold',\n}));\n\nconst StyledIncorrect = styled('div')(() => ({\n float: 'right',\n padding: 0,\n borderRadius: '4px',\n fontSize: '10px',\n backgroundColor: color.defaults.WHITE,\n color: color.defaults.INCORRECT_WITH_ICON,\n fontWeight: 'bold',\n}));\n\nconst getInputStyles = (theme, disabled, markDisabled) => ({\n float: 'right',\n padding: theme.spacing(0.5),\n fontFamily: theme.typography.fontFamily,\n fontSize: '10px',\n border: disabled\n ? `solid 1px ${color.defaults.PRIMARY_DARK}`\n : markDisabled\n ? `solid 1px ${color.disabled()}`\n : `solid 1px ${color.defaults.SECONDARY}`,\n borderRadius: '3px',\n color: markDisabled ? color.disabled() : color.defaults.PRIMARY_DARK,\n backgroundColor: color.defaults.WHITE,\n WebkitOpacity: disabled ? '1' : undefined,\n WebkitTextFillColor: markDisabled ? color.disabled() : undefined,\n});\n\nconst getStudentInputStyles = () => ({\n padding: '0',\n border: 'none',\n color: 'inherit',\n fontWeight: 'bold',\n});\n\nexport const position = (graphProps, mark, rect = { width: 0, height: 0 }) => {\n const { scale, domain, range } = graphProps;\n const shift = 5;\n\n const rightEdge = scale.x(mark.x) + rect.width + shift;\n const bottomEdge = scale.y(mark.y) + rect.height + shift;\n\n const h = rightEdge >= scale.x(domain.max) ? 'left' : 'right';\n const v = bottomEdge >= scale.y(range.min) ? 'top' : 'bottom';\n\n return `${v}-${h}`;\n};\n\nexport const coordinates = (graphProps, mark, rect = { width: 0, height: 0 }, position) => {\n const { scale } = graphProps;\n const shift = 5;\n\n switch (position) {\n case 'bottom-right':\n return { left: scale.x(mark.x) + shift, top: scale.y(mark.y) + shift };\n case 'bottom-left':\n return { left: scale.x(mark.x) - shift - rect.width, top: scale.y(mark.y) + shift };\n case 'top-left':\n return { left: scale.x(mark.x) - shift - rect.width, top: scale.y(mark.y) - shift - rect.height };\n case 'top-right':\n return { left: scale.x(mark.x) + shift, top: scale.y(mark.y) - shift - rect.height };\n default:\n return {};\n }\n};\n\nconst LabelInput = ({ _ref, externalInputRef, label, disabled, inputStyle, onChange, onBlur }) => (\n <AutosizeInput\n inputRef={(r) => {\n _ref(r);\n externalInputRef(r);\n }}\n disabled={disabled}\n inputStyle={inputStyle}\n value={label}\n onChange={onChange}\n onBlur={onBlur}\n />\n);\n\nLabelInput.propTypes = {\n _ref: PropTypes.func,\n externalInputRef: PropTypes.func,\n label: PropTypes.string,\n disabled: PropTypes.bool,\n inputStyle: PropTypes.object,\n onChange: PropTypes.func,\n onBlur: PropTypes.func,\n};\n\nexport const MarkLabel = (props) => {\n // the state repositions the label once the input has a size, the ref is never a render behind\n const inputNode = useRef(null);\n const [input, setInput] = useState(null);\n const _ref = useCallback((node) => {\n inputNode.current = node;\n setInput(node);\n }, []);\n const theme = useTheme();\n\n const { mark, graphProps, disabled, autoFocus, inputRef: externalInputRef } = props;\n\n const [label, setLabel] = useState(mark.label);\n const { correctness, correctnesslabel, correctlabel } = mark;\n\n const isFocused = () =>\n !!inputNode.current && typeof document !== 'undefined' && document.activeElement === inputNode.current;\n\n // an empty label with an enabled input is one the user just added: label mode has to be on and it\n // always starts off. Read from the mark, not from autoFocus, because the tool that asked for the\n // label can be remounted by the marks coming back from the host before the input renders.\n const isNewLabel = useRef(mark.label === '' && !disabled && !mark.disabled);\n const insistUntil = useRef(0);\n const lastSaved = useRef(mark.label);\n const insisting = () => Date.now() < insistUntil.current && !(inputNode.current && inputNode.current.value);\n\n const onChange = (e) => setLabel(e.target.value);\n\n const saveLabel = (value) => {\n if (value === lastSaved.current) {\n return;\n }\n\n lastSaved.current = value;\n props.onChange(value);\n };\n\n const handleBlur = useCallback(() => {\n // in the DNA env the focus is moved while the model is saved - not the user leaving the label\n if (insisting()) {\n return;\n }\n\n isNewLabel.current = false;\n\n if (label === '') {\n props.onChange('');\n } else if (label !== mark.label) {\n // the debounce can still be pending, and once the focus is gone an echo of the model would\n // overwrite what was typed before it fires\n saveLabel(label);\n }\n\n // lets the tool know that this label is not being edited anymore, so it stops auto focusing it\n if (props.onBlur) {\n props.onBlur();\n }\n }, [label, mark.label, props.onChange, props.onBlur]);\n\n const debouncedLabel = useDebounce(label, DEBOUNCE_DELAY);\n\n // props to state, but not while focused: the mark can come back from an async model save with an\n // older label and overwrite what was typed meanwhile\n useEffect(() => {\n if (isFocused()) {\n return;\n }\n\n setLabel(mark.label);\n }, [mark.label]);\n\n // pick up the change to debouncedLabel and save it\n useEffect(() => {\n if (typeof debouncedLabel === 'string' && debouncedLabel !== mark.label) {\n saveLabel(debouncedLabel);\n }\n }, [debouncedLabel]);\n\n const focusInput = () => {\n const node = inputNode.current;\n\n // node.disabled, not the disabled prop: a disabled input silently ignores focus()\n if ((!autoFocus && !isNewLabel.current && !insisting()) || !node || node.disabled || isFocused()) {\n return;\n }\n\n node.focus();\n\n // a new label is focused once, so it cannot fight over the focus with another one\n if (isFocused()) {\n isNewLabel.current = false;\n }\n\n // keep the caret at the end, otherwise typing continues in front of the existing label\n const caret = (node.value || '').length;\n\n if (node.setSelectionRange) {\n node.setSelectionRange(caret, caret);\n }\n };\n\n // after every render: the input can appear a render or more later (the mark comes back from an\n // async model save) and a replaced node loses the focus without this component being told\n useEffect(() => focusInput());\n\n // and again on a timer, for the DNA env, where the focus is moved once the renders are over. The\n // original code focused from a setTimeout, which is what let it survive that.\n useEffect(() => {\n if (!autoFocus && !isNewLabel.current) {\n return;\n }\n\n if (!insistUntil.current) {\n insistUntil.current = Date.now() + INSIST_ON_FOCUS_FOR;\n }\n\n const timers = INSIST_AT.map((delay) => setTimeout(focusInput, delay));\n\n return () => timers.forEach((t) => clearTimeout(t));\n }, [autoFocus]);\n\n const rect = input ? input.getBoundingClientRect() : { width: 0, height: 0 };\n const pos = position(graphProps, mark, rect);\n const leftTop = coordinates(graphProps, mark, rect, pos);\n\n const style = {\n position: 'fixed',\n pointerEvents: 'auto',\n display: 'flex',\n alignItems: 'center',\n gap: '3px',\n ...leftTop,\n };\n\n const secondLabelStyle = {\n ...style,\n top: leftTop.top + 25,\n };\n\n const disabledInput = disabled || mark.disabled;\n\n const renderInput = (inputStyle, labelValue) => (\n <LabelInput\n _ref={_ref}\n externalInputRef={externalInputRef}\n label={labelValue}\n disabled={disabledInput}\n inputStyle={inputStyle}\n onChange={onChange}\n onBlur={handleBlur}\n />\n );\n\n const studentInputStyle = getStudentInputStyles();\n\n if (correctness === 'correct' && correctnesslabel === 'correct' && correctlabel) {\n return (\n <StyledInputCorrect style={style}>\n <SvgIcon type=\"correct\" />\n {renderInput(studentInputStyle, correctlabel)}\n </StyledInputCorrect>\n );\n }\n\n if (correctness === 'correct' && correctnesslabel === 'correct' && !correctlabel) {\n return null;\n }\n\n if (correctness === 'correct' && correctnesslabel === 'incorrect') {\n return (\n <>\n <StyledInputIncorrect style={style}>\n <SvgIcon type=\"incorrect\" />\n {label === '' ? (\n <SvgIcon type=\"empty\" style={{ marginLeft: '3px' }} />\n ) : (\n renderInput(studentInputStyle, label)\n )}\n </StyledInputIncorrect>\n <StyledInputMissing style={secondLabelStyle}>{renderInput(studentInputStyle, correctlabel)}</StyledInputMissing>\n </>\n );\n }\n\n if (correctness === 'missing') {\n return <StyledInputMissing style={style}>{renderInput(studentInputStyle, label)}</StyledInputMissing>;\n }\n\n if (correctness === 'incorrect') {\n return <StyledIncorrect style={style}>{renderInput(studentInputStyle, label)}</StyledIncorrect>;\n }\n\n // an empty label that cannot be edited is just an empty box - the config draws the background\n // marks into every correct answer graph too\n if (disabledInput && !label) {\n return null;\n }\n\n return <div style={style}>{renderInput(getInputStyles(theme, disabled, mark.disabled), label)}</div>;\n};\n\nMarkLabel.propTypes = {\n autoFocus: PropTypes.bool,\n disabled: PropTypes.bool,\n onBlur: PropTypes.func,\n onChange: PropTypes.func,\n graphProps: types.GraphPropsType,\n inputRef: PropTypes.func,\n mark: PropTypes.object,\n};\n\nexport default MarkLabel;\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.18",
|
|
7
7
|
"description": "Graphing components",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"react",
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"@mapbox/point-geometry": "^1.1.0",
|
|
23
23
|
"@mui/icons-material": "^7.3.4",
|
|
24
24
|
"@mui/material": "^7.3.4",
|
|
25
|
-
"@pie-lib/drag": "^4.1.
|
|
26
|
-
"@pie-lib/editable-html-tip-tap": "^2.1.
|
|
25
|
+
"@pie-lib/drag": "^4.1.2",
|
|
26
|
+
"@pie-lib/editable-html-tip-tap": "^2.1.15",
|
|
27
27
|
"@pie-lib/graphing-utils": "^3.0.2",
|
|
28
|
-
"@pie-lib/plot": "^4.0.
|
|
29
|
-
"@pie-lib/render-ui": "^7.0.
|
|
28
|
+
"@pie-lib/plot": "^4.0.17",
|
|
29
|
+
"@pie-lib/render-ui": "^7.0.1",
|
|
30
30
|
"@pie-lib/translator": "^4.0.2",
|
|
31
31
|
"@visx/axis": "^3.0.0",
|
|
32
32
|
"@visx/clip-path": "^3.0.0",
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"react": "^18.2.0"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "38176e40de37e31fc3bf4edb8669cf2238e910d3",
|
|
58
58
|
"scripts": {}
|
|
59
59
|
}
|
|
@@ -765,6 +765,25 @@ describe('label focus', () => {
|
|
|
765
765
|
expect(document.activeElement).toBe(input);
|
|
766
766
|
});
|
|
767
767
|
|
|
768
|
+
// in the DNA env the focus is moved while the model save is handled, after the last render
|
|
769
|
+
it('takes the focus back when something steals it while the model is saved', () => {
|
|
770
|
+
const { container } = render(<Host />);
|
|
771
|
+
|
|
772
|
+
clickPoint(container);
|
|
773
|
+
const input = container.querySelector('foreignObject input');
|
|
774
|
+
expect(document.activeElement).toBe(input);
|
|
775
|
+
|
|
776
|
+
const elsewhere = document.createElement('input');
|
|
777
|
+
document.body.appendChild(elsewhere);
|
|
778
|
+
elsewhere.focus();
|
|
779
|
+
expect(document.activeElement).toBe(elsewhere);
|
|
780
|
+
|
|
781
|
+
act(() => jest.advanceTimersByTime(300));
|
|
782
|
+
|
|
783
|
+
expect(document.activeElement).toBe(input);
|
|
784
|
+
elsewhere.remove();
|
|
785
|
+
});
|
|
786
|
+
|
|
768
787
|
it('focuses the label even if the tool was remounted before it rendered', () => {
|
|
769
788
|
const { container } = render(<Host shiftMarks={true} />);
|
|
770
789
|
|
|
@@ -82,13 +82,13 @@ describe('MarkLabel - editing', () => {
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
it('does not focus the input when disabled', () => {
|
|
85
|
-
const { input } = renderComponent({ autoFocus: true, disabled: true });
|
|
85
|
+
const { input } = renderComponent({ autoFocus: true, disabled: true, mark: { x: 1, y: 1, label: 'A' } });
|
|
86
86
|
|
|
87
87
|
expect(document.activeElement).not.toBe(input);
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
it('does not focus the input of a disabled mark', () => {
|
|
91
|
-
const { input } = renderComponent({ autoFocus: true, mark: { x: 1, y: 1, label: '', disabled: true } });
|
|
91
|
+
const { input } = renderComponent({ autoFocus: true, mark: { x: 1, y: 1, label: 'A', disabled: true } });
|
|
92
92
|
|
|
93
93
|
expect(document.activeElement).not.toBe(input);
|
|
94
94
|
});
|
|
@@ -191,10 +191,17 @@ describe('MarkLabel - editing', () => {
|
|
|
191
191
|
|
|
192
192
|
// outside of label mode the input is disabled, which is how an empty label that was loaded with
|
|
193
193
|
// the item is told apart from one the user has just added - label mode always starts off
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
// the config draws the background marks into the correct answer graphs as disabled marks
|
|
195
|
+
it('is not rendered at all while it cannot be edited', () => {
|
|
196
|
+
const { container } = renderComponent({ disabled: true, mark: { x: 1, y: 1, label: '' } });
|
|
196
197
|
|
|
197
|
-
expect(
|
|
198
|
+
expect(container.querySelector('input')).toBe(null);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('is still rendered uneditable once it has text', () => {
|
|
202
|
+
const { container } = renderComponent({ disabled: true, mark: { x: 1, y: 1, label: 'A' } });
|
|
203
|
+
|
|
204
|
+
expect(container.querySelector('input').value).toBe('A');
|
|
198
205
|
});
|
|
199
206
|
|
|
200
207
|
it('is not focused when label mode is turned on afterwards', () => {
|
|
@@ -202,13 +209,14 @@ describe('MarkLabel - editing', () => {
|
|
|
202
209
|
|
|
203
210
|
rerenderWith({ disabled: false });
|
|
204
211
|
|
|
212
|
+
expect(input(container)).not.toBe(null);
|
|
205
213
|
expect(document.activeElement).not.toBe(input(container));
|
|
206
214
|
});
|
|
207
215
|
|
|
208
|
-
it('is not
|
|
209
|
-
const {
|
|
216
|
+
it('is not rendered for a disabled mark while it is empty', () => {
|
|
217
|
+
const { container } = renderComponent({ mark: { x: 1, y: 1, label: '', disabled: true } });
|
|
210
218
|
|
|
211
|
-
expect(
|
|
219
|
+
expect(container.querySelector('input')).toBe(null);
|
|
212
220
|
});
|
|
213
221
|
});
|
|
214
222
|
|
|
@@ -247,6 +255,29 @@ describe('MarkLabel - editing', () => {
|
|
|
247
255
|
expect(onBlur).toHaveBeenCalled();
|
|
248
256
|
});
|
|
249
257
|
|
|
258
|
+
// clicking a button or anything else interactive blurs the label while the debounce is pending
|
|
259
|
+
it('saves what was typed straight away', () => {
|
|
260
|
+
const { input } = renderComponent({ mark: { x: 1, y: 1, label: '' } });
|
|
261
|
+
|
|
262
|
+
fireEvent.change(input, { target: { value: 'AB' } });
|
|
263
|
+
fireEvent.blur(input);
|
|
264
|
+
|
|
265
|
+
expect(onChange).toHaveBeenCalledWith('AB');
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('does not save it twice when the debounce catches up', () => {
|
|
269
|
+
jest.useFakeTimers();
|
|
270
|
+
const { input } = renderComponent({ mark: { x: 1, y: 1, label: '' } });
|
|
271
|
+
|
|
272
|
+
fireEvent.change(input, { target: { value: 'AB' } });
|
|
273
|
+
fireEvent.blur(input);
|
|
274
|
+
act(() => jest.advanceTimersByTime(1000));
|
|
275
|
+
|
|
276
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
277
|
+
expect(onChange).toHaveBeenCalledWith('AB');
|
|
278
|
+
jest.useRealTimers();
|
|
279
|
+
});
|
|
280
|
+
|
|
250
281
|
it('reports an empty label on blur', () => {
|
|
251
282
|
const { input } = renderComponent({ mark: { x: 1, y: 1, label: 'A' } });
|
|
252
283
|
|
package/src/mark-label.jsx
CHANGED
|
@@ -8,6 +8,11 @@ import { color } from '@pie-lib/render-ui';
|
|
|
8
8
|
import SvgIcon from './label-svg-icon';
|
|
9
9
|
|
|
10
10
|
const DEBOUNCE_DELAY = 500;
|
|
11
|
+
// A new label insists on the focus for this long: in the DNA env something moves the focus while the
|
|
12
|
+
// model save that creating the label triggered is handled, after the last render. Nothing typed yet
|
|
13
|
+
// is what tells that apart from the user leaving the label.
|
|
14
|
+
const INSIST_ON_FOCUS_FOR = 500;
|
|
15
|
+
const INSIST_AT = [0, 50, 120, 250, 400];
|
|
11
16
|
|
|
12
17
|
const StyledInputCorrect = styled('div')(({ theme }) => ({
|
|
13
18
|
float: 'right',
|
|
@@ -130,8 +135,7 @@ LabelInput.propTypes = {
|
|
|
130
135
|
};
|
|
131
136
|
|
|
132
137
|
export const MarkLabel = (props) => {
|
|
133
|
-
// the
|
|
134
|
-
// once it has a size, the ref is what the focus is asserted on - it is never a render behind
|
|
138
|
+
// the state repositions the label once the input has a size, the ref is never a render behind
|
|
135
139
|
const inputNode = useRef(null);
|
|
136
140
|
const [input, setInput] = useState(null);
|
|
137
141
|
const _ref = useCallback((node) => {
|
|
@@ -148,33 +152,51 @@ export const MarkLabel = (props) => {
|
|
|
148
152
|
const isFocused = () =>
|
|
149
153
|
!!inputNode.current && typeof document !== 'undefined' && document.activeElement === inputNode.current;
|
|
150
154
|
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
// because the tool that asked for the label can be remounted by the marks coming back from the
|
|
155
|
-
// host (async model save) before the input ever renders, and its autoFocus goes with it.
|
|
155
|
+
// an empty label with an enabled input is one the user just added: label mode has to be on and it
|
|
156
|
+
// always starts off. Read from the mark, not from autoFocus, because the tool that asked for the
|
|
157
|
+
// label can be remounted by the marks coming back from the host before the input renders.
|
|
156
158
|
const isNewLabel = useRef(mark.label === '' && !disabled && !mark.disabled);
|
|
159
|
+
const insistUntil = useRef(0);
|
|
160
|
+
const lastSaved = useRef(mark.label);
|
|
161
|
+
const insisting = () => Date.now() < insistUntil.current && !(inputNode.current && inputNode.current.value);
|
|
157
162
|
|
|
158
163
|
const onChange = (e) => setLabel(e.target.value);
|
|
159
164
|
|
|
165
|
+
const saveLabel = (value) => {
|
|
166
|
+
if (value === lastSaved.current) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
lastSaved.current = value;
|
|
171
|
+
props.onChange(value);
|
|
172
|
+
};
|
|
173
|
+
|
|
160
174
|
const handleBlur = useCallback(() => {
|
|
175
|
+
// in the DNA env the focus is moved while the model is saved - not the user leaving the label
|
|
176
|
+
if (insisting()) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
161
180
|
isNewLabel.current = false;
|
|
162
181
|
|
|
163
182
|
if (label === '') {
|
|
164
183
|
props.onChange('');
|
|
184
|
+
} else if (label !== mark.label) {
|
|
185
|
+
// the debounce can still be pending, and once the focus is gone an echo of the model would
|
|
186
|
+
// overwrite what was typed before it fires
|
|
187
|
+
saveLabel(label);
|
|
165
188
|
}
|
|
166
189
|
|
|
167
190
|
// lets the tool know that this label is not being edited anymore, so it stops auto focusing it
|
|
168
191
|
if (props.onBlur) {
|
|
169
192
|
props.onBlur();
|
|
170
193
|
}
|
|
171
|
-
}, [label, props.onChange, props.onBlur]);
|
|
194
|
+
}, [label, mark.label, props.onChange, props.onBlur]);
|
|
172
195
|
|
|
173
196
|
const debouncedLabel = useDebounce(label, DEBOUNCE_DELAY);
|
|
174
197
|
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
// (async) model save with an older label and that would overwrite the characters typed meanwhile.
|
|
198
|
+
// props to state, but not while focused: the mark can come back from an async model save with an
|
|
199
|
+
// older label and overwrite what was typed meanwhile
|
|
178
200
|
useEffect(() => {
|
|
179
201
|
if (isFocused()) {
|
|
180
202
|
return;
|
|
@@ -186,21 +208,15 @@ export const MarkLabel = (props) => {
|
|
|
186
208
|
// pick up the change to debouncedLabel and save it
|
|
187
209
|
useEffect(() => {
|
|
188
210
|
if (typeof debouncedLabel === 'string' && debouncedLabel !== mark.label) {
|
|
189
|
-
|
|
211
|
+
saveLabel(debouncedLabel);
|
|
190
212
|
}
|
|
191
213
|
}, [debouncedLabel]);
|
|
192
214
|
|
|
193
|
-
|
|
194
|
-
// This runs after every render on purpose - there is no reliable single moment to focus at:
|
|
195
|
-
// the input shows up whenever the mark comes back from the (async) model save, and a remount
|
|
196
|
-
// of the input (same save, replaced node) drops the focus without this component being told.
|
|
197
|
-
// Asserting the focus on every render is what makes it stick; it is a no-op once the input has
|
|
198
|
-
// it, so the caret the user placed is left alone.
|
|
199
|
-
useEffect(() => {
|
|
215
|
+
const focusInput = () => {
|
|
200
216
|
const node = inputNode.current;
|
|
201
217
|
|
|
202
218
|
// node.disabled, not the disabled prop: a disabled input silently ignores focus()
|
|
203
|
-
if ((!autoFocus && !isNewLabel.current) || !node || node.disabled || isFocused()) {
|
|
219
|
+
if ((!autoFocus && !isNewLabel.current && !insisting()) || !node || node.disabled || isFocused()) {
|
|
204
220
|
return;
|
|
205
221
|
}
|
|
206
222
|
|
|
@@ -217,7 +233,27 @@ export const MarkLabel = (props) => {
|
|
|
217
233
|
if (node.setSelectionRange) {
|
|
218
234
|
node.setSelectionRange(caret, caret);
|
|
219
235
|
}
|
|
220
|
-
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// after every render: the input can appear a render or more later (the mark comes back from an
|
|
239
|
+
// async model save) and a replaced node loses the focus without this component being told
|
|
240
|
+
useEffect(() => focusInput());
|
|
241
|
+
|
|
242
|
+
// and again on a timer, for the DNA env, where the focus is moved once the renders are over. The
|
|
243
|
+
// original code focused from a setTimeout, which is what let it survive that.
|
|
244
|
+
useEffect(() => {
|
|
245
|
+
if (!autoFocus && !isNewLabel.current) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!insistUntil.current) {
|
|
250
|
+
insistUntil.current = Date.now() + INSIST_ON_FOCUS_FOR;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const timers = INSIST_AT.map((delay) => setTimeout(focusInput, delay));
|
|
254
|
+
|
|
255
|
+
return () => timers.forEach((t) => clearTimeout(t));
|
|
256
|
+
}, [autoFocus]);
|
|
221
257
|
|
|
222
258
|
const rect = input ? input.getBoundingClientRect() : { width: 0, height: 0 };
|
|
223
259
|
const pos = position(graphProps, mark, rect);
|
|
@@ -290,6 +326,12 @@ export const MarkLabel = (props) => {
|
|
|
290
326
|
return <StyledIncorrect style={style}>{renderInput(studentInputStyle, label)}</StyledIncorrect>;
|
|
291
327
|
}
|
|
292
328
|
|
|
329
|
+
// an empty label that cannot be edited is just an empty box - the config draws the background
|
|
330
|
+
// marks into every correct answer graph too
|
|
331
|
+
if (disabledInput && !label) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
|
|
293
335
|
return <div style={style}>{renderInput(getInputStyles(theme, disabled, mark.disabled), label)}</div>;
|
|
294
336
|
};
|
|
295
337
|
|
|
@@ -409,7 +409,8 @@ describe('Component', () => {
|
|
|
409
409
|
expect(document.activeElement).not.toBe(labelNode.querySelector('input'));
|
|
410
410
|
});
|
|
411
411
|
|
|
412
|
-
|
|
412
|
+
// the blur that the DNA env causes by moving the focus is not the user leaving the label
|
|
413
|
+
it('keeps the focus on a new empty label that something else blurred', () => {
|
|
413
414
|
const { container } = render(<Controlled initialMark={xy(1, 1)} labelModeEnabled={true} />);
|
|
414
415
|
|
|
415
416
|
clickPoint(container);
|
|
@@ -417,9 +418,23 @@ describe('Component', () => {
|
|
|
417
418
|
expect(document.activeElement).toBe(input);
|
|
418
419
|
|
|
419
420
|
fireEvent.blur(input);
|
|
421
|
+
fireEvent.change(input, { target: { value: 'A' } });
|
|
422
|
+
|
|
423
|
+
expect(document.activeElement).toBe(input);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('stops auto focusing the label once it has text and is blurred', () => {
|
|
427
|
+
const { container } = render(<Controlled initialMark={xy(1, 1)} labelModeEnabled={true} />);
|
|
428
|
+
|
|
429
|
+
clickPoint(container);
|
|
430
|
+
const input = labelNode.querySelector('input');
|
|
420
431
|
|
|
421
|
-
// a re-render must not pull the focus back into the label the user just left
|
|
422
432
|
fireEvent.change(input, { target: { value: 'A' } });
|
|
433
|
+
fireEvent.blur(input);
|
|
434
|
+
input.blur();
|
|
435
|
+
|
|
436
|
+
// a re-render must not pull the focus back into the label the user just left
|
|
437
|
+
fireEvent.change(input, { target: { value: 'AB' } });
|
|
423
438
|
expect(document.activeElement).not.toBe(input);
|
|
424
439
|
});
|
|
425
440
|
|