@lesjoursfr/edith 2.1.2 → 2.1.3

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.
@@ -0,0 +1,255 @@
1
+ import { cleanDomContent, createNodeWith, hasClass, hasTagName, isHTMLElement, isSelfClosing, removeCommentNodes, removeEmptyTextNodes, removeNodes, textifyNode, unwrapNode, } from "./dom.js";
2
+ import { getSelection, moveCursorAfterNode, moveCursorInsideNode, selectNodeContents, selectNodes } from "./range.js";
3
+ /**
4
+ * Split the node at the caret position.
5
+ * @param {Range} range the caret position
6
+ * @param {HTMLElement} node the node to split
7
+ * @returns {Text} the created text node with the caret inside
8
+ */
9
+ function splitNodeAtCaret(range, node) {
10
+ // Get the node's parent
11
+ const parent = node.parentNode;
12
+ // Clone the current range & move the starting point to the beginning of the parent's node
13
+ const beforeCaret = range.cloneRange();
14
+ beforeCaret.setStart(parent, 0);
15
+ // Extract the content before the caret
16
+ const frag = beforeCaret.extractContents();
17
+ // Add a TextNode
18
+ const textNode = document.createTextNode("\u200B");
19
+ frag.append(textNode);
20
+ // Add back the content into the node's parent
21
+ parent.prepend(frag);
22
+ // Move the cursor in the created TextNode
23
+ moveCursorInsideNode(textNode);
24
+ // Return the inserted TextNode
25
+ return textNode;
26
+ }
27
+ /**
28
+ * Extract the selection from the node.
29
+ * @param {Range} range the selection to extract
30
+ * @param {HTMLElement} node the node to split
31
+ * @param {string} tag the tag to remove
32
+ * @returns {HTMLElement} the created node
33
+ */
34
+ function extractSelectionFromNode(range, node) {
35
+ // Get the node's parent
36
+ const parent = node.parentNode;
37
+ // Clone the current range & move the starting point to the beginning of the parent's node
38
+ const beforeSelection = new Range();
39
+ beforeSelection.selectNodeContents(parent);
40
+ beforeSelection.setEnd(range.startContainer, range.startOffset);
41
+ const afterSelection = new Range();
42
+ afterSelection.selectNodeContents(parent);
43
+ afterSelection.setStart(range.endContainer, range.endOffset);
44
+ // Extract the content of the selection
45
+ const fragBefore = beforeSelection.extractContents();
46
+ const fragAfter = afterSelection.extractContents();
47
+ // Add back the content into the node's parent
48
+ parent.prepend(fragBefore);
49
+ parent.append(fragAfter);
50
+ // Remove the parent from the selection
51
+ let current = !isHTMLElement(range.commonAncestorContainer)
52
+ ? range.commonAncestorContainer.parentNode
53
+ : range.commonAncestorContainer;
54
+ while (current.tagName !== node.tagName) {
55
+ // Take the parent
56
+ current = current.parentNode;
57
+ }
58
+ const innerNodes = unwrapNode(current);
59
+ // Preserve the selection
60
+ selectNodes(innerNodes);
61
+ // Return the inserted TextNode
62
+ return innerNodes[0].parentNode;
63
+ }
64
+ /**
65
+ * Create a node at the caret position.
66
+ * @param {Range} range the caret position
67
+ * @param {string} tag the tag name of the node
68
+ * @param {object} options optional parameters
69
+ * @param {string} options.textContent the text content of the node
70
+ * @returns {HTMLElement} the created node with the caret inside
71
+ */
72
+ function insertTagAtCaret(range, tag, options = {}) {
73
+ // Create the tag
74
+ const node = document.createElement(tag);
75
+ // Add a zero-width char or the word "lien" to create a valid cursor position inside the element
76
+ if (tag === "a") {
77
+ node.textContent = options.textContent || "lien";
78
+ }
79
+ else {
80
+ node.innerHTML = "\u200B";
81
+ }
82
+ // Insert the tag at the cursor position
83
+ range.insertNode(node);
84
+ // Add an extra space after the tag if it's a link
85
+ if (tag === "a") {
86
+ node.insertAdjacentText("afterend", " ");
87
+ }
88
+ // Move the cursor inside the created tag
89
+ moveCursorInsideNode(node);
90
+ // Return the inserted tag
91
+ return node;
92
+ }
93
+ /**
94
+ * Replace the current selection by the given HTML code.
95
+ * @param {string} html the HTML code
96
+ */
97
+ export function replaceSelectionByHtml(html) {
98
+ // Get the caret position
99
+ const { sel, range } = getSelection();
100
+ // Check if the user has selected something
101
+ if (range === undefined) {
102
+ return;
103
+ }
104
+ // Create the fragment to insert
105
+ const frag = document.createDocumentFragment();
106
+ // Create the nodes to insert
107
+ const el = createNodeWith("div", { innerHTML: html });
108
+ frag.append(...el.childNodes);
109
+ const lastNode = frag.childNodes[frag.childNodes.length - 1];
110
+ // Replace the current selection by the pasted content
111
+ sel.deleteFromDocument();
112
+ range.insertNode(frag);
113
+ // Preserve the selection
114
+ moveCursorAfterNode(lastNode);
115
+ }
116
+ /**
117
+ * Wrap the current selection inside a new node.
118
+ * @param {string} tag the tag name of the node
119
+ * @param {object} options optional parameters
120
+ * @param {string} options.textContent the text content of the node
121
+ * @returns {HTMLElement|Text} the created node or the root node
122
+ */
123
+ export function wrapInsideTag(tag, options = {}) {
124
+ // Get the caret position
125
+ const { sel, range } = getSelection();
126
+ // Check if the user has selected something
127
+ if (range === undefined) {
128
+ return;
129
+ }
130
+ // Check if there is a Selection
131
+ if (range.collapsed) {
132
+ // Check if a parent element has the same tag name
133
+ let parent = sel.anchorNode.parentNode;
134
+ while (!hasClass(parent, "edith-visual")) {
135
+ if (hasTagName(parent, tag)) {
136
+ // One of the parent has the same tag name
137
+ // Split the parent at the caret & insert a TextNode
138
+ return splitNodeAtCaret(range, parent);
139
+ }
140
+ // Take the parent
141
+ parent = parent.parentNode;
142
+ }
143
+ // We just have to insert a new Node at the caret position
144
+ return insertTagAtCaret(range, tag, options);
145
+ }
146
+ // There is a selection
147
+ // Check if a parent element has the same tag name
148
+ let parent = range.commonAncestorContainer;
149
+ while (!isHTMLElement(parent) || !hasClass(parent, "edith-visual")) {
150
+ if (isHTMLElement(parent) && hasTagName(parent, tag)) {
151
+ // One of the parent has the same tag name
152
+ // Extract the selection from the parent
153
+ return extractSelectionFromNode(range, parent);
154
+ }
155
+ // Take the parent
156
+ parent = parent.parentNode;
157
+ }
158
+ // Try to replace all elements with the same tag name in the selection
159
+ for (const el of [...parent.getElementsByTagName(tag)]) {
160
+ // Check if the the Element Intersect the Selection
161
+ if (sel.containsNode(el, true)) {
162
+ // Unwrap the node
163
+ const innerNodes = unwrapNode(el);
164
+ // Return the node
165
+ selectNodes(innerNodes);
166
+ parent.normalize();
167
+ return parent;
168
+ }
169
+ }
170
+ // Nothing was replaced
171
+ // Wrap the selection inside the given tag
172
+ const node = document.createElement(tag);
173
+ node.appendChild(range.extractContents());
174
+ range.insertNode(node);
175
+ // Remove empty tags
176
+ removeNodes(parent, (el) => {
177
+ return isHTMLElement(el) && !isSelfClosing(el.tagName) && (el.textContent === null || el.textContent.length === 0);
178
+ });
179
+ // Return the node
180
+ selectNodeContents(node);
181
+ return node;
182
+ }
183
+ /**
184
+ * Wrap the current selection inside a link.
185
+ * @param {string} text the text of the link
186
+ * @param {string} href the href of the link
187
+ * @param {boolean} targetBlank add target="_blank" attribute or not
188
+ * @returns {HTMLElement|Text} the created node
189
+ */
190
+ export function wrapInsideLink(text, href, targetBlank) {
191
+ // Wrap the selection inside a link
192
+ const tag = wrapInsideTag("a", { textContent: text });
193
+ // Check if we have a tag
194
+ if (tag === undefined) {
195
+ return;
196
+ }
197
+ // Check if it's a Text node
198
+ if (!isHTMLElement(tag)) {
199
+ return tag;
200
+ }
201
+ // Add an href Attribute
202
+ tag.setAttribute("href", href);
203
+ // Create a target="_blank" attribute if required
204
+ if (targetBlank === true) {
205
+ tag.setAttribute("target", "_blank");
206
+ }
207
+ // Return the tag
208
+ return tag;
209
+ }
210
+ /**
211
+ * Clear the style in the current selection.
212
+ */
213
+ export function clearSelectionStyle() {
214
+ // Get the caret position
215
+ const { sel, range } = getSelection();
216
+ // Check if there is something to do
217
+ if (range === undefined || !isHTMLElement(range.commonAncestorContainer)) {
218
+ return;
219
+ }
220
+ // Try to replace all non-text elements by their text
221
+ for (const el of [...range.commonAncestorContainer.children]) {
222
+ // Check if the the Element Intersect the Selection
223
+ if (sel.containsNode(el, true)) {
224
+ // Replace the node by its text
225
+ textifyNode(el);
226
+ }
227
+ }
228
+ }
229
+ /**
230
+ * Clean the given HTML code.
231
+ * @param {string} html the HTML code to clean
232
+ * @param {object} style active styles
233
+ * @returns {HTMLElement} the cleaned HTML code
234
+ */
235
+ export function cleanPastedHtml(html, style) {
236
+ // Create a new div with the HTML content
237
+ const result = document.createElement("div");
238
+ result.innerHTML = html;
239
+ // Clean the HTML content
240
+ cleanDomContent(result, style);
241
+ result.normalize();
242
+ // Clean empty text nodes
243
+ removeEmptyTextNodes(result);
244
+ // Fix extra stuff in the HTML code :
245
+ // - Clean spaces
246
+ // - Merge siblings tags
247
+ result.innerHTML = result.innerHTML
248
+ .replace(/\s* \s*/g, " ")
249
+ .replace(/\s+/g, " ")
250
+ .replace(/(<\/b>[\n\r\s]*<b>|<\/i>[\n\r\s]*<i>|<\/u>[\n\r\s]*<u>|<\/s>[\n\r\s]*<s>)/g, " ");
251
+ // Clean comment nodes
252
+ removeCommentNodes(result);
253
+ // Return Cleaned HTML
254
+ return result;
255
+ }
@@ -0,0 +1,47 @@
1
+ type EdithEvent = {
2
+ type: string;
3
+ ns: Array<string> | null;
4
+ handler: EventListenerOrEventListenerObject;
5
+ };
6
+ type EdithEvents = {
7
+ [key: string]: EdithEvent;
8
+ };
9
+ declare global {
10
+ interface Window {
11
+ edithEvents: EdithEvents;
12
+ }
13
+ interface Document {
14
+ edithEvents: EdithEvents;
15
+ }
16
+ interface HTMLElement {
17
+ edithEvents: EdithEvents;
18
+ }
19
+ }
20
+ export declare enum Events {
21
+ modeChanged = "edith-mode-changed",
22
+ initialized = "edith-initialized"
23
+ }
24
+ /**
25
+ * Set an event listener on every node.
26
+ * @param {Window|Document|HTMLElement|NodeList} nodes
27
+ * @param {string} events
28
+ * @param {Function} handler
29
+ */
30
+ export declare function on(nodes: Window | Document | HTMLElement | NodeListOf<HTMLElement>, events: string, handler: EventListenerOrEventListenerObject): void;
31
+ /**
32
+ * Remove event listeners from the node.
33
+ * @param {Window|Document|HTMLElement|NodeList} node
34
+ * @param {string} events
35
+ * @param {Function|undefined} handler
36
+ */
37
+ export declare function off(nodes: Window | Document | HTMLElement | NodeListOf<HTMLElement>, events: string, handler?: EventListenerOrEventListenerObject): void;
38
+ /**
39
+ * Trigger the EdithEvent on the node.
40
+ * @param {Window|Document|HTMLElement} node
41
+ * @param {string} event
42
+ * @param {Object|undefined} payload
43
+ */
44
+ export declare function trigger(node: Window | Document | HTMLElement, event: string, payload?: {
45
+ [key: string]: unknown;
46
+ }): void;
47
+ export {};
@@ -0,0 +1,100 @@
1
+ const eventsNamespace = "edithEvents";
2
+ let eventsGuid = 0;
3
+ export var Events;
4
+ (function (Events) {
5
+ Events["modeChanged"] = "edith-mode-changed";
6
+ Events["initialized"] = "edith-initialized";
7
+ })(Events || (Events = {}));
8
+ /**
9
+ * Parse an event type to separate the type & the namespace
10
+ * @param {string} string
11
+ */
12
+ function parseEventType(string) {
13
+ const [type, ...nsArray] = string.split(".");
14
+ return {
15
+ type,
16
+ ns: nsArray ?? null,
17
+ };
18
+ }
19
+ /**
20
+ * Set an event listener on the node.
21
+ * @param {Window|Document|HTMLElement} node
22
+ * @param {string} events
23
+ * @param {Function} handler
24
+ */
25
+ function addEventListener(node, events, handler) {
26
+ if (node[eventsNamespace] === undefined) {
27
+ node[eventsNamespace] = {};
28
+ }
29
+ for (const event of events.split(" ")) {
30
+ const { type, ns } = parseEventType(event);
31
+ const handlerGuid = (++eventsGuid).toString(10);
32
+ node.addEventListener(type, handler);
33
+ node[eventsNamespace][handlerGuid] = { type, ns, handler };
34
+ }
35
+ }
36
+ /**
37
+ * Remove event listeners from the node.
38
+ * @param {Window|Document|HTMLElement} node
39
+ * @param {string} events
40
+ * @param {Function|undefined} handler
41
+ */
42
+ function removeEventListener(node, events, handler) {
43
+ if (node[eventsNamespace] === undefined) {
44
+ node[eventsNamespace] = {};
45
+ }
46
+ for (const event of events.split(" ")) {
47
+ const { type, ns } = parseEventType(event);
48
+ for (const [guid, handlerObj] of Object.entries(node[eventsNamespace])) {
49
+ if (handlerObj.type !== type && type !== "*") {
50
+ continue;
51
+ }
52
+ if ((ns === null || handlerObj.ns?.includes(ns[0])) &&
53
+ (handler === undefined || (typeof handler === "function" && handler === handlerObj.handler))) {
54
+ delete node[eventsNamespace][guid];
55
+ node.removeEventListener(handlerObj.type, handlerObj.handler);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ /**
61
+ * Set an event listener on every node.
62
+ * @param {Window|Document|HTMLElement|NodeList} nodes
63
+ * @param {string} events
64
+ * @param {Function} handler
65
+ */
66
+ export function on(nodes, events, handler) {
67
+ if (nodes instanceof NodeList) {
68
+ for (const node of nodes) {
69
+ addEventListener(node, events, handler);
70
+ }
71
+ }
72
+ else {
73
+ addEventListener(nodes, events, handler);
74
+ }
75
+ }
76
+ /**
77
+ * Remove event listeners from the node.
78
+ * @param {Window|Document|HTMLElement|NodeList} node
79
+ * @param {string} events
80
+ * @param {Function|undefined} handler
81
+ */
82
+ export function off(nodes, events, handler) {
83
+ if (nodes instanceof NodeList) {
84
+ for (const node of nodes) {
85
+ removeEventListener(node, events, handler);
86
+ }
87
+ }
88
+ else {
89
+ removeEventListener(nodes, events, handler);
90
+ }
91
+ }
92
+ /**
93
+ * Trigger the EdithEvent on the node.
94
+ * @param {Window|Document|HTMLElement} node
95
+ * @param {string} event
96
+ * @param {Object|undefined} payload
97
+ */
98
+ export function trigger(node, event, payload) {
99
+ node.dispatchEvent(new CustomEvent(event, { detail: payload }));
100
+ }
@@ -0,0 +1,14 @@
1
+ export declare class History {
2
+ private buffer;
3
+ constructor();
4
+ /**
5
+ * Add a new snapshot to the history.
6
+ * @param {string} doc the element to save
7
+ */
8
+ push(doc: string): void;
9
+ /**
10
+ * Get the last saved element
11
+ * @returns {(string|null)} the last saved element or null
12
+ */
13
+ pop(): string | null;
14
+ }
@@ -0,0 +1,24 @@
1
+ export class History {
2
+ buffer = [];
3
+ constructor() { }
4
+ /**
5
+ * Add a new snapshot to the history.
6
+ * @param {string} doc the element to save
7
+ */
8
+ push(doc) {
9
+ this.buffer.push(doc);
10
+ if (this.buffer.length > 20) {
11
+ this.buffer.shift();
12
+ }
13
+ }
14
+ /**
15
+ * Get the last saved element
16
+ * @returns {(string|null)} the last saved element or null
17
+ */
18
+ pop() {
19
+ if (this.buffer.length === 0) {
20
+ return null;
21
+ }
22
+ return this.buffer.pop();
23
+ }
24
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./dom.js";
2
+ export * from "./edit.js";
3
+ export * from "./events.js";
4
+ export * from "./history.js";
5
+ export * from "./mode.js";
6
+ export * from "./range.js";
7
+ export * from "./throttle.js";
@@ -0,0 +1,7 @@
1
+ export * from "./dom.js";
2
+ export * from "./edit.js";
3
+ export * from "./events.js";
4
+ export * from "./history.js";
5
+ export * from "./mode.js";
6
+ export * from "./range.js";
7
+ export * from "./throttle.js";
@@ -0,0 +1,4 @@
1
+ export declare enum EditorModes {
2
+ Visual = 1,
3
+ Code = 2
4
+ }
@@ -0,0 +1,5 @@
1
+ export var EditorModes;
2
+ (function (EditorModes) {
3
+ EditorModes[EditorModes["Visual"] = 1] = "Visual";
4
+ EditorModes[EditorModes["Code"] = 2] = "Code";
5
+ })(EditorModes || (EditorModes = {}));
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @typedef {Object} CurrentSelection
3
+ * @property {Selection} sel the current selection
4
+ * @property {(Range|undefined)} range the current range
5
+ */
6
+ export type CurrentSelection = {
7
+ sel: Selection;
8
+ range?: Range;
9
+ };
10
+ /**
11
+ * Get the current selection.
12
+ * @returns {CurrentSelection} the current selection
13
+ */
14
+ export declare function getSelection(): CurrentSelection;
15
+ /**
16
+ * Restore the given selection.
17
+ * @param {CurrentSelection} selection the selection to restore
18
+ */
19
+ export declare function restoreSelection(selection: CurrentSelection): void;
20
+ /**
21
+ * Move the cursor inside the node.
22
+ * @param {ChildNode} target the targeted node
23
+ */
24
+ export declare function moveCursorInsideNode(target: ChildNode): void;
25
+ /**
26
+ * Move the cursor after the node.
27
+ * @param {ChildNode} target the targeted node
28
+ */
29
+ export declare function moveCursorAfterNode(target: ChildNode): void;
30
+ /**
31
+ * Select the node's content.
32
+ * @param {ChildNode} target the targeted node
33
+ */
34
+ export declare function selectNodeContents(target: ChildNode): void;
35
+ /**
36
+ * Select the given Nodes.
37
+ * @param {Array<ChildNode>} nodes The list of Nodes to select.
38
+ */
39
+ export declare function selectNodes(nodes: ChildNode[]): void;
40
+ /**
41
+ * Check if the current selection is inside the given node.
42
+ * @param {ChildNode} node the targeted node
43
+ * @returns {boolean} true if the selection is inside
44
+ */
45
+ export declare function isSelectionInsideNode(node: ChildNode): boolean;
@@ -0,0 +1,86 @@
1
+ import { isHTMLElement, isSelfClosing } from "./dom.js";
2
+ /**
3
+ * Get the current selection.
4
+ * @returns {CurrentSelection} the current selection
5
+ */
6
+ export function getSelection() {
7
+ const sel = window.getSelection();
8
+ return { sel, range: sel.rangeCount ? sel.getRangeAt(0) : undefined };
9
+ }
10
+ /**
11
+ * Restore the given selection.
12
+ * @param {CurrentSelection} selection the selection to restore
13
+ */
14
+ export function restoreSelection(selection) {
15
+ const sel = window.getSelection();
16
+ sel.removeAllRanges();
17
+ if (selection.range !== undefined) {
18
+ sel.addRange(selection.range);
19
+ }
20
+ }
21
+ /**
22
+ * Move the cursor inside the node.
23
+ * @param {ChildNode} target the targeted node
24
+ */
25
+ export function moveCursorInsideNode(target) {
26
+ const range = document.createRange();
27
+ const sel = window.getSelection();
28
+ range.setStart(target, 1);
29
+ range.collapse(true);
30
+ sel.removeAllRanges();
31
+ sel.addRange(range);
32
+ }
33
+ /**
34
+ * Move the cursor after the node.
35
+ * @param {ChildNode} target the targeted node
36
+ */
37
+ export function moveCursorAfterNode(target) {
38
+ const range = document.createRange();
39
+ const sel = window.getSelection();
40
+ range.setStartAfter(target);
41
+ range.collapse(true);
42
+ sel.removeAllRanges();
43
+ sel.addRange(range);
44
+ }
45
+ /**
46
+ * Select the node's content.
47
+ * @param {ChildNode} target the targeted node
48
+ */
49
+ export function selectNodeContents(target) {
50
+ const range = document.createRange();
51
+ const sel = window.getSelection();
52
+ range.selectNodeContents(target);
53
+ range.collapse(false);
54
+ sel.removeAllRanges();
55
+ sel.addRange(range);
56
+ }
57
+ /**
58
+ * Select the given Nodes.
59
+ * @param {Array<ChildNode>} nodes The list of Nodes to select.
60
+ */
61
+ export function selectNodes(nodes) {
62
+ // Check if we just have a self-closing tag
63
+ if (nodes.length === 1 && isHTMLElement(nodes[0]) && isSelfClosing(nodes[0].tagName)) {
64
+ moveCursorAfterNode(nodes[0]); // Move the cursor after the Node
65
+ return;
66
+ }
67
+ // Select Nodes
68
+ const range = document.createRange();
69
+ const sel = window.getSelection();
70
+ range.setStartBefore(nodes[0]);
71
+ range.setEndAfter(nodes[nodes.length - 1]);
72
+ sel.removeAllRanges();
73
+ sel.addRange(range);
74
+ }
75
+ /**
76
+ * Check if the current selection is inside the given node.
77
+ * @param {ChildNode} node the targeted node
78
+ * @returns {boolean} true if the selection is inside
79
+ */
80
+ export function isSelectionInsideNode(node) {
81
+ const { range } = getSelection();
82
+ if (range === undefined) {
83
+ return false;
84
+ }
85
+ return node.contains(range.startContainer) && node.contains(range.endContainer);
86
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Based on lodash version of throttle : https://github.com/lodash/lodash/blob/master/throttle.js
3
+ */
4
+ /**
5
+ * Creates a debounced function that delays invoking `func` until after `wait`
6
+ * milliseconds have elapsed since the last time the debounced function was
7
+ * invoked, or until the next browser frame is drawn. Provide `options` to indicate
8
+ * whether `func` should be invoked on the leading and/or trailing edge of the
9
+ * `wait` timeout. The `func` is invoked with the last arguments provided to the
10
+ * debounced function. Subsequent calls to the debounced function return the
11
+ * result of the last `func` invocation.
12
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
13
+ * invoked on the trailing edge of the timeout only if the debounced function
14
+ * is invoked more than once during the `wait` timeout.
15
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
16
+ * until the next tick, similar to `setTimeout` with a timeout of `0`.
17
+ * @param {Function} func The function to debounce
18
+ * @param {number} wait The number of milliseconds to delay
19
+ * @param {Object} [options={}] The options object
20
+ * @param {boolean} [options.leading=false] Specify invoking on the leading edge of the timeout
21
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing edge of the timeout
22
+ * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's invoked
23
+ * @returns {Function} Returns the new debounced function
24
+ */
25
+ declare function debounce<F extends (...args: any) => any>(func: F, wait: number, options?: {
26
+ leading?: boolean;
27
+ trailing?: boolean;
28
+ maxWait?: number;
29
+ }): (...args: Parameters<F>) => ReturnType<F>;
30
+ /**
31
+ * Creates a throttled function that only invokes `func` at most once per
32
+ * every `wait` milliseconds (or once per browser frame). Provide `options` to indicate
33
+ * whether `func` should be invoked on the leading and/or trailing edge of the
34
+ * `wait` timeout. The `func` is invoked with the last arguments provided to the
35
+ * throttled function. Subsequent calls to the throttled function return the
36
+ * result of the last `func` invocation.
37
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
38
+ * invoked on the trailing edge of the timeout only if the throttled function
39
+ * is invoked more than once during the `wait` timeout.
40
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
41
+ * until the next tick, similar to `setTimeout` with a timeout of `0`.
42
+ * @param {Function} func The function to throttle
43
+ * @param {number} wait The number of milliseconds to throttle invocations to
44
+ * @param {Object} [options={}] The options object
45
+ * @param {boolean} [options.leading=true] Specify invoking on the leading edge of the timeout
46
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing edge of the timeout
47
+ * @returns {Function} Returns the new throttled function
48
+ */
49
+ declare function throttle<F extends (...args: any) => any>(func: F, wait: number, options?: {
50
+ leading?: boolean;
51
+ trailing?: boolean;
52
+ }): (...args: Parameters<F>) => ReturnType<F>;
53
+ export { debounce, throttle };