@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 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 node is kept in a ref as well as in the state: the state is needed to reposition the label
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
- // A label that has just been added is empty and its input is enabled - label mode has to be on
200
- // for that to happen and it always starts off, so a mark that was loaded with an empty label
201
- // cannot grab the focus. This is read from the mark rather than taken from the autoFocus prop
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
- // useState only sets the value once, to synch props to state need useEffect.
222
- // While this input has the focus we keep what the user typed: the mark can come back from an
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
- props.onChange(debouncedLabel);
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));
@@ -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.17",
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.1",
26
- "@pie-lib/editable-html-tip-tap": "^2.1.14",
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.16",
29
- "@pie-lib/render-ui": "^7.0.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": "e6b46157ab321f4488117149f21783511f30970c",
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
- it('is not focused while label mode is off', () => {
195
- const { input } = renderComponent({ disabled: true, mark: { x: 1, y: 1, label: '' } });
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(document.activeElement).not.toBe(input);
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 focused when the mark is disabled', () => {
209
- const { input } = renderComponent({ mark: { x: 1, y: 1, label: '', disabled: true } });
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(document.activeElement).not.toBe(input);
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
 
@@ -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 node is kept in a ref as well as in the state: the state is needed to reposition the label
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
- // A label that has just been added is empty and its input is enabled - label mode has to be on
152
- // for that to happen and it always starts off, so a mark that was loaded with an empty label
153
- // cannot grab the focus. This is read from the mark rather than taken from the autoFocus prop
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
- // useState only sets the value once, to synch props to state need useEffect.
176
- // While this input has the focus we keep what the user typed: the mark can come back from an
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
- props.onChange(debouncedLabel);
211
+ saveLabel(debouncedLabel);
190
212
  }
191
213
  }, [debouncedLabel]);
192
214
 
193
- // A label that has just been added has to be focused so that it can be typed into right away.
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
- it('stops auto focusing the label once it is blurred', () => {
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