hyper-undo 0.7.0 → 0.8.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # hyper-undo changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ ### Added
6
+ - `refused: 'skip'` scope option: one `undo()` or `redo()` press removes each entry that preflight or apply refuses (every code), emits a `skipped` event carrying the entry's plain-data description, and goes on to the next entry until one applies or the stack is empty. The receipt gains a `skipped` list, and the default (`null`) keeps a refused entry on top as before.
7
+ - `skipped` event: fired once per entry a `refused: 'skip'` press removes.
8
+ - `trackContent(root, { read, write, prop })`: a field's content is recorded as one guarded value step, its saved HTML before and after, sampled from the changes inside the root instead of the raw text and node steps those changes would otherwise leave. Returns a release function, and `stop()` forgets every tracked root.
9
+ - `durableForm` scope option: a host gives a node a stable saved form, used instead of its live markup when certifying and replaying steps
10
+ - `editableKeys: 'page'` scope option: in editable content, Cmd+Z, Cmd+Shift+Z, Ctrl+Y and the browser's own `beforeinput` `historyUndo`/`historyRedo` go to the page history instead of the browser's per-field undo. Form controls, IME compositions, the `shadowKeydownIn` editors and regions the scope does not record keep their own undo, and the default leaves every key with the browser.
11
+ - `ownKeysIn` option: selectors whose history keys belong to the page even inside a `shadowKeydownIn` editor.
12
+ - `holdReplay` option: a consumer can hold undo and redo, which then return `{ ok: false, code: 'held' }` without refusing the entry, touching a stack or changing the document.
13
+ - `typingBreak: 'sentence'` scope option: an undo press undoes one sentence of typing. A step closes after the space or line break that follows `.`, `?` or `!`, at a field switch, at a switch between typing and deleting, after a paste, a drop, a cut or a format command, when a selection is replaced, and at a caret jump made with the mouse or the navigation keys. An open IME composition never lets the idle timer close a step, on every scope.
14
+ - `endsSentence(textBefore)`: the sentence rule as a predicate, for a host that groups typing the same way.
15
+ - A successful `undo()` or `redo()` receipt gains `caret`, where the applied entry changed text: `{ node, offset }` for a text node or an added or removed one, and `{ root, textOffset }` for a tracked content root. The key is present only when the applied entry changed text; a refused press carries no `caret`. A press that skips entries and then applies one reports that entry's `caret`. The engine never touches the selection.
16
+
17
+ ### Fixed
18
+ - Changes inside a subtree removed from a `no-undo` region no longer leave a history entry
19
+ - An entry description shows a node's durable form as text, not as an internal token
20
+
3
21
  ## [0.6.4] - 2026-10-15
4
22
 
5
23
  ### Changed
@@ -19,6 +37,11 @@
19
37
 
20
38
  ## [Unreleased]
21
39
 
40
+ ## [0.7.1] - 2026-10-30
41
+
42
+ ### Fixed
43
+ - Undo and redo keep changes made inside a subtree that an edit removes: a child moved out of a column that is then removed returns to the column on undo and leaves again on redo.
44
+
22
45
  ## [0.7.0] - 2026-10-30
23
46
 
24
47
  ### Added
package/README.md CHANGED
@@ -66,12 +66,13 @@ the box.
66
66
  | `undo.discardCaptured()` | drain and throw away the captured records (failure path companion) |
67
67
  | `undo.flush()` | force-close the current idle batch as its own commit |
68
68
  | `undo.command(label, fn)` | run a synchronous `fn` and push only its own writes as one labelled entry; returns `{ id, label }`, or `null` when it wrote nothing |
