trackValue.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. import '../utils/dataTransfer/Clipboard.js';
  2. import { getWindow } from '../utils/misc/getWindow.js';
  3. import { setUIValueClean, setUISelection, hasUISelection } from './UI.js';
  4. const TrackChanges = Symbol('Track programmatic changes for React workaround');
  5. // When the input event happens in the browser, React executes all event handlers
  6. // and if they change state of a controlled value, nothing happens.
  7. // But when we trigger the event handlers in test environment with React@17,
  8. // the changes are rolled back before the state update is applied.
  9. // This results in a reset cursor.
  10. // There might be a better way to work around if we figure out
  11. // why the batched update is executed differently in our test environment.
  12. function isReact17Element(element) {
  13. return Object.getOwnPropertyNames(element).some((k)=>k.startsWith('__react')) && getWindow(element).REACT_VERSION === 17;
  14. }
  15. function startTrackValue(element) {
  16. if (!isReact17Element(element)) {
  17. return;
  18. }
  19. element[TrackChanges] = {
  20. previousValue: String(element.value),
  21. tracked: []
  22. };
  23. }
  24. function trackOrSetValue(element, v) {
  25. var _element_TrackChanges_tracked, _element_TrackChanges;
  26. (_element_TrackChanges = element[TrackChanges]) === null || _element_TrackChanges === undefined ? undefined : (_element_TrackChanges_tracked = _element_TrackChanges.tracked) === null || _element_TrackChanges_tracked === undefined ? undefined : _element_TrackChanges_tracked.push(v);
  27. if (!element[TrackChanges]) {
  28. setUIValueClean(element);
  29. setUISelection(element, {
  30. focusOffset: v.length
  31. });
  32. }
  33. }
  34. function commitValueAfterInput(element, cursorOffset) {
  35. var _changes_tracked;
  36. const changes = element[TrackChanges];
  37. element[TrackChanges] = undefined;
  38. if (!(changes === null || changes === undefined ? undefined : (_changes_tracked = changes.tracked) === null || _changes_tracked === undefined ? undefined : _changes_tracked.length)) {
  39. return;
  40. }
  41. const isJustReactStateUpdate = changes.tracked.length === 2 && changes.tracked[0] === changes.previousValue && changes.tracked[1] === element.value;
  42. if (!isJustReactStateUpdate) {
  43. setUIValueClean(element);
  44. }
  45. if (hasUISelection(element)) {
  46. setUISelection(element, {
  47. focusOffset: isJustReactStateUpdate ? cursorOffset : element.value.length
  48. });
  49. }
  50. }
  51. export { commitValueAfterInput, startTrackValue, trackOrSetValue };