Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,18 @@ export class Component<T extends HTMLElement = HTMLElement> extends ElementCompo
return [...this.node.querySelectorAll<T>(selectors)].map(e => new Component<T>(e));
}

/**
* Traverse the component and its parents (heading toward the document root) until it finds a component that matches
* the specified {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors CSS selector}.
* @param selectors
* @typeParam T Component element type
*/
public closest<T extends HTMLElement = HTMLElement>(selectors: string): Component<T> | null {
const element = this.node.closest<T>(selectors);
if (element == null) return null;
return new Component<T>(element);
}

/**
* Set style property
* @param name Property name
Expand Down Expand Up @@ -113,6 +125,10 @@ export class Component<T extends HTMLElement = HTMLElement> extends ElementCompo
return this;
}

public override clone(deep = true) {
return new Component<T>(this.node.cloneNode(deep) as T);
}

public override on<K extends keyof HTMLElementEventMap>(type: K, listener: (ev: HTMLElementEventMap[K], component: this) => any): typeof this;
public override on<K extends keyof HTMLElementEventMap>(type: K, listener: (ev: HTMLElementEventMap[K], component: this) => any, options: AddEventListenerOptions): typeof this;
public override on<K extends keyof HTMLElementEventMap>(type: K, listener: (ev: HTMLElementEventMap[K], component: this) => any, useCapture: boolean): typeof this;
Expand Down
6 changes: 6 additions & 0 deletions src/DocumentComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ export class DocumentComponent extends NodeComponent<DocumentFragment> {
component.slot(idPrefix + index, doc.node);
return doc;
}

public override clone(deep = true) {
const doc = new DocumentComponent();
doc.node.append(this.node.cloneNode(deep));
return doc;
}
}
36 changes: 36 additions & 0 deletions src/ElementComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,25 @@ export abstract class ElementComponent<T extends Element> extends NodeComponent<
return this;
}

/**
* Insert components in the children list of this `ElementComponent`’s parent, just before this `ElementComponent`.
* @param components Components to insert
*/
public before(...components: NodeComponent<any>[]) {
this.node.before(...components.map(c => c.node));
return this;
}

/**
* Insert components in the children list of this `ElementComponent`’s parent, just after this `ElementComponent`.
* @param components Components to insert
*/
public after(...components: NodeComponent<any>[]) {
this.node.after(...components.map(c => c.node));
return this;
}


/**
* Add classes
*/
Expand Down Expand Up @@ -162,6 +181,23 @@ export abstract class ElementComponent<T extends Element> extends NodeComponent<
return this.node[name];
}

/**
* Check whether the component is visible.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility Element: checkVisibility() - MDN}
*/
public isVisible() {
return this.node.checkVisibility();
}

/**
* Get a {@link !DOMRect} object providing information about the size of a component and its position relative to
* the {@link https://developer.mozilla.org/en-US/docs/Glossary/Viewport viewport}.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect Element: getBoundingClientRect() - MDN}
*/
public boundingClientRect() {
return this.node.getBoundingClientRect();
}

/**
* Remove the element
*/
Expand Down
8 changes: 8 additions & 0 deletions src/NodeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ export abstract class NodeComponent<T extends Node> {
return this;
}

/**
* Clone this component. Event listeners are not cloned.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode Node: cloneNode() - MDN}
* @param [deep] Whether to clone the whole subtree.
* @returns A duplicate of this component.
*/
public abstract clone(deep?: boolean): NodeComponent<T>;

/**
* Add event listener
* @param type A case-sensitive string representing the event type to listen for.
Expand Down
4 changes: 4 additions & 0 deletions src/SvgComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ export class SvgComponent extends ElementComponent<SVGSVGElement> {
public static from(svg: string) {
return new SvgComponent(document.createRange().createContextualFragment(svg).children[0] as SVGSVGElement);
}

public override clone(deep = true) {
return new SvgComponent(this.node.cloneNode(deep) as SVGSVGElement);
}
}
7 changes: 7 additions & 0 deletions src/TextComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ export class TextComponent extends NodeComponent<Text> {
throw new DOMException(`NodeComponent.append: Cannot add children to a ${this.constructor.name}`);
}

/**
* Clone this text component.
*/
public override clone() {
return new TextComponent(this.node.cloneNode() as Text);
}

/**
* Get the text content
*/
Expand Down