@lexical/history 0.35.1-nightly.20250924.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,7 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ var extension = require('@lexical/extension');
11
12
  var utils = require('@lexical/utils');
12
13
  var lexical = require('lexical');
13
14
 
@@ -118,7 +119,7 @@ function isTextNodeUnchanged(key, prevEditorState, nextEditorState) {
118
119
  }
119
120
  return false;
120
121
  }
121
- function createMergeActionGetter(editor, delay) {
122
+ function createMergeActionGetter(editor, delayOrStore) {
122
123
  let prevChangeTime = Date.now();
123
124
  let prevChangeType = OTHER;
124
125
  return (prevEditorState, nextEditorState, currentHistoryEntry, dirtyLeaves, dirtyElements, tags) => {
@@ -150,6 +151,7 @@ function createMergeActionGetter(editor, delay) {
150
151
  }
151
152
  return DISCARD_HISTORY_CANDIDATE;
152
153
  }
154
+ const delay = typeof delayOrStore === 'number' ? delayOrStore : delayOrStore.peek();
153
155
  if (shouldPushHistory === false && changeType !== OTHER && changeType === prevChangeType && changeTime < prevChangeTime + delay && isSameEditor) {
154
156
  return HISTORY_MERGE;
155
157
  }
@@ -294,6 +296,68 @@ function createEmptyHistoryState() {
294
296
  undoStack: []
295
297
  };
296
298
  }
299
+ /**
300
+ * Registers necessary listeners to manage undo/redo history stack and related
301
+ * editor commands, via the \@lexical/history module.
302
+ */
303
+
304
+ const HistoryExtension = lexical.defineExtension({
305
+ build: (editor, {
306
+ delay,
307
+ createInitialHistoryState,
308
+ disabled
309
+ }) => extension.namedSignals({
310
+ delay,
311
+ disabled,
312
+ historyState: createInitialHistoryState(editor)
313
+ }),
314
+ config: lexical.safeCast({
315
+ createInitialHistoryState: createEmptyHistoryState,
316
+ delay: 300,
317
+ disabled: typeof window === 'undefined'
318
+ }),
319
+ name: '@lexical/history/History',
320
+ register: (editor, config, state) => {
321
+ const stores = state.getOutput();
322
+ return extension.effect(() => stores.disabled.value ? undefined : registerHistory(editor, stores.historyState.value, stores.delay));
323
+ }
324
+ });
325
+ function getHistoryPeer(editor) {
326
+ return editor ? extension.getPeerDependencyFromEditor(editor, HistoryExtension.name) : null;
327
+ }
328
+
329
+ /**
330
+ * Registers necessary listeners to manage undo/redo history stack and related
331
+ * editor commands, via the \@lexical/history module, only if the parent editor
332
+ * has a history plugin implementation.
333
+ */
334
+ const SharedHistoryExtension = lexical.defineExtension({
335
+ dependencies: [lexical.configExtension(HistoryExtension, {
336
+ createInitialHistoryState: () => {
337
+ throw new Error('SharedHistory did not inherit parent history');
338
+ },
339
+ disabled: true
340
+ })],
341
+ name: '@lexical/history/SharedHistory',
342
+ register(editor, _config, state) {
343
+ const {
344
+ output
345
+ } = state.getDependency(HistoryExtension);
346
+ const parentPeer = getHistoryPeer(editor._parentEditor);
347
+ if (!parentPeer) {
348
+ return () => {};
349
+ }
350
+ const parentOutput = parentPeer.output;
351
+ return extension.effect(() => extension.batch(() => {
352
+ output.delay.value = parentOutput.delay.value;
353
+ output.historyState.value = parentOutput.historyState.value;
354
+ // Note that toggling the parent history will force this to be changed
355
+ output.disabled.value = parentOutput.disabled.value;
356
+ }));
357
+ }
358
+ });
297
359
 
360
+ exports.HistoryExtension = HistoryExtension;
361
+ exports.SharedHistoryExtension = SharedHistoryExtension;
298
362
  exports.createEmptyHistoryState = createEmptyHistoryState;
299
363
  exports.registerHistory = registerHistory;
@@ -6,8 +6,9 @@
6
6
  *
7
7
  */
8
8
 
9
+ import { namedSignals, effect, batch, getPeerDependencyFromEditor } from '@lexical/extension';
9
10
  import { mergeRegister } from '@lexical/utils';
10
- import { UNDO_COMMAND, COMMAND_PRIORITY_EDITOR, REDO_COMMAND, CLEAR_EDITOR_COMMAND, CLEAR_HISTORY_COMMAND, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, HISTORIC_TAG, HISTORY_PUSH_TAG, HISTORY_MERGE_TAG, $isRangeSelection, $isTextNode, $isRootNode } from 'lexical';
11
+ import { defineExtension, safeCast, configExtension, UNDO_COMMAND, COMMAND_PRIORITY_EDITOR, REDO_COMMAND, CLEAR_EDITOR_COMMAND, CLEAR_HISTORY_COMMAND, CAN_REDO_COMMAND, CAN_UNDO_COMMAND, HISTORIC_TAG, HISTORY_PUSH_TAG, HISTORY_MERGE_TAG, $isRangeSelection, $isTextNode, $isRootNode } from 'lexical';
11
12
 
12
13
  /**
13
14
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -116,7 +117,7 @@ function isTextNodeUnchanged(key, prevEditorState, nextEditorState) {
116
117
  }
117
118
  return false;
118
119
  }
119
- function createMergeActionGetter(editor, delay) {
120
+ function createMergeActionGetter(editor, delayOrStore) {
120
121
  let prevChangeTime = Date.now();
121
122
  let prevChangeType = OTHER;
122
123
  return (prevEditorState, nextEditorState, currentHistoryEntry, dirtyLeaves, dirtyElements, tags) => {
@@ -148,6 +149,7 @@ function createMergeActionGetter(editor, delay) {
148
149
  }
149
150
  return DISCARD_HISTORY_CANDIDATE;
150
151
  }
152
+ const delay = typeof delayOrStore === 'number' ? delayOrStore : delayOrStore.peek();
151
153
  if (shouldPushHistory === false && changeType !== OTHER && changeType === prevChangeType && changeTime < prevChangeTime + delay && isSameEditor) {
152
154
  return HISTORY_MERGE;
153
155
  }
@@ -292,5 +294,65 @@ function createEmptyHistoryState() {
292
294
  undoStack: []
293
295
  };
294
296
  }
297
+ /**
298
+ * Registers necessary listeners to manage undo/redo history stack and related
299
+ * editor commands, via the \@lexical/history module.
300
+ */
301
+
302
+ const HistoryExtension = defineExtension({
303
+ build: (editor, {
304
+ delay,
305
+ createInitialHistoryState,
306
+ disabled
307
+ }) => namedSignals({
308
+ delay,
309
+ disabled,
310
+ historyState: createInitialHistoryState(editor)
311
+ }),
312
+ config: safeCast({
313
+ createInitialHistoryState: createEmptyHistoryState,
314
+ delay: 300,
315
+ disabled: typeof window === 'undefined'
316
+ }),
317
+ name: '@lexical/history/History',
318
+ register: (editor, config, state) => {
319
+ const stores = state.getOutput();
320
+ return effect(() => stores.disabled.value ? undefined : registerHistory(editor, stores.historyState.value, stores.delay));
321
+ }
322
+ });
323
+ function getHistoryPeer(editor) {
324
+ return editor ? getPeerDependencyFromEditor(editor, HistoryExtension.name) : null;
325
+ }
326
+
327
+ /**
328
+ * Registers necessary listeners to manage undo/redo history stack and related
329
+ * editor commands, via the \@lexical/history module, only if the parent editor
330
+ * has a history plugin implementation.
331
+ */
332
+ const SharedHistoryExtension = defineExtension({
333
+ dependencies: [configExtension(HistoryExtension, {
334
+ createInitialHistoryState: () => {
335
+ throw new Error('SharedHistory did not inherit parent history');
336
+ },
337
+ disabled: true
338
+ })],
339
+ name: '@lexical/history/SharedHistory',
340
+ register(editor, _config, state) {
341
+ const {
342
+ output
343
+ } = state.getDependency(HistoryExtension);
344
+ const parentPeer = getHistoryPeer(editor._parentEditor);
345
+ if (!parentPeer) {
346
+ return () => {};
347
+ }
348
+ const parentOutput = parentPeer.output;
349
+ return effect(() => batch(() => {
350
+ output.delay.value = parentOutput.delay.value;
351
+ output.historyState.value = parentOutput.historyState.value;
352
+ // Note that toggling the parent history will force this to be changed
353
+ output.disabled.value = parentOutput.disabled.value;
354
+ }));
355
+ }
356
+ });
295
357
 
296
- export { createEmptyHistoryState, registerHistory };
358
+ export { HistoryExtension, SharedHistoryExtension, createEmptyHistoryState, registerHistory };
@@ -6,7 +6,8 @@
6
6
  *
7
7
  * @flow strict
8
8
  */
9
- import type {EditorState, BaseSelection, LexicalEditor} from 'lexical';
9
+ import type {LexicalExtension, ExtensionConfigBase, EditorState, BaseSelection, LexicalEditor} from 'lexical';
10
+ import type {NamedSignalsOutput} from '@lexical/extension';
10
11
 
11
12
  export type HistoryStateEntry = {
12
13
  editor: LexicalEditor,
@@ -24,3 +25,15 @@ declare export function registerHistory(
24
25
  delay: number,
25
26
  ): () => void;
26
27
  declare export function createEmptyHistoryState(): HistoryState;
28
+
29
+ export type HistoryConfig = {
30
+ delay: number;
31
+ createInitialHistoryState: (editor: LexicalEditor) => HistoryState;
32
+ disabled: boolean;
33
+ }
34
+ declare export var HistoryExtension: LexicalExtension<HistoryConfig, "@lexical/history/History", NamedSignalsOutput<{
35
+ delay: number;
36
+ disabled: boolean;
37
+ historyState: HistoryState;
38
+ }>, void>;
39
+ declare export var SharedHistoryExtension: LexicalExtension<ExtensionConfigBase, "@lexical/history/SharedHistory", void, void>;
@@ -9,5 +9,7 @@
9
9
  import * as modDev from './LexicalHistory.dev.mjs';
10
10
  import * as modProd from './LexicalHistory.prod.mjs';
11
11
  const mod = process.env.NODE_ENV !== 'production' ? modDev : modProd;
12
+ export const HistoryExtension = mod.HistoryExtension;
13
+ export const SharedHistoryExtension = mod.SharedHistoryExtension;
12
14
  export const createEmptyHistoryState = mod.createEmptyHistoryState;
13
15
  export const registerHistory = mod.registerHistory;
@@ -7,5 +7,7 @@
7
7
  */
8
8
 
9
9
  const mod = await (process.env.NODE_ENV !== 'production' ? import('./LexicalHistory.dev.mjs') : import('./LexicalHistory.prod.mjs'));
10
+ export const HistoryExtension = mod.HistoryExtension;
11
+ export const SharedHistoryExtension = mod.SharedHistoryExtension;
10
12
  export const createEmptyHistoryState = mod.createEmptyHistoryState;
11
13
  export const registerHistory = mod.registerHistory;
@@ -6,4 +6,4 @@
6
6
  *
7
7
  */
8
8
 
9
- "use strict";var t=require("@lexical/utils"),e=require("lexical");const n=0,r=1,o=2,i=0,s=1,c=2,a=3,u=4;function d(t,n,r,o,d){if(null===t||0===r.size&&0===o.size&&!d)return i;const _=n._selection,l=t._selection;if(d)return s;if(!(e.$isRangeSelection(_)&&e.$isRangeSelection(l)&&l.isCollapsed()&&_.isCollapsed()))return i;const f=function(t,n,r){const o=t._nodeMap,i=[];for(const t of n){const e=o.get(t);void 0!==e&&i.push(e)}for(const[t,n]of r){if(!n)continue;const r=o.get(t);void 0===r||e.$isRootNode(r)||i.push(r)}return i}(n,r,o);if(0===f.length)return i;if(f.length>1){const r=n._nodeMap,o=r.get(_.anchor.key),s=r.get(l.anchor.key);return o&&s&&!t._nodeMap.has(o.__key)&&e.$isTextNode(o)&&1===o.__text.length&&1===_.anchor.offset?c:i}const O=f[0],C=t._nodeMap.get(O.__key);if(!e.$isTextNode(C)||!e.$isTextNode(O)||C.__mode!==O.__mode)return i;const p=C.__text,M=O.__text;if(p===M)return i;const N=_.anchor,g=l.anchor;if(N.key!==g.key||"text"!==N.type)return i;const S=N.offset,h=g.offset,m=M.length-p.length;return 1===m&&h===S-1?c:-1===m&&h===S+1?a:-1===m&&h===S?u:i}function _(t,s){let c=Date.now(),a=i;return(u,_,l,f,O,C)=>{const p=Date.now();if(C.has(e.HISTORIC_TAG))return a=i,c=p,o;const M=d(u,_,f,O,t.isComposing()),N=(()=>{const d=null===l||l.editor===t,N=C.has(e.HISTORY_PUSH_TAG);if(!N&&d&&C.has(e.HISTORY_MERGE_TAG))return n;if(null===u)return r;const g=_._selection;if(!(f.size>0||O.size>0))return null!==g?n:o;if(!1===N&&M!==i&&M===a&&p<c+s&&d)return n;if(1===f.size){if(function(t,n,r){const o=n._nodeMap.get(t),i=r._nodeMap.get(t),s=n._selection,c=r._selection;return!(e.$isRangeSelection(s)&&e.$isRangeSelection(c)&&"element"===s.anchor.type&&"element"===s.focus.type&&"text"===c.anchor.type&&"text"===c.focus.type||!e.$isTextNode(o)||!e.$isTextNode(i)||o.__parent!==i.__parent)&&JSON.stringify(n.read((()=>o.exportJSON())))===JSON.stringify(r.read((()=>i.exportJSON())))}(Array.from(f)[0],u,_))return n}return r})();return c=p,a=M,N}}function l(t){t.undoStack=[],t.redoStack=[],t.current=null}exports.createEmptyHistoryState=function(){return{current:null,redoStack:[],undoStack:[]}},exports.registerHistory=function(n,i,s){const c=_(n,s);return t.mergeRegister(n.registerCommand(e.UNDO_COMMAND,(()=>(function(t,n){const r=n.redoStack,o=n.undoStack;if(0!==o.length){const i=n.current,s=o.pop();null!==i&&(r.push(i),t.dispatchCommand(e.CAN_REDO_COMMAND,!0)),0===o.length&&t.dispatchCommand(e.CAN_UNDO_COMMAND,!1),n.current=s||null,s&&s.editor.setEditorState(s.editorState,{tag:e.HISTORIC_TAG})}}(n,i),!0)),e.COMMAND_PRIORITY_EDITOR),n.registerCommand(e.REDO_COMMAND,(()=>(function(t,n){const r=n.redoStack,o=n.undoStack;if(0!==r.length){const i=n.current;null!==i&&(o.push(i),t.dispatchCommand(e.CAN_UNDO_COMMAND,!0));const s=r.pop();0===r.length&&t.dispatchCommand(e.CAN_REDO_COMMAND,!1),n.current=s||null,s&&s.editor.setEditorState(s.editorState,{tag:e.HISTORIC_TAG})}}(n,i),!0)),e.COMMAND_PRIORITY_EDITOR),n.registerCommand(e.CLEAR_EDITOR_COMMAND,(()=>(l(i),!1)),e.COMMAND_PRIORITY_EDITOR),n.registerCommand(e.CLEAR_HISTORY_COMMAND,(()=>(l(i),n.dispatchCommand(e.CAN_REDO_COMMAND,!1),n.dispatchCommand(e.CAN_UNDO_COMMAND,!1),!0)),e.COMMAND_PRIORITY_EDITOR),n.registerUpdateListener((({editorState:t,prevEditorState:s,dirtyLeaves:a,dirtyElements:u,tags:d})=>{const _=i.current,l=i.redoStack,f=i.undoStack,O=null===_?null:_.editorState;if(null!==_&&t===O)return;const C=c(s,t,_,a,u,d);if(C===r)0!==l.length&&(i.redoStack=[],n.dispatchCommand(e.CAN_REDO_COMMAND,!1)),null!==_&&(f.push({..._}),n.dispatchCommand(e.CAN_UNDO_COMMAND,!0));else if(C===o)return;i.current={editor:n,editorState:t}})))};
9
+ "use strict";var e=require("@lexical/extension"),t=require("@lexical/utils"),n=require("lexical");const r=0,o=1,i=2,s=0,a=1,c=2,d=3,u=4;function l(e,t,r,o,i){if(null===e||0===r.size&&0===o.size&&!i)return s;const l=t._selection,_=e._selection;if(i)return a;if(!(n.$isRangeSelection(l)&&n.$isRangeSelection(_)&&_.isCollapsed()&&l.isCollapsed()))return s;const f=function(e,t,r){const o=e._nodeMap,i=[];for(const e of t){const t=o.get(e);void 0!==t&&i.push(t)}for(const[e,t]of r){if(!t)continue;const r=o.get(e);void 0===r||n.$isRootNode(r)||i.push(r)}return i}(t,r,o);if(0===f.length)return s;if(f.length>1){const r=t._nodeMap,o=r.get(l.anchor.key),i=r.get(_.anchor.key);return o&&i&&!e._nodeMap.has(o.__key)&&n.$isTextNode(o)&&1===o.__text.length&&1===l.anchor.offset?c:s}const p=f[0],h=e._nodeMap.get(p.__key);if(!n.$isTextNode(h)||!n.$isTextNode(p)||h.__mode!==p.__mode)return s;const O=h.__text,S=p.__text;if(O===S)return s;const C=l.anchor,y=_.anchor;if(C.key!==y.key||"text"!==C.type)return s;const g=C.offset,m=y.offset,M=S.length-O.length;return 1===M&&m===g-1?c:-1===M&&m===g+1?d:-1===M&&m===g?u:s}function _(e,t){let a=Date.now(),c=s;return(d,u,_,f,p,h)=>{const O=Date.now();if(h.has(n.HISTORIC_TAG))return c=s,a=O,i;const S=l(d,u,f,p,e.isComposing()),C=(()=>{const l=null===_||_.editor===e,C=h.has(n.HISTORY_PUSH_TAG);if(!C&&l&&h.has(n.HISTORY_MERGE_TAG))return r;if(null===d)return o;const y=u._selection;if(!(f.size>0||p.size>0))return null!==y?r:i;const g="number"==typeof t?t:t.peek();if(!1===C&&S!==s&&S===c&&O<a+g&&l)return r;if(1===f.size){if(function(e,t,r){const o=t._nodeMap.get(e),i=r._nodeMap.get(e),s=t._selection,a=r._selection;return!(n.$isRangeSelection(s)&&n.$isRangeSelection(a)&&"element"===s.anchor.type&&"element"===s.focus.type&&"text"===a.anchor.type&&"text"===a.focus.type||!n.$isTextNode(o)||!n.$isTextNode(i)||o.__parent!==i.__parent)&&JSON.stringify(t.read((()=>o.exportJSON())))===JSON.stringify(r.read((()=>i.exportJSON())))}(Array.from(f)[0],d,u))return r}return o})();return a=O,c=S,C}}function f(e){e.undoStack=[],e.redoStack=[],e.current=null}function p(e,r,s){const a=_(e,s),c=t.mergeRegister(e.registerCommand(n.UNDO_COMMAND,(()=>(function(e,t){const r=t.redoStack,o=t.undoStack;if(0!==o.length){const i=t.current,s=o.pop();null!==i&&(r.push(i),e.dispatchCommand(n.CAN_REDO_COMMAND,!0)),0===o.length&&e.dispatchCommand(n.CAN_UNDO_COMMAND,!1),t.current=s||null,s&&s.editor.setEditorState(s.editorState,{tag:n.HISTORIC_TAG})}}(e,r),!0)),n.COMMAND_PRIORITY_EDITOR),e.registerCommand(n.REDO_COMMAND,(()=>(function(e,t){const r=t.redoStack,o=t.undoStack;if(0!==r.length){const i=t.current;null!==i&&(o.push(i),e.dispatchCommand(n.CAN_UNDO_COMMAND,!0));const s=r.pop();0===r.length&&e.dispatchCommand(n.CAN_REDO_COMMAND,!1),t.current=s||null,s&&s.editor.setEditorState(s.editorState,{tag:n.HISTORIC_TAG})}}(e,r),!0)),n.COMMAND_PRIORITY_EDITOR),e.registerCommand(n.CLEAR_EDITOR_COMMAND,(()=>(f(r),!1)),n.COMMAND_PRIORITY_EDITOR),e.registerCommand(n.CLEAR_HISTORY_COMMAND,(()=>(f(r),e.dispatchCommand(n.CAN_REDO_COMMAND,!1),e.dispatchCommand(n.CAN_UNDO_COMMAND,!1),!0)),n.COMMAND_PRIORITY_EDITOR),e.registerUpdateListener((({editorState:t,prevEditorState:s,dirtyLeaves:c,dirtyElements:d,tags:u})=>{const l=r.current,_=r.redoStack,f=r.undoStack,p=null===l?null:l.editorState;if(null!==l&&t===p)return;const h=a(s,t,l,c,d,u);if(h===o)0!==_.length&&(r.redoStack=[],e.dispatchCommand(n.CAN_REDO_COMMAND,!1)),null!==l&&(f.push({...l}),e.dispatchCommand(n.CAN_UNDO_COMMAND,!0));else if(h===i)return;r.current={editor:e,editorState:t}})));return c}function h(){return{current:null,redoStack:[],undoStack:[]}}const O=n.defineExtension({build:(t,{delay:n,createInitialHistoryState:r,disabled:o})=>e.namedSignals({delay:n,disabled:o,historyState:r(t)}),config:n.safeCast({createInitialHistoryState:h,delay:300,disabled:"undefined"==typeof window}),name:"@lexical/history/History",register:(t,n,r)=>{const o=r.getOutput();return e.effect((()=>o.disabled.value?void 0:p(t,o.historyState.value,o.delay)))}});const S=n.defineExtension({dependencies:[n.configExtension(O,{createInitialHistoryState:()=>{throw new Error("SharedHistory did not inherit parent history")},disabled:!0})],name:"@lexical/history/SharedHistory",register(t,n,r){const{output:o}=r.getDependency(O),i=function(t){return t?e.getPeerDependencyFromEditor(t,O.name):null}(t._parentEditor);if(!i)return()=>{};const s=i.output;return e.effect((()=>e.batch((()=>{o.delay.value=s.delay.value,o.historyState.value=s.historyState.value,o.disabled.value=s.disabled.value}))))}});exports.HistoryExtension=O,exports.SharedHistoryExtension=S,exports.createEmptyHistoryState=h,exports.registerHistory=p;
@@ -6,4 +6,4 @@
6
6
  *
7
7
  */
8
8
 
9
- import{mergeRegister as t}from"@lexical/utils";import{UNDO_COMMAND as e,COMMAND_PRIORITY_EDITOR as n,REDO_COMMAND as r,CLEAR_EDITOR_COMMAND as o,CLEAR_HISTORY_COMMAND as i,CAN_REDO_COMMAND as c,CAN_UNDO_COMMAND as s,HISTORIC_TAG as a,HISTORY_PUSH_TAG as u,HISTORY_MERGE_TAG as d,$isRangeSelection as l,$isTextNode as f,$isRootNode as p}from"lexical";const m=0,h=1,_=2,g=0,S=1,k=2,y=3,C=4;function x(t,e,n,r,o){if(null===t||0===n.size&&0===r.size&&!o)return g;const i=e._selection,c=t._selection;if(o)return S;if(!(l(i)&&l(c)&&c.isCollapsed()&&i.isCollapsed()))return g;const s=function(t,e,n){const r=t._nodeMap,o=[];for(const t of e){const e=r.get(t);void 0!==e&&o.push(e)}for(const[t,e]of n){if(!e)continue;const n=r.get(t);void 0===n||p(n)||o.push(n)}return o}(e,n,r);if(0===s.length)return g;if(s.length>1){const n=e._nodeMap,r=n.get(i.anchor.key),o=n.get(c.anchor.key);return r&&o&&!t._nodeMap.has(r.__key)&&f(r)&&1===r.__text.length&&1===i.anchor.offset?k:g}const a=s[0],u=t._nodeMap.get(a.__key);if(!f(u)||!f(a)||u.__mode!==a.__mode)return g;const d=u.__text,m=a.__text;if(d===m)return g;const h=i.anchor,_=c.anchor;if(h.key!==_.key||"text"!==h.type)return g;const x=h.offset,M=_.offset,z=m.length-d.length;return 1===z&&M===x-1?k:-1===z&&M===x+1?y:-1===z&&M===x?C:g}function M(t,e){let n=Date.now(),r=g;return(o,i,c,s,p,S)=>{const k=Date.now();if(S.has(a))return r=g,n=k,_;const y=x(o,i,s,p,t.isComposing()),C=(()=>{const a=null===c||c.editor===t,C=S.has(u);if(!C&&a&&S.has(d))return m;if(null===o)return h;const x=i._selection;if(!(s.size>0||p.size>0))return null!==x?m:_;if(!1===C&&y!==g&&y===r&&k<n+e&&a)return m;if(1===s.size){if(function(t,e,n){const r=e._nodeMap.get(t),o=n._nodeMap.get(t),i=e._selection,c=n._selection;return!(l(i)&&l(c)&&"element"===i.anchor.type&&"element"===i.focus.type&&"text"===c.anchor.type&&"text"===c.focus.type||!f(r)||!f(o)||r.__parent!==o.__parent)&&JSON.stringify(e.read((()=>r.exportJSON())))===JSON.stringify(n.read((()=>o.exportJSON())))}(Array.from(s)[0],o,i))return m}return h})();return n=k,r=y,C}}function z(t){t.undoStack=[],t.redoStack=[],t.current=null}function v(u,d,l){const f=M(u,l),p=t(u.registerCommand(e,(()=>(function(t,e){const n=e.redoStack,r=e.undoStack;if(0!==r.length){const o=e.current,i=r.pop();null!==o&&(n.push(o),t.dispatchCommand(c,!0)),0===r.length&&t.dispatchCommand(s,!1),e.current=i||null,i&&i.editor.setEditorState(i.editorState,{tag:a})}}(u,d),!0)),n),u.registerCommand(r,(()=>(function(t,e){const n=e.redoStack,r=e.undoStack;if(0!==n.length){const o=e.current;null!==o&&(r.push(o),t.dispatchCommand(s,!0));const i=n.pop();0===n.length&&t.dispatchCommand(c,!1),e.current=i||null,i&&i.editor.setEditorState(i.editorState,{tag:a})}}(u,d),!0)),n),u.registerCommand(o,(()=>(z(d),!1)),n),u.registerCommand(i,(()=>(z(d),u.dispatchCommand(c,!1),u.dispatchCommand(s,!1),!0)),n),u.registerUpdateListener((({editorState:t,prevEditorState:e,dirtyLeaves:n,dirtyElements:r,tags:o})=>{const i=d.current,a=d.redoStack,l=d.undoStack,p=null===i?null:i.editorState;if(null!==i&&t===p)return;const m=f(e,t,i,n,r,o);if(m===h)0!==a.length&&(d.redoStack=[],u.dispatchCommand(c,!1)),null!==i&&(l.push({...i}),u.dispatchCommand(s,!0));else if(m===_)return;d.current={editor:u,editorState:t}})));return p}function E(){return{current:null,redoStack:[],undoStack:[]}}export{E as createEmptyHistoryState,v as registerHistory};
9
+ import{namedSignals as t,effect as e,batch as n,getPeerDependencyFromEditor as r}from"@lexical/extension";import{mergeRegister as o}from"@lexical/utils";import{defineExtension as i,safeCast as a,configExtension as s,UNDO_COMMAND as c,COMMAND_PRIORITY_EDITOR as d,REDO_COMMAND as u,CLEAR_EDITOR_COMMAND as l,CLEAR_HISTORY_COMMAND as f,CAN_REDO_COMMAND as p,CAN_UNDO_COMMAND as h,HISTORIC_TAG as m,HISTORY_PUSH_TAG as y,HISTORY_MERGE_TAG as g,$isRangeSelection as S,$isTextNode as _,$isRootNode as k}from"lexical";const x=0,C=1,v=2,b=0,w=1,E=2,H=3,M=4;function z(t,e,n,r,o){if(null===t||0===n.size&&0===r.size&&!o)return b;const i=e._selection,a=t._selection;if(o)return w;if(!(S(i)&&S(a)&&a.isCollapsed()&&i.isCollapsed()))return b;const s=function(t,e,n){const r=t._nodeMap,o=[];for(const t of e){const e=r.get(t);void 0!==e&&o.push(e)}for(const[t,e]of n){if(!e)continue;const n=r.get(t);void 0===n||k(n)||o.push(n)}return o}(e,n,r);if(0===s.length)return b;if(s.length>1){const n=e._nodeMap,r=n.get(i.anchor.key),o=n.get(a.anchor.key);return r&&o&&!t._nodeMap.has(r.__key)&&_(r)&&1===r.__text.length&&1===i.anchor.offset?E:b}const c=s[0],d=t._nodeMap.get(c.__key);if(!_(d)||!_(c)||d.__mode!==c.__mode)return b;const u=d.__text,l=c.__text;if(u===l)return b;const f=i.anchor,p=a.anchor;if(f.key!==p.key||"text"!==f.type)return b;const h=f.offset,m=p.offset,y=l.length-u.length;return 1===y&&m===h-1?E:-1===y&&m===h+1?H:-1===y&&m===h?M:b}function O(t,e){let n=Date.now(),r=b;return(o,i,a,s,c,d)=>{const u=Date.now();if(d.has(m))return r=b,n=u,v;const l=z(o,i,s,c,t.isComposing()),f=(()=>{const f=null===a||a.editor===t,p=d.has(y);if(!p&&f&&d.has(g))return x;if(null===o)return C;const h=i._selection;if(!(s.size>0||c.size>0))return null!==h?x:v;const m="number"==typeof e?e:e.peek();if(!1===p&&l!==b&&l===r&&u<n+m&&f)return x;if(1===s.size){if(function(t,e,n){const r=e._nodeMap.get(t),o=n._nodeMap.get(t),i=e._selection,a=n._selection;return!(S(i)&&S(a)&&"element"===i.anchor.type&&"element"===i.focus.type&&"text"===a.anchor.type&&"text"===a.focus.type||!_(r)||!_(o)||r.__parent!==o.__parent)&&JSON.stringify(e.read((()=>r.exportJSON())))===JSON.stringify(n.read((()=>o.exportJSON())))}(Array.from(s)[0],o,i))return x}return C})();return n=u,r=l,f}}function J(t){t.undoStack=[],t.redoStack=[],t.current=null}function N(t,e,n){const r=O(t,n),i=o(t.registerCommand(c,(()=>(function(t,e){const n=e.redoStack,r=e.undoStack;if(0!==r.length){const o=e.current,i=r.pop();null!==o&&(n.push(o),t.dispatchCommand(p,!0)),0===r.length&&t.dispatchCommand(h,!1),e.current=i||null,i&&i.editor.setEditorState(i.editorState,{tag:m})}}(t,e),!0)),d),t.registerCommand(u,(()=>(function(t,e){const n=e.redoStack,r=e.undoStack;if(0!==n.length){const o=e.current;null!==o&&(r.push(o),t.dispatchCommand(h,!0));const i=n.pop();0===n.length&&t.dispatchCommand(p,!1),e.current=i||null,i&&i.editor.setEditorState(i.editorState,{tag:m})}}(t,e),!0)),d),t.registerCommand(l,(()=>(J(e),!1)),d),t.registerCommand(f,(()=>(J(e),t.dispatchCommand(p,!1),t.dispatchCommand(h,!1),!0)),d),t.registerUpdateListener((({editorState:n,prevEditorState:o,dirtyLeaves:i,dirtyElements:a,tags:s})=>{const c=e.current,d=e.redoStack,u=e.undoStack,l=null===c?null:c.editorState;if(null!==c&&n===l)return;const f=r(o,n,c,i,a,s);if(f===C)0!==d.length&&(e.redoStack=[],t.dispatchCommand(p,!1)),null!==c&&(u.push({...c}),t.dispatchCommand(h,!0));else if(f===v)return;e.current={editor:t,editorState:n}})));return i}function D(){return{current:null,redoStack:[],undoStack:[]}}const I=i({build:(e,{delay:n,createInitialHistoryState:r,disabled:o})=>t({delay:n,disabled:o,historyState:r(e)}),config:a({createInitialHistoryState:D,delay:300,disabled:"undefined"==typeof window}),name:"@lexical/history/History",register:(t,n,r)=>{const o=r.getOutput();return e((()=>o.disabled.value?void 0:N(t,o.historyState.value,o.delay)))}});const L=i({dependencies:[s(I,{createInitialHistoryState:()=>{throw new Error("SharedHistory did not inherit parent history")},disabled:!0})],name:"@lexical/history/SharedHistory",register(t,o,i){const{output:a}=i.getDependency(I),s=function(t){return t?r(t,I.name):null}(t._parentEditor);if(!s)return()=>{};const c=s.output;return e((()=>n((()=>{a.delay.value=c.delay.value,a.historyState.value=c.historyState.value,a.disabled.value=c.disabled.value}))))}});export{I as HistoryExtension,L as SharedHistoryExtension,D as createEmptyHistoryState,N as registerHistory};
package/index.d.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  *
7
7
  */
8
8
  import type { EditorState, LexicalEditor } from 'lexical';
9
+ import { ReadonlySignal } from '@lexical/extension';
9
10
  export type HistoryStateEntry = {
10
11
  editor: LexicalEditor;
11
12
  editorState: EditorState;
@@ -24,9 +25,39 @@ export type HistoryState = {
24
25
  * instead of merging the current changes with the current stack.
25
26
  * @returns The listeners cleanup callback function.
26
27
  */
27
- export declare function registerHistory(editor: LexicalEditor, historyState: HistoryState, delay: number): () => void;
28
+ export declare function registerHistory(editor: LexicalEditor, historyState: HistoryState, delay: number | ReadonlySignal<number>): () => void;
28
29
  /**
29
30
  * Creates an empty history state.
30
31
  * @returns - The empty history state, as an object.
31
32
  */
32
33
  export declare function createEmptyHistoryState(): HistoryState;
34
+ export interface HistoryConfig {
35
+ /**
36
+ * The time (in milliseconds) the editor should delay generating a new history stack,
37
+ * instead of merging the current changes with the current stack. The default is 300ms.
38
+ */
39
+ delay: number;
40
+ /**
41
+ * The initial history state, the default is {@link createEmptyHistoryState}.
42
+ */
43
+ createInitialHistoryState: (editor: LexicalEditor) => HistoryState;
44
+ /**
45
+ * Whether history is disabled or not
46
+ */
47
+ disabled: boolean;
48
+ }
49
+ /**
50
+ * Registers necessary listeners to manage undo/redo history stack and related
51
+ * editor commands, via the \@lexical/history module.
52
+ */
53
+ export declare const HistoryExtension: import("lexical").LexicalExtension<HistoryConfig, "@lexical/history/History", import("@lexical/extension").NamedSignalsOutput<{
54
+ delay: number;
55
+ disabled: boolean;
56
+ historyState: HistoryState;
57
+ }>, unknown>;
58
+ /**
59
+ * Registers necessary listeners to manage undo/redo history stack and related
60
+ * editor commands, via the \@lexical/history module, only if the parent editor
61
+ * has a history plugin implementation.
62
+ */
63
+ export declare const SharedHistoryExtension: import("lexical").LexicalExtension<import("lexical").ExtensionConfigBase, "@lexical/history/SharedHistory", unknown, unknown>;
package/package.json CHANGED
@@ -8,12 +8,13 @@
8
8
  "history"
9
9
  ],
10
10
  "license": "MIT",
11
- "version": "0.35.1-nightly.20250924.0",
11
+ "version": "0.36.0",
12
12
  "main": "LexicalHistory.js",
13
13
  "types": "index.d.ts",
14
14
  "dependencies": {
15
- "@lexical/utils": "0.35.1-nightly.20250924.0",
16
- "lexical": "0.35.1-nightly.20250924.0"
15
+ "@lexical/extension": "0.36.0",
16
+ "@lexical/utils": "0.36.0",
17
+ "lexical": "0.36.0"
17
18
  },
18
19
  "repository": {
19
20
  "type": "git",