69
+ | `undo.trackContent(root, { read, write, prop })` | record `root`'s content as one guarded value step: `read(root)` is sampled when a mutation lands inside the root and `write(root, html)` replays a step, so the inside of a tracked root is never recorded as raw text or node steps. Returns a release function; `stop()` forgets every tracked root. `prop` defaults to `'content'` |
69
70
  | `undo.setRecording(mode)` | `'automatic'` (default) or `'commands'`; see [Recording modes](#recording-modes) |
70
- | `undo.undo()` / `undo.redo()` | navigate history; each returns a receipt, `{ ok: true, entryId, label, direction }` or `{ ok: false, code, entryId, label, direction }`. `undo({ entryId })` and `redo({ entryId })` replay only while that entry is the next one, and refuse `stale-entry` otherwise |
71
+ | `undo.undo()` / `undo.redo()` | navigate history; each returns a receipt, `{ ok: true, entryId, label, direction, skipped, caret }` or `{ ok: false, code, entryId, label, direction }`. `skipped` is the list of skip records from this call and is present only when something was skipped, and a press that only skipped returns `{ ok: false, code: 'empty', direction, skipped }`. `caret` says where the applied entry changed text (see [Where the text changed](#where-the-text-changed)); it is present only when the applied entry changed text. `undo({ entryId })` and `redo({ entryId })` replay only while that entry is the next one, refuse `stale-entry` otherwise, and never skip |
71
72
  | `undo.discard(entryId)` | drop the refused top entry, and only that one: `{ ok: true, entryId, direction }`, or `{ ok: false, code: 'not-refused' }` |
72
73
  | `undo.clear()` | clear both stacks |
73
74
  | `undo.pause()` / `undo.resume()` | recorder skips while paused |
74
- | `undo.on('undo'\|'redo'\|'commit'\|'refused'\|'discard'\|'clear', fn)` / `undo.off(...)` | subscribe to lifecycle events; `undo`/`redo` fire after a navigate with the receipt, `refused` with `{ entryId, label, direction, code, targets }`, `commit` after a new commit, `discard` with `{ entryId, label, direction }`, `clear` after a reset. (No generic `change` event.) |
75
+ | `undo.on('undo'\|'redo'\|'commit'\|'refused'\|'skipped'\|'discard'\|'clear', fn)` / `undo.off(...)` | subscribe to lifecycle events; `undo`/`redo` fire after a navigate with the receipt, `refused` with `{ entryId, label, direction, code, targets }`, `skipped` with `{ entryId, label, direction, code, targets, description }`, `commit` after a new commit, `discard` with `{ entryId, label, direction }`, `clear` after a reset. (No generic `change` event.) |
75
76
  | `undo.canUndo` / `undo.canRedo` | booleans (getters) |
76
77
  | `undo.history` | `[{ id, label, timestamp }, ...]`, oldest first; `timestamp` is `Date.now()` millis. The entry that was just refused also carries `refused: { direction, code, targets }` |
77
78
  | `undo.future` | the redo stack in the same shape, next redo first |
@@ -90,9 +91,15 @@ the box.
90
91
  | `idleLabel` | `'Edit'` | label for auto-closed batches |
91
92
  | `bindKeys` | `true` (singleton), `false` (`create`) | install the global Cmd+Z handler |
92
93
  | `shadowKeydownIn` | code-editor selectors (see below) | when `event.target.closest(selector)` matches, the global handler bails without `preventDefault` |
94
+ | `editableKeys` | `'native'` | how the history keys and the browser's own history input event are routed inside editable content. `'native'` leaves every `contenteditable` (and the `shadowKeydownIn` list) its own undo. `'page'` sends Cmd+Z, Cmd+Shift+Z, Ctrl+Y and a `beforeinput` `historyUndo`/`historyRedo` to the page history when the target sits inside a tracked content root or matches `ownKeysIn`; a form control, the `shadowKeydownIn` list and an editing host the scope does not record keep their own undo. Only then is `beforeinput` listened to at all |
95
+ | `ownKeysIn` | `null` | selectors whose history keys and history input events belong to the page stack under `editableKeys: 'page'`, even when the element also matches `shadowKeydownIn` (a block editor sharing its element with `.ProseMirror`) |
96
+ | `typingBreak` | `null` | `'sentence'` closes the open typing step after the space or line break that follows `.`, `?` or `!` (the delimiter belongs to the finished sentence), at a switch to another field, at a switch between typing and deleting, after a paste, a drop, a cut or a format command, when a selection is replaced, and at a caret jump made with the mouse or a navigation key. So one undo press undoes one sentence of typing. On every scope an open IME composition holds the idle step open |
97
+ | `holdReplay` | `null` | function `() => boolean`; while it answers true, `undo()` and `redo()` return `{ ok: false, code: 'held' }` without flushing, moving either stack, changing the document or emitting `refused` |
98
+ | `refused` | `null` | `'skip'` lets one `undo()` or `redo()` press get past a step it can no longer replay: the refused entry is removed from its stack (it goes to no other stack), announced with a `skipped` event, and the same call goes on to the next entry until one applies or the stack is empty. Every refusal code is skipped, `replay-error` included, but `undo({ entryId })` never skips. The default keeps a refused entry on top. See [Refusals](#refusals) |
93
99
  | `ignoreAttribute` | `null` | predicate `(attrName, element) => boolean`; return true to skip recording that attribute mutation, and the certificate's projection skips it too, so such a change never refuses a later undo or redo. |
94
100
  | `isProtected` | `null` | predicate `(node) => boolean`; return true for content that no undo or redo may erase, and an operation that would remove or replace a subtree containing such a node is refused with code `"protected"`. |
95
101
  | `ignoreNode` | `null` | predicate `(node) => boolean`; in automatic mode a `childList` record whose every added and removed node it accepts is not recorded, so a gesture's own repeated moves leave no generic entry beside the one the consumer records with `command`, and such a node is left out of a bracketed entry's added and removed lists too. |
102
+ | `durableForm` | `null` | function `(node, host) => string \| undefined`; return a string for a node whose live markup is not its saved markup (a mounted rich text editor), and the certificate uses that string as the node's whole form instead of looking inside it, at record time and at every replay check. Return `undefined` to keep the default form. A throw or a non-string also keeps the default. |
96
103
  | `debug` | `false` | console.log internal state transitions |
97
104
 
98
105
  ## Batching
@@ -141,6 +148,39 @@ undo.undo() // { ok: true, entryId, label, direction }
141
148
 
142
149
  A refused entry keeps its place on top, and `undo.history` (or `undo.future`) shows `refused: { direction, code, targets }` on it, so nothing is lost and nothing is silently skipped. `undo.discard(entryId)` drops exactly that entry and leaves the document and every other entry as they are.
143
150
 
151
+ ### Skipping what can no longer be replayed
152
+
153
+ By default a refused entry keeps its place on top, so every later press refuses it again until it is dismissed. With `refused: 'skip'` one press removes it instead and goes on:
154
+
155
+ ```js
156
+ const undo = hyperundo.create({ refused: 'skip' })
157
+ undo.on('skipped', ({ entryId, label, direction, code, targets, description }) => keepCopy(description))
158
+
159
+ undo.undo()
160
+ // { ok: true, entryId: 'A', label: 'Edit A', direction: 'undo',
161
+ // skipped: [{ entryId: 'C', label: 'Edit C', direction: 'undo', code: 'content-changed',
162
+ // targets: [...], description: { id: 'C', label: 'Edit C', ... } }] }
163
+ ```
164
+
165
+ The press pops each refused entry, emits one `skipped` event for it and continues to the next entry in the same call, until one applies or the stack is empty (`{ ok: false, code: 'empty', direction, skipped }`). A skipped entry goes to no other stack and emits no `refused` event. Its `description` is the plain-data `describe(entryId)` of the entry, built before it is removed, so a consumer can keep a recovery copy after the fact. `undo({ entryId })` never skips: a named entry is refused as it is today.
166
+
167
+ ### Where the text changed
168
+
169
+ A successful receipt carries `caret`, taken from the last operation of the replay that changed text, so a host can put the caret where the removed or restored text was. The key is present only when the applied entry changed text:
170
+
171
+ | The entry changed | `caret` |
172
+ |---|---|
173
+ | a text node | `{ node, offset }`, at the end of the changed run of its data |
174
+ | a tracked content root (`trackContent`) | `{ root, textOffset }`, at the end of the changed run of `root.textContent` |
175
+ | added or removed a text node | `{ node, offset }`: the parent at the node's index, or the node at its length |
176
+ | a value step with a `write` and no `content` flag, an attribute, a node that is not text | no `caret` key |
177
+
178
+ ```js
179
+ undo.undo() // { ok: true, entryId, label, direction, skipped, caret: { node, offset: 5 } }
180
+ ```
181
+
182
+ The engine never reads or writes the selection; placing the caret is the host's job. A refused or skipped press reports no `caret`, and when one press skips entries and then applies one, the `caret` is the applied entry's.
183
+
144
184
  `targets` is one `{ id, kind }` per node the refused step addresses. `id` is the nearest `[data-id]` ancestor, so a text step with no id of its own names the record it was typed in, and `null` when nothing in the ancestor chain carries one; `kind` says what the target was to the step (`added`, `removed`, `move`, `protected`, or the attribute or property name of a value step). The receipt's own `targets` are on the `refused` event and the history entry, so a consumer can name the record a refusal is about without asking the engine again.
145
185
 
146
186
  ## Describing an entry
@@ -198,6 +238,32 @@ records nothing: the page's Cmd+Z history starts at the write a commit or a
198
238
  `command` makes of that text. Pass `bindKeys: false` to opt out entirely and
199
239
  bind your own handler.
200
240
 
241
+ ### One undo press, one sentence of typing
242
+
243
+ `typingBreak: 'sentence'` groups typing into sentences instead of into half
244
+ second batches. A step closes after the space or line break that follows `.`,
245
+ `?` or `!`, so the space belongs to the finished sentence; the rule is simple on
246
+ purpose, so `e.g. ` ends a step early and `3.5` does not. It also closes at a
247
+ switch to another field, at a switch between typing and deleting, after a paste,
248
+ a drop, a cut or a format command (each is a step of its own), when a selection
249
+ is replaced, and at a caret jump made with the mouse or with the navigation
250
+ keys. An open IME composition never lets the idle timer close a step, with or
251
+ without the option.
252
+
253
+ `endsSentence(textBefore)` is exported for a host that needs the same rule.
254
+
255
+ ### Editable content can share the page history
256
+
257
+ `editableKeys: 'page'` gives `contenteditable` fields the page's timeline. A key
258
+ or the browser's own Undo (`beforeinput` `historyUndo`) inside a plain field, a
259
+ tracked rich field, or an element named by `ownKeysIn` calls `undo()` or
260
+ `redo()`; the event is prevented, so the browser's per-field undo never runs and
261
+ the two histories cannot drift. An `input`, a `textarea`, a `select`, an open
262
+ IME composition, the `shadowKeydownIn` list, and an editing host inside a
263
+ region the scope does not record (an authored `no-undo` field) keep their own
264
+ undo. An empty page history still prevents the key: the field's own undo would
265
+ change text the page history does not know about.
266
+
201
267
  ## Filter attributes
202
268
 
203
269
  A mutation is excluded from recording when its target's ancestor chain contains
@@ -1 +1 @@
1
- var hyperundo=(()=>{var J=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var ft=Object.getOwnPropertyNames;var mt=Object.prototype.hasOwnProperty;var pt=(e,n)=>{for(var t in n)J(e,t,{get:n[t],enumerable:!0})},gt=(e,n,t,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of ft(n))!mt.call(e,i)&&i!==t&&J(e,i,{get:()=>n[i],enumerable:!(r=ct(n,i))||r.enumerable});return e};var ht=e=>gt(J({},"__esModule",{value:!0}),e);var Yt={};pt(Yt,{default:()=>Gt,undo:()=>ne});function yt(e,n=null){let t=[];if(e.type==="attributes"){let r=e.target,i=e.attributeName,a=e.oldValue,l=r.getAttribute(i);return a==null&&l!=null?t.push({kind:"attr-add",target:r,name:i,newValue:l}):a!=null&&l==null?t.push({kind:"attr-remove",target:r,name:i,oldValue:a}):a!==l&&t.push({kind:"attr-set",target:r,name:i,oldValue:a,newValue:l}),t}if(e.type==="characterData")return t.push({kind:"text",target:e.target,oldValue:e.oldValue,newValue:e.target.data}),t;if(e.type==="childList"){let r=e.target,i=e.nextSibling,a=e.nextSibling;for(;a&&n?.(a);)a=a.nextSibling;let l=e.previousSibling;for(;l&&n?.(l);)l=l.previousSibling;let s=n?Array.from(e.addedNodes).filter(g=>!n(g)):Array.from(e.addedNodes),d=n?Array.from(e.removedNodes).filter(g=>!n(g)):Array.from(e.removedNodes);return s.length>0&&t.push({kind:"add",parent:r,nodes:s,before:i,afterAuthored:a,beforeAuthored:l,record:e}),d.length>0&&t.push({kind:"remove",parent:r,nodes:d,before:i,afterAuthored:a,beforeAuthored:l,record:e}),t}return t}function ve(e,n=null){let t=[],r=new Map;for(let i of e){if(i.type==="attributes"){let a=i.target,l=i.attributeName,s=r.get(a);s||(s=new Map,r.set(a,s)),s.has(l)||(s.set(l,{idx:t.length,oldValue:i.oldValue}),t.push(null));continue}for(let a of yt(i,n))t.push(a)}for(let[i,a]of r)for(let[l,s]of a){let d=s.oldValue,g=i.getAttribute(l),p=null;d===g?p=null:d==null?p={kind:"attr-add",target:i,name:l,newValue:g}:g==null?p={kind:"attr-remove",target:i,name:l,oldValue:d}:p={kind:"attr-set",target:i,name:l,oldValue:d,newValue:g},t[s.idx]=p}return t.filter(i=>i!=null)}function Ae(e){let n=[],t=new Map;for(let i of e){let a=we(i);if(a==null){n.push(i);continue}let l=t.get(i.target);l||(l=new Map,t.set(i.target,l));let s=l.get(a);if(s==null){let d=ke(i);if(d.oldValue===d.newValue)continue;l.set(a,n.length),n.push({...i,...d})}else n[s]={...n[s],newValue:ke(i).newValue}}let r=[];for(let i of n){if(we(i)==null){r.push(i);continue}i.oldValue!==i.newValue&&r.push(wt(i))}return r}var bt=new Set(["attr-set","attr-add","attr-remove","text","value"]);function we(e){return bt.has(e.kind)?e.kind==="text"?"#text":e.kind==="value"?`#${e.prop||"value"}`:e.name==null?null:`@${e.name}`:null}function ke(e){return e.kind==="attr-add"?{oldValue:null,newValue:e.newValue}:e.kind==="attr-remove"?{oldValue:e.oldValue,newValue:null}:{oldValue:e.oldValue,newValue:e.newValue}}function wt(e){return e.kind!=="attr-add"&&e.kind!=="attr-remove"?e:e.oldValue==null&&e.newValue!=null?{...e,kind:"attr-add"}:e.oldValue!=null&&e.newValue==null?{...e,kind:"attr-remove"}:{...e,kind:"attr-set"}}var Ne=new WeakMap,kt=0;function T(e){let n=Ne.get(e);return n||(n=`n${++kt}`,Ne.set(e,n)),n}function v(e){return!!e&&typeof e=="object"&&typeof e.nodeType=="number"}function vt(e){return e.kind==="add"||e.kind==="remove"}function Se(e,n){let t=[],r=e.childNodes;if(!r)return t;for(let i of r)n&&n(i)||t.push(T(i));return t}function z(e,n,t=null,r=null){if(!v(e))return null;if(e.nodeType===3)return`#text:${JSON.stringify(e.data)}`;if(e.nodeType===8)return`#comment:${JSON.stringify(e.data)}`;if(e.nodeType!==1)return`#node:${e.nodeType}`;let i=[];if(e.attributes){for(let s of e.attributes)At(s.name,e,n,t)||i.push(`${s.name}=${JSON.stringify(s.value)}`);i.sort()}let a=[];if(e.childNodes)for(let s of e.childNodes)Nt(s,r)||a.push(z(s,n,t,r));return`<${String(e.tagName||"").toLowerCase()}${i.length?` ${i.join(" ")}`:""}>${a.join("")}</>`}function G(e,n=[]){if(!v(e))return n;if(e.nodeType===1){let t=e.getAttribute&&e.getAttribute("data-id");t&&n.push(t)}if(e.childNodes)for(let t of e.childNodes)G(t,n);return n}function At(e,n,t,r=null){if(typeof t!="function")return!1;try{return!!t(e,n,r)}catch{return!1}}function Nt(e,n){if(typeof n!="function")return!1;try{return!!n(e)}catch{return!1}}function Te(e,n){if(typeof n!="function")return[];let t=[],r=i=>{if(!v(i))return;let a=!1;try{a=!!n(i)}catch{a=!1}if(a&&t.push(E(i,"protected")),i.childNodes)for(let l of i.childNodes)r(l)};for(let i of e)r(i);return t}function E(e,n,t=null){let r=e;r&&r.nodeType!==1&&(r=r.parentElement);let i=r&&typeof r.closest=="function"?r.closest("[data-id]"):null;return!i&&t&&typeof t.closest=="function"&&(i=t.closest("[data-id]")),{id:(i?i.getAttribute("data-id"):null)||null,kind:n||null}}function Et(e,n,t=null){return(e||[]).filter(v).map(r=>E(r,n,t))}function q(e){return{replayable:!1,reason:e,steps:[]}}function D(e,n){let t=[[n.afterAuthored,i=>i],[n.beforeAuthored,i=>i+1],[n.before,i=>i]],r=!1;for(let[i,a]of t){if(!v(i))continue;r=!0;let l=e.indexOf(T(i));if(l>=0)return a(l)}return r?null:e.length}function Ve(e,n={}){let t=n.isIgnored||null,r=n.ignoreAttribute||null,i=Ae(e),a=[];for(let p of i){if(!vt(p)){if(!v(p.target))return q("non-dom-target");continue}if(!v(p.parent))return q("non-dom-parent");let h=Array.from(p.nodes||[]).filter(v);if(h.length!==0){if(h.length!==Array.from(p.nodes||[]).length)return q("non-dom-node");a.push({primitive:p,nodes:h,parent:p.parent})}}if(St(a))return q("in-record-move");let l=Tt(a,t);if(!l)return q("ambiguous-structure");let s=Vt(a,l),d=new Map(a.map(p=>[p.primitive,p])),g=[];for(let p of i){let h=d.get(p);if(!h){g.push(Pt(p));continue}let w=s.get(h);if(w){w.at===h&&g.push(w.step);continue}g.push(It(h,l.get(h),r,t))}return{replayable:!0,reason:null,steps:g}}function St(e){let n=new Map;for(let t of e){let r=t.primitive.record;if(!r)continue;let i=n.get(r);i||(i=new Map,n.set(r,i));for(let a of t.nodes){let l=i.get(a);l||(l=new Set,i.set(a,l)),l.add(t.primitive.kind)}}for(let t of n.values())for(let r of t.values())if(r.size>1)return!0;return!1}function Tt(e,n){let t=new Map;for(let i of e)t.has(i.parent)||t.set(i.parent,Se(i.parent,n));let r=new Map;for(let i=e.length-1;i>=0;i--){let a=e[i],l=t.get(a.parent);if(!l)return null;let s=l.slice(),d;if(a.primitive.kind==="add"){let g=a.nodes.map(T);if(!g.every(p=>l.includes(p)))return null;d=l.filter(p=>!g.includes(p))}else{let g=D(s,a.primitive);if(g==null)return null;d=s.slice(),d.splice(g,0,...a.nodes.map(T))}r.set(a,{before:d,after:s}),t.set(a.parent,d)}return r}function Vt(e,n){let t=new Map,r=new Map;e.forEach((a,l)=>{for(let s of a.nodes){let d=T(s);a.primitive.kind==="remove"?t.set(d,{item:a,index:l,node:s}):r.set(d,{item:a,index:l,node:s})}});let i=new Map;for(let[a,l]of t){let s=r.get(a);if(!s||s.index<l.index||l.item.nodes.length!==1||s.item.nodes.length!==1)continue;let d={type:"move",node:l.node,sourceParent:l.item.parent,destParent:s.item.parent,source:n.get(l.item),dest:n.get(s.item),sourceSlot:l.item.primitive,destSlot:s.item.primitive,targets:[E(l.node,"move")]};i.set(l.item,{step:d,at:s.item}),i.set(s.item,{step:d,at:s.item})}return i}function It(e,n,t,r){let i=e.primitive.kind;return{type:i==="add"?"add":"restore",parent:e.parent,nodes:e.nodes,seqBefore:n.before,seqAfter:n.after,slot:e.primitive,content:e.nodes.map(a=>z(a,t,e.parent,r)),ids:i==="remove"?e.nodes.flatMap(a=>G(a)):[],targets:Et(e.nodes,i==="add"?"added":"removed",e.parent)}}function Pt(e){return{type:e.kind,primitive:e,targets:[E(e.target,e.name||e.prop||"text")]}}function Ie(e,n,t={}){if(!e||!e.replayable)return{ok:!1,code:"unsupported",targets:[]};let r={isIgnored:t.isIgnored||null,ignoreAttribute:t.ignoreAttribute||null,isProtected:t.isProtected||null,inScope:t.inScope||(()=>!0),liveNodesWithIds:t.liveNodesWithIds||(()=>[]),sim:new Map,planned:new Map,operations:[]};for(let i=0;i<e.steps.length;i++){let a=e.steps[n==="undo"?e.steps.length-1-i:i],l=Rt(a,n,r);if(l)return{ok:!1,code:l.code,targets:l.targets}}return{ok:!0,operations:r.operations}}function M(e,n){return e.sim.has(n)||e.sim.set(n,Se(n,e.isIgnored)),e.sim.get(n)}function Pe(e,n){for(let t=e;t;t=t.parentNode)if(n.planned.has(t))return n.planned.get(t);return n.inScope(e)}function Ce(e,n){return n.liveNodesWithIds(e).filter(t=>Pe(t,n)).length>0}function b(e,n){return{code:e,targets:n||[]}}function Ct(e){return e.kind==="text"?e.target.data:e.kind==="value"?typeof e.read=="function"?e.read(e.target):e.target[e.prop||"value"]:e.target.getAttribute(e.name)}function Rt(e,n,t){let r=n==="undo";return e.type==="move"?Lt(e,r,t):e.type==="add"?Ot(e,r,t):e.type==="restore"?_t(e,r,t):xt(e,r,t)}function xt(e,n,t){let r=e.primitive,i=n?r.newValue:r.oldValue,a=n?r.oldValue:r.newValue;return v(r.target)?Pe(r.target,t)?r.kind==="value"&&typeof r.write=="function"&&typeof r.read!="function"?b("unsupported",e.targets):Ct(r)!==i?b("content-changed",e.targets):(r.kind==="value"?t.operations.push({type:"value",target:r.target,prop:r.prop||"value",value:a,read:r.read||null,write:r.write||null}):r.kind==="text"?t.operations.push({type:"text",target:r.target,data:a}):t.operations.push({type:"attr",target:r.target,name:r.name,value:a??null}),null):b("target-detached",e.targets):b("unsupported",e.targets)}function Ot(e,n,t){if(!v(e.parent)||!t.inScope(e.parent))return b("target-detached",e.targets);if(n){if(!L(M(t,e.parent),e.seqAfter))return b("structure-changed",e.targets);let s=Te(e.nodes,t.isProtected);if(s.length>0)return b("protected",s);for(let d=0;d<e.nodes.length;d++)if(z(e.nodes[d],t.ignoreAttribute,e.parent,t.isIgnored)!==e.content[d])return b("content-changed",e.targets);for(let d of e.nodes)t.operations.push({type:"remove",node:d}),t.planned.set(d,!1);return t.sim.set(e.parent,e.seqBefore.slice()),null}if(!L(M(t,e.parent),e.seqBefore))return b("structure-changed",e.targets);for(let s of e.nodes)if(s.parentNode)return b("structure-changed",e.targets);let r=e.nodes.flatMap(s=>G(s));if(r.length>0&&Ce(r,t))return b("duplicate-id",e.targets);let i=D(e.seqBefore,e.slot);if(i==null)return b("unsupported",e.targets);let a=e.seqBefore.slice(),l=i;for(let s of e.nodes)t.operations.push({type:"insert",parent:e.parent,node:s,beforeId:a[l]??null}),a=a.slice(0,l).concat(T(s),a.slice(l)),l+=1,t.planned.set(s,!0);return t.sim.set(e.parent,e.seqAfter.slice()),null}function _t(e,n,t){if(!v(e.parent)||!t.inScope(e.parent))return b("target-detached",e.targets);if(n){if(!L(M(t,e.parent),e.seqAfter))return b("structure-changed",e.targets);for(let s=0;s<e.nodes.length;s++){let d=e.nodes[s];if(d.parentNode||z(d,t.ignoreAttribute,e.parent,t.isIgnored)!==e.content[s])return b("content-changed",e.targets)}if(e.ids.length>0&&Ce(e.ids,t))return b("duplicate-id",e.targets);let i=D(e.seqAfter,e.slot);if(i==null)return b("unsupported",e.targets);let a=e.seqAfter.slice(),l=i;for(let s of e.nodes)t.operations.push({type:"insert",parent:e.parent,node:s,beforeId:a[l]??null}),a=a.slice(0,l).concat(T(s),a.slice(l)),l+=1,t.planned.set(s,!0);return t.sim.set(e.parent,e.seqBefore.slice()),null}if(!L(M(t,e.parent),e.seqBefore))return b("structure-changed",e.targets);let r=Te(e.nodes,t.isProtected);if(r.length>0)return b("protected",r);for(let i=0;i<e.nodes.length;i++){let a=e.nodes[i];if(a.parentNode!==e.parent||z(a,t.ignoreAttribute,e.parent,t.isIgnored)!==e.content[i])return b("content-changed",e.targets)}for(let i of e.nodes)t.operations.push({type:"remove",node:i}),t.planned.set(i,!1);return t.sim.set(e.parent,e.seqAfter.slice()),null}function Mt(e,n){let t=e.indexOf(n);return t<0?null:e.slice(0,t).concat(e.slice(t+1))}function Lt(e,n,t){let r=T(e.node),i=n?e.destParent:e.sourceParent,a=n?e.sourceParent:e.destParent,l=M(t,i),s=M(t,a),d=n?e.dest.after:e.source.before,g=n?e.source.after:e.dest.before,p=n?e.sourceSlot:e.destSlot;if(!v(i)||!v(a)||!t.inScope(i)||!t.inScope(a))return b("target-detached",e.targets);if(!L(l,d))return b("structure-changed",e.targets);let h=i===a?Mt(s,r):s;if(!L(h,g))return b("structure-changed",e.targets);let w=D(g,p);return w==null?b("unsupported",e.targets):(t.operations.push({type:"insert",parent:a,node:e.node,beforeId:g[w]??null}),t.planned.set(e.node,!0),n?(t.sim.set(a,e.source.before.slice()),i!==a&&t.sim.set(i,e.dest.before.slice())):(t.sim.set(a,e.dest.after.slice()),i!==a&&t.sim.set(i,e.source.after.slice())),null)}function L(e,n){if(!e||!n||e.length!==n.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==n[t])return!1;return!0}function qt(e,n){for(let t of e.childNodes||[])if(T(t)===n)return t;return null}function Ee(e,n){typeof e.write=="function"?e.write(e.target,n):e.target[e.prop]=n}function Re(e){let n=[];try{for(let t of e)zt(t,n);return{ok:!0}}catch(t){for(let r=n.length-1;r>=0;r--)try{n[r]()}catch{}return{ok:!1,error:t}}}function zt(e,n){if(e.type==="attr"){let t=e.target.getAttribute(e.name);e.value==null?e.target.removeAttribute(e.name):e.target.setAttribute(e.name,e.value),n.push(()=>{t==null?e.target.removeAttribute(e.name):e.target.setAttribute(e.name,t)});return}if(e.type==="text"){let t=e.target.data;e.target.data=e.data,n.push(()=>{e.target.data=t});return}if(e.type==="value"){let t=typeof e.read=="function"?e.read(e.target):e.target[e.prop];Ee(e,e.value),n.push(()=>Ee(e,t));return}if(e.type==="insert"){let t=e.beforeId==null?null:qt(e.parent,e.beforeId);if(e.beforeId!=null&&!t)throw new Error("hyper-undo: replay anchor vanished");let r=e.node.parentNode,i=e.node.nextSibling;e.parent.insertBefore(e.node,t),n.push(()=>{r?r.insertBefore(e.node,i&&i.parentNode===r?i:null):e.node.parentNode===e.parent&&e.parent.removeChild(e.node)});return}if(e.type==="remove"){let t=e.node.parentNode;if(!t)throw new Error("hyper-undo: replay target is no longer attached");let r=e.node.nextSibling;t.removeChild(e.node),n.push(()=>t.insertBefore(e.node,r))}}var Kt=['[src^="chrome-extension://"]','[href^="chrome-extension://"]','[src^="moz-extension://"]','[href^="moz-extension://"]','[src^="safari-web-extension://"]','[href^="safari-web-extension://"]','[id="1p-menu-live-region"]',"com-1password-button","com-1password-menu","com-1password-notification","grammarly-extension","grammarly-desktop-integration","lt-div","lt-card","lt-toolbar","lt-highlighter","[data-lastpass-root]","[data-lastpass-icon-root]","[data-dashlane-shadowhost]","[data-klarna-extension]",'[class*="klarna-extension"]',".skiptranslate","#goog-gt-tt",".goog-te-banner-frame",".goog-te-balloon-frame","style.darkreader","style[data-darkreader-mode]","style[data-darkreader-scheme]","#loom-companion-mv3","loom-container","[ext-id]"],$t=["data-grammarly","data-lt","data-1p","data-com-onepassword","data-lastpass","data-lp","data-kwimpala","data-bitwarden","data-bw","data-dashlane","data-np","data-protonpass","data-proton-pass","data-keeper","data-rf","data-roboform","data-honey","data-rakuten","data-capital-one","data-wikibuy","data-klarna","data-darkreader","data-evernote","data-pocket","data-pin"],xe=Kt.join(","),Oe=new RegExp("^(?:"+$t.join("|")+")(?:-|$)");var rn=Object.freeze({data:Object.freeze({tokens:["no-data"],bundles:["editor-ui"]}),save:Object.freeze({tokens:["no-save"],bundles:["editor-ui"]}),snapshot:Object.freeze({tokens:["no-snapshot"],bundles:["editor-ui"]}),watch:Object.freeze({tokens:["no-watch"],bundles:["editor-ui"]}),undo:Object.freeze({tokens:["no-undo"],bundles:["editor-ui"]}),history:Object.freeze({tokens:[],bundles:["editor-ui"]})}),Bt=Object.freeze({"editor-ui":Object.freeze(["no-data","no-save","no-snapshot","no-watch","no-undo"])}),Dt=Object.freeze(["no-save","no-snapshot","no-trigger-autosave","no-dirty","no-watch","no-undo","no-data","freeze","editor-ui","live"]);function U(e,n){if(!e||e.nodeType!==1)return!1;let t=e.getAttribute?.("clay");return!!(t&&t.split(/\s+/).includes(n)||e.hasAttribute?.(n))}function Y(e,n){if(U(e,n))return!0;for(let[t,r]of Object.entries(Bt))if(r.includes(n)&&U(e,t))return!0;return!1}function _e(e){return e==="clay"||Dt.includes(e)}var Ut=["mutations-ignore","save-remove","save-ignore","save-freeze","no-undo","no-watch"];function jt(){if(typeof window>"u")return null;let e=window.clay?.region||window.hyperclay?.region;return e&&typeof e.resolveRegionPolicy=="function"?e.resolveRegionPolicy:null}function Z(e){let n=jt();if(n)try{if(!n(e).undoable)return!0}catch{}let t=e&&e.nodeType!==1?e.parentElement:e;if(t&&t.closest&&t.closest(xe))return!0;for(;t&&t.nodeType===1;){if(Y(t,"no-undo")||Y(t,"no-watch"))return!0;for(let r of Ut)if(U(t,r))return!0;t=t.parentElement}return!1}function Wt(e){let n=e.target,t=n.cloneNode(!1),r=t;for(;n.parentElement;){n=n.parentElement;let i=n.cloneNode(!1);i.appendChild(t),t=i}return e.oldValue==null?r.removeAttribute(e.attributeName):r.setAttribute(e.attributeName,e.oldValue),Z(r)}function j(e,n,t){if(t?.type==="attributes"&&_e(t.attributeName)){if(Z(e)&&Wt(t))return!0}else if(Z(e))return!0;if(t&&t.type==="attributes"){if(t.attributeName&&Oe.test(t.attributeName.toLowerCase()))return!0;if(n)try{if(n(t.attributeName,t.target))return!0}catch{}}return!1}function Me(){let e=new Map;function n(i,a){let l=e.get(i);return l||(l=new Set,e.set(i,l)),l.add(a),()=>t(i,a)}function t(i,a){let l=e.get(i);l&&l.delete(a)}function r(i,a){let l=e.get(i);if(l)for(let s of Array.from(l))try{s(a)}catch(d){console.error("[hyper-undo] listener threw",d)}}return{on:n,off:t,emit:r}}var Ft={maxHistory:100,idleWindowMs:500,idleLabel:"Edit",recording:"automatic",ignoreAttribute:null,isProtected:null,ignoreNode:null,debug:!1};function Q(e){let n={...Ft,...e};if(!n.scope)throw new Error("hyper-undo: scope is required");let t=Me(),r=[],i=[],a=`u${Math.random().toString(36).slice(2,8)}`,l=0,s=null,d=[],g=null,p=null,h=0,w=!1,P=n.recording==="commands"?"commands":"automatic",A=null,C=!1;function k(...o){n.debug&&console.log("[hyper-undo]",...o)}function $e(){w||(w=!0,p=Be(R),p.observe(n.scope,{childList:!0,attributes:!0,characterData:!0,subtree:!0,attributeOldValue:!0,characterDataOldValue:!0}),k("started"))}function Be(o){let u=typeof document<"u"&&n.scope===document.body,c=typeof window<"u"&&(window.clay?.Mutation||window.hyperclay?.Mutation)||null;return u&&c&&typeof c.createObserver=="function"?(k("sourcing records from the platform Mutation hub (shared observer)"),c.createObserver(o)):new MutationObserver(o)}function re(){w&&(w=!1,p&&(p.disconnect(),p=null),x(),r.length=0,i.length=0,d=[],s=null,A=null,C=!1,h=0,k("stopped"))}function De(){let o=n.scope;return!!(o&&o.nodeType===1&&o.isConnected===!1)}function R(o){oe(o,!1)}function oe(o,u){if(A){for(let m of o)A.records.push(m);return}if(P==="commands"||h>0)return;let c=W(Ue(o),u);if(c.length>0){for(let m of c)d.push(m);ie()}}function Ue(o){return typeof n.ignoreNode!="function"?o:o.filter(u=>{if(u.type!=="childList")return!0;let c=[...u.addedNodes,...u.removedNodes];return c.length===0?!0:!c.every(m=>je(m))})}function je(o){try{return!!n.ignoreNode(o)}catch{return!1}}function W(o,u=!1){let c=o.filter(m=>(ut(m.target)||u&&ye(m.target))&&!j(m.target,n.ignoreAttribute,m));return ve(c,m=>j(m,n.ignoreAttribute))}function ie(){x(),g=setTimeout(ae,n.idleWindowMs)}function x(){g!=null&&(clearTimeout(g),g=null)}function ae(){if(g=null,d.length===0)return;let o=d;d=[],K(n.idleLabel,o)}function K(o,u){let c=Ve(u,{isIgnored:F,ignoreAttribute:ue});if(c.steps.length===0)return k("commit",o,"with nothing to record"),t.emit("commit"),null;let m={id:`${a}-${++l}`,label:o,timestamp:Date.now(),primitives:u,certificate:c};for(r.push(m),i.length=0,s=null;r.length>n.maxHistory;)r.shift();return k("commit",o,"primitives:",u.length),t.emit("commit"),m}function F(o){return j(o,n.ignoreAttribute)}function ue(o,u,c=null){if(typeof n.ignoreAttribute!="function")return!1;try{return!!n.ignoreAttribute(o,u,c)}catch{return!1}}function We(o){if(typeof n.isProtected!="function")return!1;try{return!!n.isProtected(o)}catch{return!1}}function Fe(o,u){if(!w)throw new Error("hyper-undo: scope not started");if(P==="commands")return de(o,u,{honorPause:!0,receipt:!1});R(p.takeRecords()),O();let c=h===0?se():null,m=u();if(m&&typeof m.then=="function")throw new Error("hyper-undo: commit() fn must be synchronous; returned a Promise");if(oe(p.takeRecords(),!0),c!=null&&le(c),d.length===0){t.emit("commit");return}x();let y=d;d=[],K(o,y)}function Xe(o){if(!w)throw new Error("hyper-undo: scope not started");if(!p)return;if(h>1){p.takeRecords();return}O();let u=W(p.takeRecords(),!0);u.length!==0&&(x(),K(o,u))}function He(){p&&p.takeRecords()}function X(){let o=n.scope;return o&&o.ownerDocument||(typeof document<"u"?document:null)}function $(){let o=X();return!o||!o.head||typeof o.head.querySelector!="function"?null:o.head.querySelector("title")}function se(){let o=$();return o?o.textContent:null}function le(o){let u=$();if(!u||o==null)return;let c=u.textContent;c!==o&&fe({kind:"value",target:u,prop:"textContent",oldValue:o,newValue:c})}function Je(o){if(!o)return null;let u=X();if(!u||o.target!==u||o.prop!=="title")return o;let c=$();return c?{kind:"value",target:c,prop:"textContent",oldValue:o.oldValue,newValue:o.newValue}:null}function Ge(){if(typeof window>"u")return!1;let o=window.clay?.effect||window.hyperclay?.effect;return!!(o&&o.running)}function Ye(){p&&R(p.takeRecords()),O(),A={records:[],primitives:[]}}function Ze(){let o=A;if(A=null,!o)return[];let u=W(o.records,!0);for(let c of o.primitives)u.push(c);return u}function de(o,u,{honorPause:c,receipt:m}){if(typeof u!="function")throw new Error("hyper-undo: command() needs a synchronous function");if(A)throw new Error("hyper-undo: command() cannot nest inside another command");if(C)throw new Error("hyper-undo: command() cannot run during undo or redo");if(Ge())throw new Error("hyper-undo: command() cannot run inside a derived-effect context");if(u.constructor&&u.constructor.name==="AsyncFunction")throw new Error("hyper-undo: command() fn must be synchronous; it was declared async");let y=c&&h>0,N=y?null:se();Ye();let S=[],V=null,_;try{try{_=u()}catch(be){V=be}if(p&&R(p.takeRecords()),_&&typeof _.then=="function"){try{_.then(void 0,()=>{})}catch{}V||(V=new Error("hyper-undo: command() fn must be synchronous; returned a Promise"))}y||le(N)}finally{S=Ze()}let B=y||S.length===0?null:K(o,S);if(V)throw V;return m?B?{id:B.id,label:B.label}:null:B}function Qe(o,u){if(!w)throw new Error("hyper-undo: scope not started");return de(o,u,{honorPause:!1,receipt:!0})}function et(o){if(o!=="automatic"&&o!=="commands")throw new Error("hyper-undo: setRecording() takes 'automatic' or 'commands'");if(A)throw new Error("hyper-undo: setRecording() cannot change while a command is running");return P===o||(O(),P=o,k("recording",o)),P}function ce(o){if(!w||!o||!A&&(h>0||P==="commands"))return;let u=Je(o);u&&fe(u)}function fe(o){if(A){A.primitives.push(o);return}d.push(o),ie()}function tt(o,{prop:u="value",oldValue:c,newValue:m,read:y,write:N}={}){!o||c===m||ce({kind:"value",target:o,prop:u,oldValue:c,newValue:m,read:y,write:N})}function O(){h===0&&p&&R(p.takeRecords()),d.length!==0&&(x(),ae())}function me(){h===0&&p&&R(p.takeRecords()),h++,k("paused",h)}function pe(){h!==0&&(h--,h===0&&p&&p.takeRecords(),k("resumed",h))}function ge(o,u){if(De())return re(),{ok:!1,code:"disconnected"};O();let c=o==="undo"?r:i,m=o==="undo"?i:r,y=c.at(-1);if(!y)return{ok:!1,code:"empty"};if(u&&u!==y.id){let _=he(u)||y;return H(_,o,"stale-entry")}let N;C=!0;try{N=Ie(y.certificate,o,{isIgnored:F,ignoreAttribute:ue,isProtected:We,inScope:st,liveNodesWithIds:lt})}finally{C=!1}if(!N.ok)return H(y,o,N.code,N.targets);me();let S;C=!0;try{S=Re(N.operations)}finally{C=!1,pe()}if(!S.ok)return k(`${o} failed and was rolled back`,S.error),H(y,o,"replay-error");c.pop(),m.push(y),s=null;let V={ok:!0,entryId:y.id,label:y.label,direction:o};return k(o,y.label),t.emit(o,V),V}function nt(o){return ge("undo",o&&o.entryId)}function rt(o){return ge("redo",o&&o.entryId)}function he(o){return r.find(u=>u.id===o)||i.find(u=>u.id===o)||null}function H(o,u,c,m=[]){return s={entryId:o.id,direction:u,code:c,targets:m},k("refused",u,c),t.emit("refused",{entryId:o.id,label:o.label,direction:u,code:c,targets:m}),{ok:!1,code:c,entryId:o.id,label:o.label,direction:u}}function ot(o){if(!s||s.entryId!==o)return{ok:!1,code:"not-refused",entryId:o};let u=s.direction,c=u==="undo"?r:i,m=c.at(-1);return!m||m.id!==o?{ok:!1,code:"stale-entry",entryId:o}:(c.pop(),s=null,k("discarded",m.label),t.emit("discard",{entryId:o,label:m.label,direction:u}),{ok:!0,entryId:o,direction:u})}function it(o){let u=he(o);if(!u||!u.certificate||!u.certificate.replayable)return null;let c=s&&s.entryId===u.id?{direction:s.direction,code:s.code,targets:(s.targets||[]).map(m=>({id:m.id??null,kind:m.kind??null}))}:null;return{id:u.id,label:u.label,timestamp:u.timestamp,refused:c,steps:u.certificate.steps.map(at)}}function at(o){if(o.type==="move")return{kind:"move",node:{id:E(o.node).id},from:{id:E(o.sourceParent).id},to:{id:E(o.destParent).id}};if(o.type==="add"||o.type==="restore")return{kind:o.type==="add"?"add":"remove",parent:{id:E(o.parent).id},nodes:o.nodes.map((N,S)=>({id:E(N).id,html:o.content[S]??null}))};let u=o.primitive,c={id:E(u.target).id},m=u.oldValue??null,y=u.newValue??null;return o.type==="value"?{kind:"value",target:c,prop:u.prop??"value",before:m,after:y}:o.type==="text"?{kind:"text",target:c,before:m,after:y}:o.type==="attr-set"||o.type==="attr-add"||o.type==="attr-remove"?{kind:"attribute",target:c,name:u.name??null,before:m,after:y}:{kind:o.type,target:c,before:m,after:y}}function ut(o){let u=n.scope;return!u||!o?!1:o===u||typeof u.contains=="function"&&u.contains(o)}function ye(o){let u=X(),c=u&&u.head;if(!c||!o)return!1;let m=o.nodeType===1?o:o.parentElement;for(;m&&m!==c;m=m.parentElement)if(m.localName==="title")return!1;return m===c}function st(o){let u=n.scope;return!o||!u?!1:o===u||$()===o||ye(o)?!0:typeof u.contains=="function"?u.contains(o):!1}function lt(o){let u=n.scope;if(!o||o.length===0||typeof u?.querySelectorAll!="function")return[];let c=new Set(o),m=[];for(let y of u.querySelectorAll("[data-id]"))c.has(y.getAttribute("data-id"))&&(F(y)||m.push(y));return m}function dt(){p&&p.takeRecords(),r.length=0,i.length=0,d=[],s=null,x(),k("cleared"),t.emit("clear")}return{_config:n,start:$e,stop:re,commit:Fe,commitCaptured:Xe,discardCaptured:He,flush:O,command:Qe,setRecording:et,record:ce,recordValue:tt,undo:nt,redo:rt,clear:dt,discard:ot,describe:it,pause:me,resume:pe,on:t.on,off:t.off,get canUndo(){return r.length>0},get canRedo(){return i.length>0},get isPaused(){return h>0},get history(){return r.map(o=>{let u={id:o.id,label:o.label,timestamp:o.timestamp};return s&&s.entryId===o.id&&(u.refused={direction:s.direction,code:s.code,targets:s.targets}),u})},get future(){return i.map(o=>{let u={id:o.id,label:o.label,timestamp:o.timestamp};return s&&s.entryId===o.id&&(u.refused={direction:s.direction,code:s.code,targets:s.targets}),u}).reverse()},get scope(){return n.scope}}}var Xt=new Set(["checkbox","radio","button","submit","reset","image","file","range","color"]);function Ht(e){let n=typeof e.composedPath=="function"?e.composedPath():[],t=n.length>0?n:Jt(e.target);for(let r of t){if(!r||r.nodeType!==1)continue;let i=String(r.tagName||"").toUpperCase();if(i==="TEXTAREA"||i==="SELECT"||i==="INPUT"&&!Xt.has(String(r.type||r.getAttribute?.("type")||"text").toLowerCase())||r.isContentEditable===!0)return!0;let a=r.getAttribute&&r.getAttribute("contenteditable");if(a!=null&&String(a).toLowerCase()!=="false")return!0}return!1}function Jt(e){let n=[];for(let t=e;t;t=t.parentNode||(t.host??null))n.push(t);return n}function Le(e,n){let t=r=>{let i=e.scope;if(i&&i.nodeType===1&&i.isConnected===!1){n&&n();return}if(r.defaultPrevented||r.isComposing||r.keyCode===229||Ht(r))return;let a=r.target,l=e._config.shadowKeydownIn;if(a&&a.closest&&Array.isArray(l))for(let g of l)try{if(a.closest(g))return}catch{}if(!(r.metaKey||r.ctrlKey))return;let d=(r.key||"").toLowerCase();if(d==="z"&&!r.shiftKey){r.preventDefault(),r.stopPropagation(),e.undo();return}if(d==="z"&&r.shiftKey){r.preventDefault(),r.stopPropagation(),e.redo();return}if(d==="y"&&!r.shiftKey){r.preventDefault(),r.stopPropagation(),e.redo();return}};return window.addEventListener("keydown",t,!0),()=>window.removeEventListener("keydown",t,!0)}var ee=[".CodeMirror",".cm-editor",".monaco-editor",".ace_editor",".ql-editor",".tiptap",".ProseMirror",".overtype-input","[data-richclay-active]"],f=null,te=null,qe=null,I=null;function ze(e,n){if(I){if(I.inst===e)return I.cleanup;throw new Error("hyper-undo: another scope already owns the global Cmd+Z binding (bindKeys: true). Stop it first, or use bindKeys: false for additional scopes.")}let t=Le(e,n);return I={inst:e,cleanup:t},t}function Ke(e){I&&I.inst===e&&(I.cleanup(),I=null)}var ne={defaults:{shadowKeydownIn:ee},start(e={}){let n=e.scope||(typeof document<"u"?document.body:null);if(!n)throw new Error("hyper-undo: no scope (need document.body or explicit { scope })");if(f){if(te===n)return console.warn("[hyper-undo] start() called again on existing singleton; ignoring new options"),f;throw new Error("hyper-undo: start() called with a different scope while the singleton is already started. Use undo.create({ scope }) for additional scopes, or call undo.stop() first.")}let t={...e,scope:n,shadowKeydownIn:e.shadowKeydownIn||ee};return f=Q(t),f.start(),te=n,e.bindKeys!==!1&&(qe=ze(f,()=>ne.stop())),f},stop(){f&&(Ke(f),qe=null,f.stop(),f=null,te=null)},create(e={}){let n=e.scope||(typeof document<"u"?document.body:null);if(!n)throw new Error("hyper-undo: no scope (need document.body or explicit { scope })");let t={...e,scope:n,shadowKeydownIn:e.shadowKeydownIn||ee},r=Q(t),i=null,a={_config:r._config,commit:r.commit,command:r.command,setRecording:r.setRecording,commitCaptured:r.commitCaptured,discardCaptured:r.discardCaptured,flush:r.flush,record:r.record,recordValue:r.recordValue,undo:r.undo,redo:r.redo,clear:r.clear,discard:r.discard,describe:r.describe,pause:r.pause,resume:r.resume,on:r.on,off:r.off,get canUndo(){return r.canUndo},get canRedo(){return r.canRedo},get isPaused(){return r.isPaused},get history(){return r.history},get future(){return r.future},get scope(){return r.scope},start(){e.bindKeys&&(i=ze(r,()=>a.stop())),r.start()},stop(){Ke(r),i=null,r.stop()}};return a},commit(e,n){return f?f.commit(e,n):void 0},command(e,n){return f?f.command(e,n):void 0},setRecording(e){return f?f.setRecording(e):void 0},commitCaptured(e){return f?f.commitCaptured(e):void 0},discardCaptured(){return f?f.discardCaptured():void 0},record(e){return f?f.record(e):void 0},recordValue(e,n){return f?f.recordValue(e,n):void 0},undo(e){return f?f.undo(e):void 0},redo(e){return f?f.redo(e):void 0},clear(){return f?f.clear():void 0},discard(e){return f?f.discard(e):void 0},describe(e){return f?f.describe(e):void 0},pause(){return f?f.pause():void 0},resume(){return f?f.resume():void 0},flush(){return f?f.flush():void 0},on(e,n){return f?f.on(e,n):void 0},off(e,n){return f?f.off(e,n):void 0},get canUndo(){return f?f.canUndo:!1},get canRedo(){return f?f.canRedo:!1},get history(){return f?f.history:[]},get future(){return f?f.future:[]},get isPaused(){return f?f.isPaused:!1}};var Gt=ne;return ht(Yt);})();
1
+ var hyperundo=(()=>{var he=Object.defineProperty;var Kt=Object.getOwnPropertyDescriptor;var Bt=Object.getOwnPropertyNames;var Ft=Object.prototype.hasOwnProperty;var qt=(e,n)=>{for(var t in n)he(e,t,{get:n[t],enumerable:!0})},zt=(e,n,t,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let a of Bt(n))!Ft.call(e,a)&&a!==t&&he(e,a,{get:()=>n[a],enumerable:!(o=Kt(n,a))||o.enumerable});return e};var $t=e=>zt(he({},"__esModule",{value:!0}),e);var Rn={};qt(Rn,{default:()=>Pn,endsSentence:()=>ke,undo:()=>Ne});function Ut(e,n=null){let t=[];if(e.type==="attributes"){let o=e.target,a=e.attributeName,i=e.oldValue,s=o.getAttribute(a);return i==null&&s!=null?t.push({kind:"attr-add",target:o,name:a,newValue:s}):i!=null&&s==null?t.push({kind:"attr-remove",target:o,name:a,oldValue:i}):i!==s&&t.push({kind:"attr-set",target:o,name:a,oldValue:i,newValue:s}),t}if(e.type==="characterData")return t.push({kind:"text",target:e.target,oldValue:e.oldValue,newValue:e.target.data}),t;if(e.type==="childList"){let o=e.target,a=e.nextSibling,i=e.nextSibling;for(;i&&n?.(i);)i=i.nextSibling;let s=e.previousSibling;for(;s&&n?.(s);)s=s.previousSibling;let d=n?Array.from(e.addedNodes).filter(y=>!n(y)):Array.from(e.addedNodes),f=n?Array.from(e.removedNodes).filter(y=>!n(y)):Array.from(e.removedNodes);return d.length>0&&t.push({kind:"add",parent:o,nodes:d,before:a,afterAuthored:i,beforeAuthored:s,record:e}),f.length>0&&t.push({kind:"remove",parent:o,nodes:f,before:a,afterAuthored:i,beforeAuthored:s,record:e}),t}return t}function We(e,n=null){let t=[],o=new Map;for(let a of e){if(a.type==="attributes"){let i=a.target,s=a.attributeName,d=o.get(i);d||(d=new Map,o.set(i,d)),d.has(s)||(d.set(s,{idx:t.length,oldValue:a.oldValue}),t.push(null));continue}for(let i of Ut(a,n))t.push(i)}for(let[a,i]of o)for(let[s,d]of i){let f=d.oldValue,y=a.getAttribute(s),p=null;f===y?p=null:f==null?p={kind:"attr-add",target:a,name:s,newValue:y}:y==null?p={kind:"attr-remove",target:a,name:s,oldValue:f}:p={kind:"attr-set",target:a,name:s,oldValue:f,newValue:y},t[d.idx]=p}return t.filter(a=>a!=null)}function je(e,{sameContent:n=(t,o)=>t===o}={}){let t=[],o=new Map;for(let i of e){let s=$e(i);if(s==null){t.push(i);continue}let d=o.get(i.target);d||(d=new Map,o.set(i.target,d));let f=d.get(s);if(f==null){let y=Ue(i);if(y.oldValue===y.newValue)continue;d.set(s,t.length),t.push({...i,...y})}else t[f]={...t[f],newValue:Ue(i).newValue}}let a=[];for(let i of t){if($e(i)==null){a.push(i);continue}i.oldValue!==i.newValue&&(i.kind==="value"&&i.content===!0&&n(i.oldValue,i.newValue)||a.push(jt(i)))}return a}var Wt=new Set(["attr-set","attr-add","attr-remove","text","value"]);function $e(e){return Wt.has(e.kind)?e.kind==="text"?"#text":e.kind==="value"?`#${e.prop||"value"}`:e.name==null?null:`@${e.name}`:null}function Ue(e){return e.kind==="attr-add"?{oldValue:null,newValue:e.newValue}:e.kind==="attr-remove"?{oldValue:e.oldValue,newValue:null}:{oldValue:e.oldValue,newValue:e.newValue}}function jt(e){return e.kind!=="attr-add"&&e.kind!=="attr-remove"?e:e.oldValue==null&&e.newValue!=null?{...e,kind:"attr-add"}:e.oldValue!=null&&e.newValue==null?{...e,kind:"attr-remove"}:{...e,kind:"attr-set"}}var Xe=new WeakMap,Xt=0;function _(e){let n=Xe.get(e);return n||(n=`n${++Xt}`,Xe.set(e,n)),n}function N(e){return!!e&&typeof e=="object"&&typeof e.nodeType=="number"}function Ht(e){return e.kind==="add"||e.kind==="remove"}function Ge(e,n){let t=[],o=e.childNodes;if(!o)return t;for(let a of o)n&&n(a)||t.push(_(a));return t}function He(e,n,t){if(typeof n!="function"||!N(e)||e.nodeType!==1)return null;let o=null;try{o=n(e,t)}catch{o=null}return typeof o=="string"?`#form:${JSON.stringify(o)}`:null}function Q(e,n,t=null,o=null,a=null,i=null){if(!N(e))return null;let s=He(e,a,t);if(s!=null)return s;if(e.nodeType===3)return`#text:${JSON.stringify(i&&i.has(e)?i.get(e):e.data)}`;if(e.nodeType===8)return`#comment:${JSON.stringify(e.data)}`;if(e.nodeType!==1)return`#node:${e.nodeType}`;let d=[];if(e.attributes){for(let p of e.attributes)Jt(p.name,e,n,t)||d.push(`${p.name}=${JSON.stringify(p.value)}`);d.sort()}let f=[];if(e.childNodes)for(let p of e.childNodes){let w=He(p,a,t);if(w!=null){f.push(w);continue}Yt(p,o)||f.push(Q(p,n,t,o,a,i))}return`<${String(e.tagName||"").toLowerCase()}${d.length?` ${d.join(" ")}`:""}>${f.join("")}</>`}function ye(e,n=[]){if(!N(e))return n;if(e.nodeType===1){let t=e.getAttribute&&e.getAttribute("data-id");t&&n.push(t)}if(e.childNodes)for(let t of e.childNodes)ye(t,n);return n}function Jt(e,n,t,o=null){if(typeof t!="function")return!1;try{return!!t(e,n,o)}catch{return!1}}function Yt(e,n){if(typeof n!="function")return!1;try{return!!n(e)}catch{return!1}}function Ze(e,n){if(typeof n!="function")return[];let t=[],o=a=>{if(!N(a))return;let i=!1;try{i=!!n(a)}catch{i=!1}if(i&&t.push(I(a,"protected")),a.childNodes)for(let s of a.childNodes)o(s)};for(let a of e)o(a);return t}function I(e,n,t=null){let o=e;o&&o.nodeType!==1&&(o=o.parentElement);let a=o&&typeof o.closest=="function"?o.closest("[data-id]"):null;return!a&&t&&typeof t.closest=="function"&&(a=t.closest("[data-id]")),{id:(a?a.getAttribute("data-id"):null)||null,kind:n||null}}function Gt(e,n,t=null){return(e||[]).filter(N).map(o=>I(o,n,t))}function Z(e){return{replayable:!1,reason:e,steps:[]}}function ie(e,n){let t=[[n.afterAuthored,a=>a],[n.beforeAuthored,a=>a+1],[n.before,a=>a]],o=!1;for(let[a,i]of t){if(!N(a))continue;o=!0;let s=e.indexOf(_(a));if(s>=0)return i(s)}return o?null:e.length}function Qe(e,n={}){let t=n.isIgnored||null,o=n.ignoreAttribute||null,a=n.durableForm||null,i=je(e,{sameContent:ae}),s=[];for(let w of i){if(!Ht(w)){if(!N(w.target))return Z("non-dom-target");continue}if(!N(w.parent))return Z("non-dom-parent");let k=Array.from(w.nodes||[]).filter(N);if(k.length!==0){if(k.length!==Array.from(w.nodes||[]).length)return Z("non-dom-node");s.push({primitive:w,nodes:k,parent:w.parent})}}if(Zt(s))return Z("in-record-move");let d=Qt(s,t);if(!d)return Z("ambiguous-structure");let f=en(s,d),y=new Map(s.map(w=>[w.primitive,w])),p=[];for(let w of i){let k=y.get(w);if(!k){p.push(nn(w));continue}let A=f.get(k);if(A){A.at===k&&p.push(A.step);continue}p.push(tn(k,d.get(k),o,t,a))}return{replayable:!0,reason:null,steps:p}}function Zt(e){let n=new Map;for(let t of e){let o=t.primitive.record;if(!o)continue;let a=n.get(o);a||(a=new Map,n.set(o,a));for(let i of t.nodes){let s=a.get(i);s||(s=new Set,a.set(i,s)),s.add(t.primitive.kind)}}for(let t of n.values())for(let o of t.values())if(o.size>1)return!0;return!1}function Qt(e,n){let t=new Map;for(let a of e)t.has(a.parent)||t.set(a.parent,Ge(a.parent,n));let o=new Map;for(let a=e.length-1;a>=0;a--){let i=e[a],s=t.get(i.parent);if(!s)return null;let d=s.slice(),f;if(i.primitive.kind==="add"){let y=i.nodes.map(_);if(!y.every(p=>s.includes(p)))return null;f=s.filter(p=>!y.includes(p))}else{let y=ie(d,i.primitive);if(y==null)return null;f=d.slice(),f.splice(y,0,...i.nodes.map(_))}o.set(i,{before:f,after:d}),t.set(i.parent,f)}return o}function en(e,n){let t=new Map,o=new Map;e.forEach((i,s)=>{for(let d of i.nodes){let f=_(d);i.primitive.kind==="remove"?t.set(f,{item:i,index:s,node:d}):o.set(f,{item:i,index:s,node:d})}});let a=new Map;for(let[i,s]of t){let d=o.get(i);if(!d||d.index<s.index||s.item.nodes.length!==1||d.item.nodes.length!==1)continue;let f={type:"move",node:s.node,sourceParent:s.item.parent,destParent:d.item.parent,source:n.get(s.item),dest:n.get(d.item),sourceSlot:s.item.primitive,destSlot:d.item.primitive,targets:[I(s.node,"move")]};a.set(s.item,{step:f,at:d.item}),a.set(d.item,{step:f,at:d.item})}return a}function tn(e,n,t,o,a=null){let i=e.primitive.kind;return{type:i==="add"?"add":"restore",parent:e.parent,nodes:e.nodes,seqBefore:n.before,seqAfter:n.after,slot:e.primitive,content:e.nodes.map(s=>Q(s,t,e.parent,o,a)),ids:i==="remove"?e.nodes.flatMap(s=>ye(s)):[],targets:Gt(e.nodes,i==="add"?"added":"removed",e.parent)}}function nn(e){return{type:e.kind,primitive:e,targets:[I(e.target,e.name||e.prop||"text")]}}function et(e,n,t={}){if(!e||!e.replayable)return{ok:!1,code:"unsupported",targets:[]};let o={isIgnored:t.isIgnored||null,ignoreAttribute:t.ignoreAttribute||null,durableForm:t.durableForm||null,isProtected:t.isProtected||null,inScope:t.inScope||(()=>!0),liveNodesWithIds:t.liveNodesWithIds||(()=>[]),sim:new Map,planned:new Map,texts:new Map,operations:[]};for(let a=0;a<e.steps.length;a++){let i=e.steps[n==="undo"?e.steps.length-1-a:a],s=on(i,n,o);if(s)return{ok:!1,code:s.code,targets:s.targets}}return{ok:!0,operations:o.operations}}function X(e,n){return e.sim.has(n)||e.sim.set(n,Ge(n,e.isIgnored)),e.sim.get(n)}function H(e,n){for(let t=e;t;t=t.parentNode)if(n.planned.has(t))return n.planned.get(t);return n.inScope(e)}function tt(e,n){return n.liveNodesWithIds(e).filter(t=>H(t,n)).length>0}function b(e,n){return{code:e,targets:n||[]}}function ae(e,n){return e===n?!0:typeof e!="string"||typeof n!="string"?!1:e.replace(/\u00A0|&nbsp;/g," ")===n.replace(/\u00A0|&nbsp;/g," ")}function rn(e){return e.kind==="text"?e.target.data:e.kind==="value"?typeof e.read=="function"?e.read(e.target):e.target[e.prop||"value"]:e.target.getAttribute(e.name)}function on(e,n,t){let o=n==="undo";return e.type==="move"?dn(e,o,t):e.type==="add"?un(e,o,t):e.type==="restore"?sn(e,o,t):an(e,o,t)}function an(e,n,t){let o=e.primitive,a=n?o.newValue:o.oldValue,i=n?o.oldValue:o.newValue;if(!N(o.target))return b("unsupported",e.targets);if(!H(o.target,t))return b("target-detached",e.targets);if(o.kind==="value"&&typeof o.write=="function"&&typeof o.read!="function")return b("unsupported",e.targets);let s=rn(o);return(o.content===!0?!ae(s,a):s!==a)?b("content-changed",e.targets):(o.kind==="value"?t.operations.push({type:"value",target:o.target,prop:o.prop||"value",value:i,read:o.read||null,write:o.write||null,content:o.content===!0}):o.kind==="text"?(t.operations.push({type:"text",target:o.target,data:i}),t.texts.set(o.target,i)):t.operations.push({type:"attr",target:o.target,name:o.name,value:i??null}),null)}function un(e,n,t){if(!N(e.parent)||!H(e.parent,t))return b("target-detached",e.targets);if(n){if(!J(X(t,e.parent),e.seqAfter))return b("structure-changed",e.targets);let d=Ze(e.nodes,t.isProtected);if(d.length>0)return b("protected",d);for(let f=0;f<e.nodes.length;f++)if(Q(e.nodes[f],t.ignoreAttribute,e.parent,t.isIgnored,t.durableForm)!==e.content[f])return b("content-changed",e.targets);for(let f of e.nodes)t.operations.push({type:"remove",node:f}),t.planned.set(f,!1);return t.sim.set(e.parent,e.seqBefore.slice()),null}if(!J(X(t,e.parent),e.seqBefore))return b("structure-changed",e.targets);for(let d of e.nodes)if(d.parentNode)return b("structure-changed",e.targets);let o=e.nodes.flatMap(d=>ye(d));if(o.length>0&&tt(o,t))return b("duplicate-id",e.targets);let a=ie(e.seqBefore,e.slot);if(a==null)return b("unsupported",e.targets);let i=e.seqBefore.slice(),s=a;for(let d of e.nodes)t.operations.push({type:"insert",parent:e.parent,node:d,beforeId:i[s]??null}),i=i.slice(0,s).concat(_(d),i.slice(s)),s+=1,t.planned.set(d,!0);return t.sim.set(e.parent,e.seqAfter.slice()),null}function sn(e,n,t){if(!N(e.parent)||!H(e.parent,t))return b("target-detached",e.targets);if(n){if(!J(X(t,e.parent),e.seqAfter))return b("structure-changed",e.targets);for(let f=0;f<e.nodes.length;f++){let y=e.nodes[f];if(y.parentNode||Q(y,t.ignoreAttribute,e.parent,t.isIgnored,t.durableForm)!==e.content[f])return b("content-changed",e.targets)}if(e.ids.length>0&&tt(e.ids,t))return b("duplicate-id",e.targets);let i=ie(e.seqAfter,e.slot);if(i==null)return b("unsupported",e.targets);let s=e.seqAfter.slice(),d=i;for(let f of e.nodes)t.operations.push({type:"insert",parent:e.parent,node:f,beforeId:s[d]??null}),s=s.slice(0,d).concat(_(f),s.slice(d)),d+=1,t.planned.set(f,!0);return t.sim.set(e.parent,e.seqBefore.slice()),null}if(!J(X(t,e.parent),e.seqBefore))return b("structure-changed",e.targets);let o=Ze(e.nodes,t.isProtected);if(o.length>0)return b("protected",o);let a=i=>t.planned.get(i)===!0||typeof t.isIgnored=="function"&&t.isIgnored(i);for(let i=0;i<e.nodes.length;i++){let s=e.nodes[i];if(s.parentNode!==e.parent||Q(s,t.ignoreAttribute,e.parent,a,t.durableForm,t.texts)!==e.content[i])return b("content-changed",e.targets)}for(let i of e.nodes)t.operations.push({type:"remove",node:i}),t.planned.set(i,!1);return t.sim.set(e.parent,e.seqAfter.slice()),null}function ln(e,n){let t=e.indexOf(n);return t<0?null:e.slice(0,t).concat(e.slice(t+1))}function dn(e,n,t){let o=_(e.node),a=n?e.destParent:e.sourceParent,i=n?e.sourceParent:e.destParent,s=X(t,a),d=X(t,i),f=n?e.dest.after:e.source.before,y=n?e.source.after:e.dest.before,p=n?e.sourceSlot:e.destSlot;if(!N(a)||!N(i)||!H(a,t)||!H(i,t))return b("target-detached",e.targets);if(!J(s,f))return b("structure-changed",e.targets);let w=a===i?ln(d,o):d;if(!J(w,y))return b("structure-changed",e.targets);let k=ie(y,p);return k==null?b("unsupported",e.targets):(t.operations.push({type:"insert",parent:i,node:e.node,beforeId:y[k]??null}),t.planned.set(e.node,!0),n?(t.sim.set(i,e.source.before.slice()),a!==i&&t.sim.set(a,e.dest.before.slice())):(t.sim.set(i,e.dest.after.slice()),a!==i&&t.sim.set(a,e.source.after.slice())),null)}function J(e,n){if(!e||!n||e.length!==n.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==n[t])return!1;return!0}function cn(e,n){for(let t of e.childNodes||[])if(_(t)===n)return t;return null}function Je(e,n){let t=Math.min(e.length,n.length),o=0;for(;o<t&&e[o]===n[o];)o++;let a=0;for(;a<t-o&&e[e.length-1-a]===n[n.length-1-a];)a++;return n.length-a}function Ye(e,n){typeof e.write=="function"?e.write(e.target,n):e.target[e.prop]=n}function nt(e){let n=[];try{let t=null;for(let o of e)t=fn(o,n)||t;return{ok:!0,caret:t}}catch(t){for(let o=n.length-1;o>=0;o--)try{n[o]()}catch{}return{ok:!1,error:t}}}function fn(e,n){if(e.type==="attr"){let t=e.target.getAttribute(e.name);e.value==null?e.target.removeAttribute(e.name):e.target.setAttribute(e.name,e.value),n.push(()=>{t==null?e.target.removeAttribute(e.name):e.target.setAttribute(e.name,t)});return}if(e.type==="text"){let t=e.target.data;return e.target.data=e.data,n.push(()=>{e.target.data=t}),{node:e.target,offset:Je(t,e.data)}}if(e.type==="value"){let t=typeof e.read=="function"?e.read(e.target):e.target[e.prop],o=e.content?e.target.textContent:null;if(Ye(e,e.value),n.push(()=>Ye(e,t)),!e.content)return;let a=e.target.textContent;return a===o?void 0:{root:e.target,textOffset:Je(o,a)}}if(e.type==="insert"){let t=e.beforeId==null?null:cn(e.parent,e.beforeId);if(e.beforeId!=null&&!t)throw new Error("hyper-undo: replay anchor vanished");let o=e.node.parentNode,a=e.node.nextSibling;return e.parent.insertBefore(e.node,t),n.push(()=>{o?o.insertBefore(e.node,a&&a.parentNode===o?a:null):e.node.parentNode===e.parent&&e.parent.removeChild(e.node)}),e.node.nodeType!==3?void 0:{node:e.node,offset:e.node.data.length}}if(e.type==="remove"){let t=e.node.parentNode;if(!t)throw new Error("hyper-undo: replay target is no longer attached");let o=e.node.nextSibling,a=Array.prototype.indexOf.call(t.childNodes,e.node);return t.removeChild(e.node),n.push(()=>t.insertBefore(e.node,o)),e.node.nodeType!==3?void 0:{node:t,offset:a}}}var pn=['[src^="chrome-extension://"]','[href^="chrome-extension://"]','[src^="moz-extension://"]','[href^="moz-extension://"]','[src^="safari-web-extension://"]','[href^="safari-web-extension://"]','[id="1p-menu-live-region"]',"com-1password-button","com-1password-menu","com-1password-notification","grammarly-extension","grammarly-desktop-integration","lt-div","lt-card","lt-toolbar","lt-highlighter","[data-lastpass-root]","[data-lastpass-icon-root]","[data-dashlane-shadowhost]","[data-klarna-extension]",'[class*="klarna-extension"]',".skiptranslate","#goog-gt-tt",".goog-te-banner-frame",".goog-te-balloon-frame","style.darkreader","style[data-darkreader-mode]","style[data-darkreader-scheme]","#loom-companion-mv3","loom-container","[ext-id]"],mn=["data-grammarly","data-lt","data-1p","data-com-onepassword","data-lastpass","data-lp","data-kwimpala","data-bitwarden","data-bw","data-dashlane","data-np","data-protonpass","data-proton-pass","data-keeper","data-rf","data-roboform","data-honey","data-rakuten","data-capital-one","data-wikibuy","data-klarna","data-darkreader","data-evernote","data-pocket","data-pin"],rt=pn.join(","),ot=new RegExp("^(?:"+mn.join("|")+")(?:-|$)");var Dn=Object.freeze({data:Object.freeze({tokens:["no-data"],bundles:["editor-ui"]}),save:Object.freeze({tokens:["no-save"],bundles:["editor-ui"]}),snapshot:Object.freeze({tokens:["no-snapshot"],bundles:["editor-ui"]}),watch:Object.freeze({tokens:["no-watch"],bundles:["editor-ui"]}),undo:Object.freeze({tokens:["no-undo"],bundles:["editor-ui"]}),history:Object.freeze({tokens:[],bundles:["editor-ui"]})}),gn=Object.freeze({"editor-ui":Object.freeze(["no-data","no-save","no-snapshot","no-watch","no-undo"])}),hn=Object.freeze(["no-save","no-snapshot","no-trigger-autosave","no-dirty","no-watch","no-undo","no-data","freeze","editor-ui","live"]);function ue(e,n){if(!e||e.nodeType!==1)return!1;let t=e.getAttribute?.("clay");return!!(t&&t.split(/\s+/).includes(n)||e.hasAttribute?.(n))}function we(e,n){if(ue(e,n))return!0;for(let[t,o]of Object.entries(gn))if(o.includes(n)&&ue(e,t))return!0;return!1}function it(e){return e==="clay"||hn.includes(e)}var yn=["mutations-ignore","save-remove","save-ignore","save-freeze","no-undo","no-watch"];function wn(){if(typeof window>"u")return null;let e=window.clay?.region||window.hyperclay?.region;return e&&typeof e.resolveRegionPolicy=="function"?e.resolveRegionPolicy:null}function be(e){let n=wn();if(n)try{if(!n(e).undoable)return!0}catch{}let t=e&&e.nodeType!==1?e.parentElement:e;if(t&&t.closest&&t.closest(rt))return!0;for(;t&&t.nodeType===1;){if(we(t,"no-undo")||we(t,"no-watch"))return!0;for(let o of yn)if(ue(t,o))return!0;t=t.parentElement}return!1}function bn(e){let n=e.target,t=n.cloneNode(!1),o=t;for(;n.parentElement;){n=n.parentElement;let a=n.cloneNode(!1);a.appendChild(t),t=a}return e.oldValue==null?o.removeAttribute(e.attributeName):o.setAttribute(e.attributeName,e.oldValue),be(o)}function ee(e,n,t){if(t?.type==="attributes"&&it(t.attributeName)){if(be(e)&&bn(t))return!0}else if(be(e))return!0;if(t&&t.type==="attributes"){if(t.attributeName&&ot.test(t.attributeName.toLowerCase()))return!0;if(n)try{if(n(t.attributeName,t.target))return!0}catch{}}return!1}function at(){let e=new Map;function n(a,i){let s=e.get(a);return s||(s=new Set,e.set(a,s)),s.add(i),()=>t(a,i)}function t(a,i){let s=e.get(a);s&&s.delete(i)}function o(a,i){let s=e.get(a);if(s)for(let d of Array.from(s))try{d(i)}catch(f){console.error("[hyper-undo] listener threw",f)}}return{on:n,off:t,emit:o}}var kn=/[.?!]["'\u201D\u2019)\]]*$/,vn=new Set(["insertParagraph","insertLineBreak"]),En=new Set(["insertFromPaste","insertFromDrop","insertFromYank","insertReplacementText","deleteByCut","deleteByDrag"]),An=new Set(["Enter","Backspace","Delete"]),Sn=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End","PageUp","PageDown"]);function ke(e){return kn.test(e)}function ut(e,{sentence:n,endStep:t,stepOpen:o=()=>!0,composing:a}){let i=e.ownerDocument&&e.ownerDocument.defaultView;if(!i)return()=>{};let s=m=>!!m&&typeof m.nodeType=="number"&&(m===e||e.contains(m)),d=!1,f=!1,y=!1,p={kind:"other",host:null},w=m=>En.has(m)||m.startsWith("format")?"alone":m.startsWith("delete")?"delete":m.startsWith("insert")?"insert":"other",k=m=>{if(!m)return null;let T=m.nodeType===1?m:m.parentElement;return T&&T.closest&&T.closest('[contenteditable]:not([contenteditable="false"])')||m},A=()=>{d&&(d=!1,t())},S=m=>{if(!n||m.isComposing||!s(m.target))return;let T=m.inputType||"",V=w(T),Y=k(m.target),te=i.getSelection&&i.getSelection(),G=!te||te.isCollapsed,se=f;f=!1;let U=y;if(y=!1,(V==="alone"||!U&&V!==p.kind&&V!=="other"&&p.kind!=="other"||!U&&(p.host!==null&&Y!==p.host||!G||se))&&t(),p={kind:V,host:Y},V==="alone"){d=!0,setTimeout(A,0);return}let W=T==="insertText"&&(m.data===" "||m.data==="\xA0");!W&&!vn.has(T)||W&&!o()||ke(Nn(i))&&(d=!0,setTimeout(A,0))},R=m=>{s(m.target)&&A()},C=m=>{s(m.target)&&a(!0)},D=m=>{s(m.target)&&a(!1)},K=m=>{s(m.target)&&(f=!0)},B=m=>{if(!s(m.target))return;if(Sn.has(m.key)){f=!0;return}if(!n||m.isComposing||m.keyCode===229||m.ctrlKey||m.metaKey||!m.key||m.key.length!==1&&!An.has(m.key))return;let T=i.getSelection&&i.getSelection(),V=p.host!==null&&k(m.target)!==p.host;!f&&!V&&(!T||T.isCollapsed)||(t(),f=!1,y=!0,setTimeout(()=>{y=!1},0))};return e.addEventListener("beforeinput",S,!0),e.addEventListener("input",R,!0),e.addEventListener("compositionstart",C,!0),e.addEventListener("compositionend",D,!0),e.addEventListener("pointerdown",K,!0),e.addEventListener("keydown",B,!0),()=>{e.removeEventListener("beforeinput",S,!0),e.removeEventListener("input",R,!0),e.removeEventListener("compositionstart",C,!0),e.removeEventListener("compositionend",D,!0),e.removeEventListener("pointerdown",K,!0),e.removeEventListener("keydown",B,!0)}}function Nn(e){let n=e.getSelection&&e.getSelection();if(!n||!n.isCollapsed||!n.anchorNode)return"";let t=n.anchorNode,o=t.nodeType===1?t:t.parentElement,a=o&&o.closest('[contenteditable]:not([contenteditable="false"])');if(!a)return"";let i=a.ownerDocument.createRange();return i.setStart(a,0),i.setEnd(t,n.anchorOffset),i.toString().replace(/\u200B/g,"").slice(-8)}var Tn={maxHistory:100,idleWindowMs:500,idleLabel:"Edit",recording:"automatic",ignoreAttribute:null,isProtected:null,ignoreNode:null,durableForm:null,typingBreak:null,refused:null,debug:!1};function ve(e){let n={...Tn,...e};if(!n.scope)throw new Error("hyper-undo: scope is required");let t=at(),o=[],a=[],i=`u${Math.random().toString(36).slice(2,8)}`,s=0,d=null,f=[],y=null,p=null,w=0,k=!1,A=n.recording==="commands"?"commands":"automatic",S=null,R=!1,C=new WeakMap,D=!1,K=!1,B=null;function m(...r){n.debug&&console.log("[hyper-undo]",...r)}function T(){k||(k=!0,p=V(F),p.observe(n.scope,{childList:!0,attributes:!0,characterData:!0,subtree:!0,attributeOldValue:!0,characterDataOldValue:!0}),B=ut(n.scope,{sentence:n.typingBreak==="sentence",stepOpen:()=>(w===0&&p&&F(p.takeRecords()),f.length>0),endStep:z,composing:yt}),m("started"))}function V(r){let u=typeof document<"u"&&n.scope===document.body,l=typeof window<"u"&&(window.clay?.Mutation||window.hyperclay?.Mutation)||null;return u&&l&&typeof l.createObserver=="function"?(m("sourcing records from the platform Mutation hub (shared observer)"),l.createObserver(r)):new MutationObserver(r)}function Y(){k&&(k=!1,p&&(p.disconnect(),p=null),B&&(B(),B=null),D=!1,q(),o.length=0,a.length=0,f=[],d=null,S=null,R=!1,w=0,C=new WeakMap,m("stopped"))}function te(){let r=n.scope;return!!(r&&r.nodeType===1&&r.isConnected===!1)}function G(r,u){try{let l=u(r);return typeof l=="string"?l:null}catch{return null}}function se(r,{read:u,write:l,prop:c="content"}={}){if(!r||typeof u!="function"||typeof l!="function")return()=>{};let h={prop:c,read:u,write:l,baseline:G(r,u)};return C.set(r,h),()=>{C.get(r)===h&&C.delete(r)}}function U(r){for(let u=r;u;u=u.parentNode)if(C.has(u))return u;return null}function W(r){let u=U(r.target);return!!u&&!(r.type==="attributes"&&r.target===u)}function L(r){let u=new Set;for(let l of r)W(l)&&u.add(U(l.target));return u}function le(r){let u=[];for(let l of r){let c=C.get(l),h=G(l,c.read);if(h!=null){if(ae(h,c.baseline)){c.baseline=h;continue}c.baseline!=null&&u.push({kind:"value",target:l,prop:c.prop,oldValue:c.baseline,newValue:h,read:c.read,write:c.write,content:!0}),c.baseline=h}}return u}function j(r){for(let u of r){let l=C.get(u);l.baseline=G(u,l.read)}}function Te(r){let u=L(r);!K&&f.some(l=>l.kind==="value"?u.has(l.target):r.some(c=>c.target===l.target&&(c.type==="characterData"?l.kind==="text":c.type==="attributes"&&c.attributeName===l.name)))&&(K=!0),j(u)}function F(r){Ce(r,!1)}function Ce(r,u){if(S){for(let c of r)S.records.push(c);return}if(A==="commands"){j(L(r));return}if(w>0){Te(r);return}let l=de(gt(r),u);for(let c of le(L(r)))l.push(c);if(l.length>0){for(let c of l)f.push(c);ce()}}function gt(r){return typeof n.ignoreNode!="function"?r:r.filter(u=>{if(u.type!=="childList")return!0;let l=[...u.addedNodes,...u.removedNodes];return l.length===0?!0:!l.every(c=>ht(c))})}function ht(r){try{return!!n.ignoreNode(r)}catch{return!1}}function de(r,u=!1){let l=_t(r),c=r.filter(h=>(ge(h.target)||l(h.target)||u&&ze(h.target))&&!W(h)&&!ee(h.target,n.ignoreAttribute,h));return We(c,h=>ee(h,n.ignoreAttribute))}function yt(r){D=!!r,!D&&f.length>0&&ce()}function ce(){q(),y=setTimeout(Ie,n.idleWindowMs)}function Ie(){if(y=null,D){y=setTimeout(Ie,n.idleWindowMs);return}fe()}function q(){y!=null&&(clearTimeout(y),y=null)}function fe(){if(y=null,f.length===0)return;let r=f;f=[],ne(n.idleLabel,r)}function ne(r,u){let l=Qe(u,{isIgnored:re,ignoreAttribute:Ve,durableForm:n.durableForm});if(l.steps.length===0)return m("commit",r,"with nothing to record"),t.emit("commit"),null;let c={id:`${i}-${++s}`,label:r,timestamp:Date.now(),primitives:u,certificate:l};for(o.push(c),a.length=0,d=null;o.length>n.maxHistory;)o.shift();return m("commit",r,"primitives:",u.length),t.emit("commit"),c}function re(r){return ee(r,n.ignoreAttribute)}function Ve(r,u,l=null){if(typeof n.ignoreAttribute!="function")return!1;try{return!!n.ignoreAttribute(r,u,l)}catch{return!1}}function wt(r){if(typeof n.isProtected!="function")return!1;try{return!!n.isProtected(r)}catch{return!1}}function bt(r,u){if(!k)throw new Error("hyper-undo: scope not started");if(A==="commands")return xe(r,u,{honorPause:!0,receipt:!1});F(p.takeRecords()),z();let l=w===0?Pe():null,c=u();if(c&&typeof c.then=="function")throw new Error("hyper-undo: commit() fn must be synchronous; returned a Promise");if(Ce(p.takeRecords(),!0),l!=null&&Re(l),f.length===0){t.emit("commit");return}q();let h=f;f=[],ne(r,h)}function kt(r){if(!k)throw new Error("hyper-undo: scope not started");if(!p)return;if(w>1){j(L(p.takeRecords()));return}z();let u=p.takeRecords(),l=de(u,!0);for(let c of le(L(u)))l.push(c);l.length!==0&&(q(),ne(r,l))}function vt(){p&&j(L(p.takeRecords()))}function pe(){let r=n.scope;return r&&r.ownerDocument||(typeof document<"u"?document:null)}function oe(){let r=pe();return!r||!r.head||typeof r.head.querySelector!="function"?null:r.head.querySelector("title")}function Pe(){let r=oe();return r?r.textContent:null}function Re(r){let u=oe();if(!u||r==null)return;let l=u.textContent;l!==r&&_e({kind:"value",target:u,prop:"textContent",oldValue:r,newValue:l})}function Et(r){if(!r)return null;let u=pe();if(!u||r.target!==u||r.prop!=="title")return r;let l=oe();return l?{kind:"value",target:l,prop:"textContent",oldValue:r.oldValue,newValue:r.newValue}:null}function At(){if(typeof window>"u")return!1;let r=window.clay?.effect||window.hyperclay?.effect;return!!(r&&r.running)}function St(){p&&F(p.takeRecords()),z(),S={records:[],primitives:[]}}function Nt(){let r=S;if(S=null,!r)return[];let u=de(r.records,!0);for(let l of le(L(r.records)))u.push(l);for(let l of r.primitives)u.push(l);return u}function xe(r,u,{honorPause:l,receipt:c}){if(typeof u!="function")throw new Error("hyper-undo: command() needs a synchronous function");if(S)throw new Error("hyper-undo: command() cannot nest inside another command");if(R)throw new Error("hyper-undo: command() cannot run during undo or redo");if(At())throw new Error("hyper-undo: command() cannot run inside a derived-effect context");if(u.constructor&&u.constructor.name==="AsyncFunction")throw new Error("hyper-undo: command() fn must be synchronous; it was declared async");let h=l&&w>0,v=h?null:Pe();St();let x=[],E=null,P;try{try{P=u()}catch($){E=$}if(p&&F(p.takeRecords()),P&&typeof P.then=="function"){try{P.then(void 0,()=>{})}catch{}E||(E=new Error("hyper-undo: command() fn must be synchronous; returned a Promise"))}h||Re(v)}finally{x=Nt()}let O=h||x.length===0?null:ne(r,x);if(E)throw E;return c?O?{id:O.id,label:O.label}:null:O}function Tt(r,u){if(!k)throw new Error("hyper-undo: scope not started");return xe(r,u,{honorPause:!1,receipt:!0})}function Ct(r){if(r!=="automatic"&&r!=="commands")throw new Error("hyper-undo: setRecording() takes 'automatic' or 'commands'");if(S)throw new Error("hyper-undo: setRecording() cannot change while a command is running");return A===r||(z(),A=r,m("recording",r)),A}function Oe(r){if(!k||!r||!S&&(w>0||A==="commands"))return;let u=Et(r);u&&_e(u)}function _e(r){if(S){S.primitives.push(r);return}f.push(r),ce()}function It(r,{prop:u="value",oldValue:l,newValue:c,read:h,write:v}={}){!r||l===c||Oe({kind:"value",target:r,prop:u,oldValue:l,newValue:c,read:h,write:v})}function z(){w===0&&p&&F(p.takeRecords()),f.length!==0&&(q(),fe())}function Le(){w===0&&p&&F(p.takeRecords()),w++,m("paused",w)}function Me(){w!==0&&(w--,w===0&&p&&(Te(p.takeRecords()),K&&(K=!1,q(),fe())),m("resumed",w))}function De(r,u){if(te())return Y(),{ok:!1,code:"disconnected"};if(typeof n.holdReplay=="function"&&n.holdReplay())return{ok:!1,code:"held"};z();let l=r==="undo"?o:a,c=r==="undo"?a:o,h=[],v=l.at(-1);if(!v)return{ok:!1,code:"empty"};if(u&&u!==v.id){let E=Be(u)||v;return me(E,r,"stale-entry")}let x=n.refused==="skip"&&!u;for(;v;){let E;R=!0;try{E=et(v.certificate,r,{isIgnored:re,ignoreAttribute:Ve,durableForm:n.durableForm,isProtected:wt,inScope:Lt,liveNodesWithIds:Mt})}finally{R=!1}if(!E.ok){if(!x)return me(v,r,E.code,E.targets);Ke(v,r,E.code,E.targets,h),v=l.at(-1);continue}Le();let P;R=!0;try{P=nt(E.operations)}finally{R=!1,Me()}if(!P.ok){if(m(`${r} failed and was rolled back`,P.error),!x)return me(v,r,"replay-error");Ke(v,r,"replay-error",[],h),v=l.at(-1);continue}j(new Set(E.operations.filter($=>$.type==="value"&&C.has($.target)).map($=>$.target))),l.pop(),c.push(v),d=null;let O={ok:!0,entryId:v.id,label:v.label,direction:r};return h.length&&(O.skipped=h),P.caret&&(O.caret=P.caret),m(r,v.label),t.emit(r,O),O}return{ok:!1,code:"empty",direction:r,skipped:h}}function Ke(r,u,l,c,h){d={entryId:r.id,direction:u,code:l,targets:c};let v=Fe(r.id);(u==="undo"?o:a).pop(),d=null;let E={entryId:r.id,label:r.label,direction:u,code:l,targets:c,description:v};m("skipped",u,l),t.emit("skipped",E),h.push(E)}function Vt(r){return De("undo",r&&r.entryId)}function Pt(r){return De("redo",r&&r.entryId)}function Be(r){return o.find(u=>u.id===r)||a.find(u=>u.id===r)||null}function me(r,u,l,c=[]){return d={entryId:r.id,direction:u,code:l,targets:c},m("refused",u,l),t.emit("refused",{entryId:r.id,label:r.label,direction:u,code:l,targets:c}),{ok:!1,code:l,entryId:r.id,label:r.label,direction:u}}function Rt(r){if(!d||d.entryId!==r)return{ok:!1,code:"not-refused",entryId:r};let u=d.direction,l=u==="undo"?o:a,c=l.at(-1);return!c||c.id!==r?{ok:!1,code:"stale-entry",entryId:r}:(l.pop(),d=null,m("discarded",c.label),t.emit("discard",{entryId:r,label:c.label,direction:u}),{ok:!0,entryId:r,direction:u})}function Fe(r){let u=Be(r);if(!u||!u.certificate||!u.certificate.replayable)return null;let l=d&&d.entryId===u.id?{direction:d.direction,code:d.code,targets:(d.targets||[]).map(c=>({id:c.id??null,kind:c.kind??null}))}:null;return{id:u.id,label:u.label,timestamp:u.timestamp,refused:l,steps:u.certificate.steps.map(Ot)}}function xt(r){return typeof r!="string"?null:r.replace(/#form:("(?:[^"\\]|\\.)*")/g,(u,l)=>{try{return JSON.parse(l)}catch{return""}})}function Ot(r){if(r.type==="move")return{kind:"move",node:{id:I(r.node).id},from:{id:I(r.sourceParent).id},to:{id:I(r.destParent).id}};if(r.type==="add"||r.type==="restore")return{kind:r.type==="add"?"add":"remove",parent:{id:I(r.parent).id},nodes:r.nodes.map((v,x)=>({id:I(v).id,html:xt(r.content[x])}))};let u=r.primitive,l={id:I(u.target).id},c=u.oldValue??null,h=u.newValue??null;return r.type==="value"?{kind:"value",target:l,prop:u.prop??"value",before:c,after:h}:r.type==="text"?{kind:"text",target:l,before:c,after:h}:r.type==="attr-set"||r.type==="attr-add"||r.type==="attr-remove"?{kind:"attribute",target:l,name:u.name??null,before:c,after:h}:{kind:r.type,target:l,before:c,after:h}}function _t(r){let u=new Set,l=!0;for(;l;){l=!1;for(let c of r)if(!(c.type!=="childList"||!c.removedNodes?.length)&&!W(c)&&!(!ge(c.target)&&!qe(c.target,u))&&!ee(c.target,n.ignoreAttribute,c))for(let h of c.removedNodes)u.has(h)||(u.add(h),l=!0)}return c=>!ge(c)&&qe(c,u)}function qe(r,u){for(let l=r;l;l=l.parentNode)if(u.has(l))return!0;return!1}function ge(r){let u=n.scope;return!u||!r||typeof r.nodeType!="number"?!1:r===u||typeof u.contains=="function"&&u.contains(r)}function ze(r){let u=pe(),l=u&&u.head;if(!l||!r)return!1;let c=r.nodeType===1?r:r.parentElement;for(;c&&c!==l;c=c.parentElement)if(c.localName==="title")return!1;return c===l}function Lt(r){let u=n.scope;return!r||!u?!1:r===u||oe()===r||ze(r)?!0:typeof u.contains=="function"?u.contains(r):!1}function Mt(r){let u=n.scope;if(!r||r.length===0||typeof u?.querySelectorAll!="function")return[];let l=new Set(r),c=[];for(let h of u.querySelectorAll("[data-id]"))l.has(h.getAttribute("data-id"))&&(re(h)||c.push(h));return c}function Dt(){p&&j(L(p.takeRecords())),o.length=0,a.length=0,f=[],d=null,q(),m("cleared"),t.emit("clear")}return{_config:n,_tracksContentAt:r=>A!=="commands"&&!!U(r),_recordsAt:r=>A!=="commands"&&!re(r),start:T,stop:Y,commit:bt,commitCaptured:kt,discardCaptured:vt,flush:z,command:Tt,setRecording:Ct,record:Oe,recordValue:It,trackContent:se,undo:Vt,redo:Pt,clear:Dt,discard:Rt,describe:Fe,pause:Le,resume:Me,on:t.on,off:t.off,get canUndo(){return o.length>0},get canRedo(){return a.length>0},get isPaused(){return w>0},get history(){return o.map(r=>{let u={id:r.id,label:r.label,timestamp:r.timestamp};return d&&d.entryId===r.id&&(u.refused={direction:d.direction,code:d.code,targets:d.targets}),u})},get future(){return a.map(r=>{let u={id:r.id,label:r.label,timestamp:r.timestamp};return d&&d.entryId===r.id&&(u.refused={direction:d.direction,code:d.code,targets:d.targets}),u}).reverse()},get scope(){return n.scope}}}var Cn=new Set(["checkbox","radio","button","submit","reset","image","file","range","color"]);function dt(e){let n=typeof e.composedPath=="function"?e.composedPath():[];return n.length>0?n:Vn(e.target)}function In(e){for(let n of dt(e)){if(!n||n.nodeType!==1)continue;let t=String(n.tagName||"").toUpperCase();if(t==="TEXTAREA"||t==="SELECT"||t==="INPUT"&&!Cn.has(String(n.type||n.getAttribute?.("type")||"text").toLowerCase()))return!0}return!1}function st(e){for(let n of dt(e)){if(!n||n.nodeType!==1)continue;if(n.isContentEditable===!0)return!0;let t=n.getAttribute&&n.getAttribute("contenteditable");if(t!=null&&String(t).toLowerCase()!=="false")return!0}return!1}function Ee(e,n){if(!e||!e.closest||!Array.isArray(n))return!1;for(let t of n)try{if(e.closest(t))return!0}catch{}return!1}function lt(e,n){if(In(e))return!0;let t=n._config,o=e.target;return t.editableKeys!=="page"?st(e)||Ee(o,t.shadowKeydownIn):Ee(o,t.ownKeysIn)||n._tracksContentAt(o)?!1:Ee(o,t.shadowKeydownIn)?!0:st(e)&&!n._recordsAt(o)}function Vn(e){let n=[];for(let t=e;t;t=t.parentNode||(t.host??null))n.push(t);return n}function ct(e,n){let t=i=>{let s=e.scope;if(s&&s.nodeType===1&&s.isConnected===!1){n&&n();return}if(i.defaultPrevented||i.isComposing||i.keyCode===229||lt(i,e)||!(i.metaKey||i.ctrlKey))return;let f=(i.key||"").toLowerCase();if(f==="z"&&!i.shiftKey){i.preventDefault(),i.stopPropagation(),e.undo();return}if(f==="z"&&i.shiftKey){i.preventDefault(),i.stopPropagation(),e.redo();return}if(f==="y"&&!i.shiftKey){i.preventDefault(),i.stopPropagation(),e.redo();return}},o=i=>{if(i.inputType!=="historyUndo"&&i.inputType!=="historyRedo")return;let s=e.scope;s&&s.nodeType===1&&s.isConnected===!1||i.defaultPrevented||i.isComposing||lt(i,e)||(i.preventDefault(),i.stopPropagation(),i.inputType==="historyRedo"?e.redo():e.undo())},a=e._config.editableKeys==="page";return window.addEventListener("keydown",t,!0),a&&window.addEventListener("beforeinput",o,!0),()=>{window.removeEventListener("keydown",t,!0),a&&window.removeEventListener("beforeinput",o,!0)}}var Ae=[".CodeMirror",".cm-editor",".monaco-editor",".ace_editor",".ql-editor",".tiptap",".ProseMirror",".overtype-input","[data-richclay-active]",".ck-editor__editable","[data-lexical-editor]","[data-slate-editor]","trix-editor",".mce-content-body"],g=null,Se=null,ft=null,M=null;function pt(e,n){if(M){if(M.inst===e)return M.cleanup;throw new Error("hyper-undo: another scope already owns the global Cmd+Z binding (bindKeys: true). Stop it first, or use bindKeys: false for additional scopes.")}let t=ct(e,n);return M={inst:e,cleanup:t},t}function mt(e){M&&M.inst===e&&(M.cleanup(),M=null)}var Ne={defaults:{shadowKeydownIn:Ae},start(e={}){let n=e.scope||(typeof document<"u"?document.body:null);if(!n)throw new Error("hyper-undo: no scope (need document.body or explicit { scope })");if(g){if(Se===n)return console.warn("[hyper-undo] start() called again on existing singleton; ignoring new options"),g;throw new Error("hyper-undo: start() called with a different scope while the singleton is already started. Use undo.create({ scope }) for additional scopes, or call undo.stop() first.")}let t={...e,scope:n,shadowKeydownIn:e.shadowKeydownIn||Ae};return g=ve(t),g.start(),Se=n,e.bindKeys!==!1&&(ft=pt(g,()=>Ne.stop())),g},stop(){g&&(mt(g),ft=null,g.stop(),g=null,Se=null)},create(e={}){let n=e.scope||(typeof document<"u"?document.body:null);if(!n)throw new Error("hyper-undo: no scope (need document.body or explicit { scope })");let t={...e,scope:n,shadowKeydownIn:e.shadowKeydownIn||Ae},o=ve(t),a=null,i={_config:o._config,commit:o.commit,command:o.command,setRecording:o.setRecording,commitCaptured:o.commitCaptured,discardCaptured:o.discardCaptured,flush:o.flush,record:o.record,recordValue:o.recordValue,trackContent:o.trackContent,undo:o.undo,redo:o.redo,clear:o.clear,discard:o.discard,describe:o.describe,pause:o.pause,resume:o.resume,on:o.on,off:o.off,get canUndo(){return o.canUndo},get canRedo(){return o.canRedo},get isPaused(){return o.isPaused},get history(){return o.history},get future(){return o.future},get scope(){return o.scope},start(){e.bindKeys&&(a=pt(o,()=>i.stop())),o.start()},stop(){mt(o),a=null,o.stop()}};return i},commit(e,n){return g?g.commit(e,n):void 0},command(e,n){return g?g.command(e,n):void 0},setRecording(e){return g?g.setRecording(e):void 0},commitCaptured(e){return g?g.commitCaptured(e):void 0},discardCaptured(){return g?g.discardCaptured():void 0},record(e){return g?g.record(e):void 0},recordValue(e,n){return g?g.recordValue(e,n):void 0},trackContent(e,n){return g?g.trackContent(e,n):()=>{}},undo(e){return g?g.undo(e):void 0},redo(e){return g?g.redo(e):void 0},clear(){return g?g.clear():void 0},discard(e){return g?g.discard(e):void 0},describe(e){return g?g.describe(e):void 0},pause(){return g?g.pause():void 0},resume(){return g?g.resume():void 0},flush(){return g?g.flush():void 0},on(e,n){return g?g.on(e,n):void 0},off(e,n){return g?g.off(e,n):void 0},get canUndo(){return g?g.canUndo:!1},get canRedo(){return g?g.canRedo:!1},get history(){return g?g.history:[]},get future(){return g?g.future:[]},get isPaused(){return g?g.isPaused:!1}};var Pn=Ne;return $t(Rn);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyper-undo",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "DOM-state undo/redo via MutationObserver inverse-op replay. Standalone or paired with hyperclayjs.",
5
5
  "keywords": [
6
6
  "undo",
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createScope } from './scope.js'
2
2
  import { installKeys } from './keys.js'
3
+ import { endsSentence } from './typing.js'
3
4
 
4
5
  const DEFAULT_SHADOW_LIST = [
5
6
  '.CodeMirror',
@@ -21,6 +22,14 @@ const DEFAULT_SHADOW_LIST = [
21
22
  // in richclay/src/richclay.js, which says it marks the region so hyper-undo
22
23
  // "defers to Squire instead of fighting it".
23
24
  '[data-richclay-active]',
25
+ // Embedded third-party editors keep their own history: the page stack never
26
+ // records what is typed in them, so a page-mode Cmd+Z there would revert some
27
+ // other field instead of the editor's own last change.
28
+ '.ck-editor__editable',
29
+ '[data-lexical-editor]',
30
+ '[data-slate-editor]',
31
+ 'trix-editor',
32
+ '.mce-content-body',
24
33
  ]
25
34
 
26
35
  let singleton = null // the Scope instance returned by createScope
@@ -113,6 +122,7 @@ const undo = {
113
122
  flush: inst.flush,
114
123
  record: inst.record,
115
124
  recordValue: inst.recordValue,
125
+ trackContent: inst.trackContent,
116
126
  undo: inst.undo,
117
127
  redo: inst.redo,
118
128
  clear: inst.clear,
@@ -152,6 +162,7 @@ const undo = {
152
162
  discardCaptured() { return singleton ? singleton.discardCaptured() : undefined },
153
163
  record(p) { return singleton ? singleton.record(p) : undefined },
154
164
  recordValue(t, o) { return singleton ? singleton.recordValue(t, o) : undefined },
165
+ trackContent(root, o) { return singleton ? singleton.trackContent(root, o) : () => {} },
155
166
  undo(opts) { return singleton ? singleton.undo(opts) : undefined },
156
167
  redo(opts) { return singleton ? singleton.redo(opts) : undefined },
157
168
  clear() { return singleton ? singleton.clear() : undefined },
@@ -169,5 +180,5 @@ const undo = {
169
180
  get isPaused() { return singleton ? singleton.isPaused : false },
170
181
  }
171
182
 
172
- export { undo }
183
+ export { undo, endsSentence }
173
184
  export default undo
package/src/keys.js CHANGED
@@ -2,16 +2,26 @@
2
2
  // subtree)? The browser's own undo belongs there, not the page stack's.
3
3
  const NO_TEXT_INPUTS = new Set(['checkbox', 'radio', 'button', 'submit', 'reset', 'image', 'file', 'range', 'color'])
4
4
 
5
- function ownsNativeUndo(event) {
5
+ function pathOf(event) {
6
6
  const path = typeof event.composedPath === 'function' ? event.composedPath() : []
7
- const nodes = path.length > 0 ? path : chainFromTarget(event.target)
8
- for (const node of nodes) {
7
+ return path.length > 0 ? path : chainFromTarget(event.target)
8
+ }
9
+
10
+ function inFormControl(event) {
11
+ for (const node of pathOf(event)) {
9
12
  if (!node || node.nodeType !== 1) continue
10
13
  const tag = String(node.tagName || '').toUpperCase()
11
14
  if (tag === 'TEXTAREA' || tag === 'SELECT') return true
12
15
  // An input that takes no typed text has no native undo of its own: a checkbox,
13
16
  // a radio or a button leaves the key to the page stack.
14
17
  if (tag === 'INPUT' && !NO_TEXT_INPUTS.has(String(node.type || node.getAttribute?.('type') || 'text').toLowerCase())) return true
18
+ }
19
+ return false
20
+ }
21
+
22
+ function inEditable(event) {
23
+ for (const node of pathOf(event)) {
24
+ if (!node || node.nodeType !== 1) continue
15
25
  if (node.isContentEditable === true) return true
16
26
  // jsdom (and older engines) do not resolve isContentEditable, so read the
17
27
  // declaration itself; an unset or explicit "false" is not editable.
@@ -21,6 +31,28 @@ function ownsNativeUndo(event) {
21
31
  return false
22
32
  }
23
33
 
34
+ function inAny(target, selectors) {
35
+ if (!target || !target.closest || !Array.isArray(selectors)) return false
36
+ for (const selector of selectors) {
37
+ try { if (target.closest(selector)) return true }
38
+ catch (_) { /* invalid selector, skip */ }
39
+ }
40
+ return false
41
+ }
42
+
43
+ // Does this history key or history input belong to someone other than the page
44
+ // stack? "page" owns editable content the scope records; a form control, an
45
+ // authored no-undo region or another in-page editor keeps its own undo.
46
+ function standsDown(event, scope) {
47
+ if (inFormControl(event)) return true
48
+ const config = scope._config
49
+ const target = event.target
50
+ if (config.editableKeys !== 'page') return inEditable(event) || inAny(target, config.shadowKeydownIn)
51
+ if (inAny(target, config.ownKeysIn) || scope._tracksContentAt(target)) return false
52
+ if (inAny(target, config.shadowKeydownIn)) return true
53
+ return inEditable(event) && !scope._recordsAt(target)
54
+ }
55
+
24
56
  function chainFromTarget(target) {
25
57
  const out = []
26
58
  for (let node = target; node; node = node.parentNode || (node.host ?? null)) out.push(node)
@@ -44,19 +76,7 @@ export function installKeys(scope, onDetached) {
44
76
  if (event.defaultPrevented) return
45
77
  // The IME owns keys while it composes.
46
78
  if (event.isComposing || event.keyCode === 229) return
47
- // A plain form control keeps the browser's own text undo. Only the unsent
48
- // control changes; Save/Enter later commits that text as a page command.
49
- if (ownsNativeUndo(event)) return
50
-
51
- // Bypass for in-page editors (CodeMirror, Monaco, etc.)
52
- const target = event.target
53
- const shadow = scope._config.shadowKeydownIn
54
- if (target && target.closest && Array.isArray(shadow)) {
55
- for (const selector of shadow) {
56
- try { if (target.closest(selector)) return }
57
- catch (_) { /* invalid selector, skip */ }
58
- }
59
- }
79
+ if (standsDown(event, scope)) return
60
80
 
61
81
  const mod = event.metaKey || event.ctrlKey
62
82
  if (!mod) return
@@ -80,6 +100,24 @@ export function installKeys(scope, onDetached) {
80
100
  }
81
101
  }
82
102
 
103
+ // Chrome delivers the Edit menu's Undo as a cancellable beforeinput event.
104
+ // Owned by the same rule as the key, it moves the page stack instead.
105
+ const onHistoryInput = (event) => {
106
+ if (event.inputType !== 'historyUndo' && event.inputType !== 'historyRedo') return
107
+ const scopeEl = scope.scope
108
+ if (scopeEl && scopeEl.nodeType === 1 && scopeEl.isConnected === false) return
109
+ if (event.defaultPrevented || event.isComposing) return
110
+ if (standsDown(event, scope)) return
111
+ event.preventDefault(); event.stopPropagation()
112
+ if (event.inputType === 'historyRedo') scope.redo()
113
+ else scope.undo()
114
+ }
115
+
116
+ const ownsInput = scope._config.editableKeys === 'page'
83
117
  window.addEventListener('keydown', handler, true)
84
- return () => window.removeEventListener('keydown', handler, true)
118
+ if (ownsInput) window.addEventListener('beforeinput', onHistoryInput, true)
119
+ return () => {
120
+ window.removeEventListener('keydown', handler, true)
121
+ if (ownsInput) window.removeEventListener('beforeinput', onHistoryInput, true)
122
+ }
85
123
  }
package/src/primitives.js CHANGED
@@ -124,7 +124,7 @@ export function recordsToPrimitives(records, ignoreNode = null) {
124
124
  // more than once. Keep ONE primitive per (target, field) carrying the first old
125
125
  // value and the final new value, and drop the ones whose endpoints are equal:
126
126
  // undo must walk back to the value before the entry, not to an intermediate one.
127
- export function normalizePrimitives(primitives) {
127
+ export function normalizePrimitives(primitives, { sameContent = (a, b) => a === b } = {}) {
128
128
  const out = []
129
129
  const slots = new Map() // target → Map(field → index in out)
130
130
 
@@ -148,6 +148,7 @@ export function normalizePrimitives(primitives) {
148
148
  for (const p of out) {
149
149
  if (scalarField(p) == null) { normalized.push(p); continue }
150
150
  if (p.oldValue === p.newValue) continue
151
+ if (p.kind === 'value' && p.content === true && sameContent(p.oldValue, p.newValue)) continue
151
152
  normalized.push(reclassifyScalar(p))
152
153
  }
153
154
  return normalized