@zzish/math-rich-input 0.1.55 → 0.1.56

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zzish/math-rich-input",
3
- "version": "0.1.55",
3
+ "version": "0.1.56",
4
4
  "description": "React component for user to enter rich text with embedded math equations.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,10 +13,11 @@
13
13
  },
14
14
  "main": "dist/index.js",
15
15
  "scripts": {
16
+ "test": "playwright test tests/caret-regression.spec.js --workers=1",
16
17
  "build": "rollup --config && webpack --config webpack.standalone.config.js",
17
18
  "build:legacy": "rollup --config",
18
19
  "build:standalone": "webpack --config webpack.standalone.config.js",
19
- "prepublishOnly": "npm run build"
20
+ "prepublishOnly": "npm test && npm run build"
20
21
  },
21
22
  "dependencies": {
22
23
  "katex": "^0.12.0",
@@ -36,6 +37,7 @@
36
37
  "@babel/preset-env": "^7.24.5",
37
38
  "@babel/preset-react": "^7.24.1",
38
39
  "@babel/register": "^7.13.8",
40
+ "@playwright/test": "^1.62.1",
39
41
  "@rollup/plugin-babel": "^5.3.0",
40
42
  "@rollup/plugin-commonjs": "^17.1.0",
41
43
  "@rollup/plugin-node-resolve": "^11.2.0",
@@ -84,6 +84,7 @@ const EMPTY_INLINE_FORMATTING_REG_EXP =
84
84
  // const LATEX_MARKER_END = "</annotation>"
85
85
 
86
86
  const MAX_HISTORY_LENGTH = 100;
87
+ const CONTROLLED_VALUE_ECHO_TIMEOUT_MS = 50;
87
88
 
88
89
  const DEFAULT_OPTIONS = {
89
90
  useExpertMode: false,
@@ -367,6 +368,21 @@ export default class MathRichInput extends React.Component {
367
368
 
368
369
  // Call the parent handler to apply the changes
369
370
  this.onChangeCallback({ value, mimeType }, { isExpertMode, selectedTab });
371
+ if (applyOptions.skipControlledRender === true) {
372
+ const pendingNativeValue = value;
373
+ // Give a scheduled controlled echo one short render window. If the host
374
+ // never echoes the value, release the gate rather than preserving a
375
+ // rejected native edit indefinitely.
376
+ setTimeout(() => {
377
+ if (
378
+ this.skipNextControlledValueRender === true &&
379
+ this.skipNextControlledValue === pendingNativeValue
380
+ ) {
381
+ this.skipNextControlledValueRender = false;
382
+ this.skipNextControlledValue = null;
383
+ }
384
+ }, CONTROLLED_VALUE_ECHO_TIMEOUT_MS);
385
+ }
370
386
  debugMathRichInput("applyChangesToComponent:after-onChange", {
371
387
  afterComponentUpdateData: this.afterComponentUpdateData,
372
388
  selection: getSelectionSnapshot(this.editableDiv),
@@ -587,6 +603,9 @@ export default class MathRichInput extends React.Component {
587
603
  ? this.getCurrentRawTextForProps(this.props)
588
604
  : null;
589
605
  const liveEditableHtml = this.editableDiv ? this.editableDiv.innerHTML : null;
606
+ const pendingNativeInputMatchesLiveDom =
607
+ this.skipNextControlledValueRender === true &&
608
+ currentRawText === this.skipNextControlledValue;
590
609
  const canPreserveNativeDom =
591
610
  this.state.hasFocus === true &&
592
611
  this.editableDiv !== null &&
@@ -594,7 +613,7 @@ export default class MathRichInput extends React.Component {
594
613
  (this.afterComponentUpdateData === null ||
595
614
  this.afterComponentUpdateData === undefined) &&
596
615
  this.lastRenderedEditableHtml !== null &&
597
- currentRawText === this.props.value;
616
+ (currentRawText === this.props.value || pendingNativeInputMatchesLiveDom);
598
617
  const preserveRangeParams = canPreserveNativeDom
599
618
  ? this.getRangeParamsPreservingInlinePlaceholder()
600
619
  : null;
@@ -609,6 +628,7 @@ export default class MathRichInput extends React.Component {
609
628
  liveEditableHtml,
610
629
  lastRenderedEditableHtml: this.lastRenderedEditableHtml,
611
630
  currentRawText,
631
+ pendingNativeInputMatchesLiveDom,
612
632
  preserveRangeParams,
613
633
  afterComponentUpdateData: this.afterComponentUpdateData,
614
634
  hasFocus: this.state.hasFocus,
@@ -2694,22 +2714,32 @@ export default class MathRichInput extends React.Component {
2694
2714
 
2695
2715
  shouldComponentUpdate(nextProps, nextState) {
2696
2716
  if (this.skipNextControlledValueRender === true) {
2717
+ const controlledValueArrived =
2718
+ nextProps.value === this.skipNextControlledValue;
2697
2719
  const canSkip =
2698
- nextProps.value === this.skipNextControlledValue &&
2699
- nextState === this.state;
2720
+ controlledValueArrived && nextState === this.state;
2700
2721
 
2701
2722
  debugMathRichInput("shouldComponentUpdate:native-input-gate", {
2702
2723
  canSkip,
2703
2724
  nextValue: nextProps.value,
2704
2725
  skipNextControlledValue: this.skipNextControlledValue,
2726
+ controlledValueArrived,
2705
2727
  currentPropsValue: this.props.value,
2706
2728
  stateChanged: nextState !== this.state,
2707
2729
  innerHTML: this.editableDiv ? this.editableDiv.innerHTML : null,
2708
2730
  selection: getSelectionSnapshot(this.editableDiv),
2709
2731
  });
2710
2732
 
2711
- this.skipNextControlledValueRender = false;
2712
- this.skipNextControlledValue = null;
2733
+ // A controlled host may commit an unrelated render before it echoes the
2734
+ // value from this native input event. Keep the gate armed through that
2735
+ // stale render so getEditableHtmlForRender can preserve the browser DOM
2736
+ // and its selection. The time-bounded fallback armed by
2737
+ // applyChangesToComponent keeps a host that rejects the value from
2738
+ // leaving the gate armed indefinitely.
2739
+ if (controlledValueArrived) {
2740
+ this.skipNextControlledValueRender = false;
2741
+ this.skipNextControlledValue = null;
2742
+ }
2713
2743
 
2714
2744
  if (canSkip) return false;
2715
2745
  }