drab 6.1.3 → 6.2.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.
@@ -54,13 +54,17 @@ export declare class Base extends HTMLElement {
54
54
  */
55
55
  swapContent(revert?: number | false): void;
56
56
  /**
57
- * Wrapper around `document.body.addEventListener` that ensures when the
58
- * element is removed from the DOM, these event listeners are cleaned up.
59
- * @param type
60
- * @param listener
61
- * @param options
57
+ * Wrapper around `addEventListener` that ensures when the element is
58
+ * removed from the DOM, these event listeners are cleaned up.
59
+ *
60
+ * @param type Event listener type - ex: `"keydown"`
61
+ * @param listener Listener to add to the target.
62
+ * @param target Event target to add the listener to - defaults to `document.body`.
63
+ * @param options Other options sans `signal`.
62
64
  */
63
- safeListener<K extends keyof DocumentEventMap, T extends HTMLElement | Window | Document = HTMLElement>(type: K, listener: (this: T, ev: DocumentEventMap[K]) => any, element?: T, options?: AddEventListenerOptions): void;
65
+ safeListener<T extends keyof HTMLElementEventMap>(type: T, listener: (this: HTMLElement, event: HTMLElementEventMap[T]) => any, element?: HTMLElement, options?: AddEventListenerOptions): void;
66
+ safeListener<T extends keyof DocumentEventMap>(type: T, listener: (this: Document, event: DocumentEventMap[T]) => any, document: Document, options?: AddEventListenerOptions): void;
67
+ safeListener<T extends keyof WindowEventMap>(type: T, listener: (this: Window, event: WindowEventMap[T]) => any, window: Window, options?: AddEventListenerOptions): void;
64
68
  /**
65
69
  * @param listener Listener to attach to all of the `trigger` elements.
66
70
  */
@@ -73,7 +73,7 @@ export class Base extends HTMLElement {
73
73
  const swap = this.querySelector(this.getAttribute("swap") ?? "[data-swap]");
74
74
  if (swap) {
75
75
  /** A copy of the content currently in `this.getContent()`. */
76
- const currentContent = Array.from(this.getContent().childNodes);
76
+ const currentContent = this.getContent().childNodes;
77
77
  /**
78
78
  * The contents of the swap element, set based on whether the
79
79
  * swap is a `template` or not.
@@ -99,17 +99,9 @@ export class Base extends HTMLElement {
99
99
  }
100
100
  }
101
101
  }
102
- /**
103
- * Wrapper around `document.body.addEventListener` that ensures when the
104
- * element is removed from the DOM, these event listeners are cleaned up.
105
- * @param type
106
- * @param listener
107
- * @param options
108
- */
109
- safeListener(type, listener, element = document.body, options = {}) {
102
+ safeListener(type, listener, target = document.body, options = {}) {
110
103
  options.signal = this.#listenerController.signal;
111
- //@ts-ignore - inferred listener type not working...?
112
- element.addEventListener(type, listener, options);
104
+ target.addEventListener(type, listener, options);
113
105
  }
114
106
  /**
115
107
  * @param listener Listener to attach to all of the `trigger` elements.
@@ -42,15 +42,13 @@ export type ContentElement = {
42
42
  * - Automatically increments/decrements ordered lists.
43
43
  * - Adds the starting character to the next line for `block` content.
44
44
  * - On double click, highlight is corrected to only highlight the current word without space around it.
45
- * - `tab` key will indent and not change focus if the selection is within a code block (three backticks).
45
+ * - `tab` key will indent or dedent (+shift) instead of focus change if the selection is within a code block (three backticks).
46
46
  * - When text is highlighted and a `wrap` character `keyPair` is typed, the highlighted text will be wrapped with the character instead of removing it. For example, if a word is highlighted and the `"` character is typed, the work will be surrounded by `"`s.
47
47
  */
48
48
  export declare class Editor extends Base {
49
49
  #private;
50
50
  /** Characters that will be automatically closed when typed. */
51
- keyPairs: {
52
- [key: string]: string;
53
- };
51
+ keyPairs: Record<string, string>;
54
52
  constructor();
55
53
  /** The `content`, expects an `HTMLTextAreaElement`. */
56
54
  get textArea(): HTMLTextAreaElement;
@@ -25,7 +25,7 @@ import { Base } from "../base/index.js";
25
25
  * - Automatically increments/decrements ordered lists.
26
26
  * - Adds the starting character to the next line for `block` content.
27
27
  * - On double click, highlight is corrected to only highlight the current word without space around it.
28
- * - `tab` key will indent and not change focus if the selection is within a code block (three backticks).
28
+ * - `tab` key will indent or dedent (+shift) instead of focus change if the selection is within a code block (three backticks).
29
29
  * - When text is highlighted and a `wrap` character `keyPair` is typed, the highlighted text will be wrapped with the character instead of removing it. For example, if a word is highlighted and the `"` character is typed, the work will be surrounded by `"`s.
30
30
  */
31
31
  export class Editor extends Base {
@@ -219,7 +219,7 @@ export class Editor extends Base {
219
219
  else {
220
220
  newNum = num + 1;
221
221
  }
222
- lines[lineNumber] = String(newNum) + line.slice(String(num).length);
222
+ lines[lineNumber] = newNum + line.slice(String(num).length);
223
223
  }
224
224
  else {
225
225
  break;
@@ -265,16 +265,26 @@ export class Editor extends Base {
265
265
  for (const [i, block] of blocks.entries()) {
266
266
  totalChars += block.length + 3;
267
267
  if (totalChars > this.#selStart) {
268
- // found
269
268
  if (i % 2) {
270
- // if caret is inside of a codeblock, indent
269
+ // caret is inside of a codeblock
271
270
  e.preventDefault();
272
- this.#addContent({ type: "inline", value: "\t" });
271
+ if (e.shiftKey) {
272
+ const { line, columnNumber } = this.#lineMeta();
273
+ if (line.startsWith("\t")) {
274
+ // dedent
275
+ const start = this.#selStart;
276
+ this.#removeStr(start - columnNumber);
277
+ this.#setSelection(start - 1);
278
+ }
279
+ }
280
+ else {
281
+ // indent
282
+ this.#addContent({ type: "inline", value: "\t" });
283
+ }
273
284
  }
274
285
  break;
275
286
  }
276
287
  }
277
- // TODO add shift tab backwards
278
288
  }
279
289
  else if (e.key === "Enter" && notHighlighted) {
280
290
  // autocomplete start of next line if block or number
@@ -330,7 +340,6 @@ export class Editor extends Base {
330
340
  else if (e.key in this.keyPairs) {
331
341
  e.preventDefault();
332
342
  this.#addContent({ type: "wrap", value: e.key });
333
- this.#openChars.push(e.key);
334
343
  }
335
344
  });
336
345
  // trims the selection if there is an extra space around it
@@ -346,8 +355,6 @@ export class Editor extends Base {
346
355
  });
347
356
  // reset #openChars on click since the cursor has changed position
348
357
  this.textArea.addEventListener("click", () => (this.#openChars = []));
349
- for (const trigger of this.getTrigger()) {
350
- trigger.addEventListener(this.event, () => this.#addContent(trigger.dataset));
351
- }
358
+ this.triggerListener((e) => this.#addContent(e.target.dataset));
352
359
  }
353
360
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "drab",
3
3
  "description": "Interactivity for You",
4
- "version": "6.1.3",
4
+ "version": "6.2.0",
5
5
  "homepage": "https://drab.robino.dev",
6
6
  "license": "MIT",
7
7
  "author": {