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
23 changes: 21 additions & 2 deletions packages/nanotags/src/setup-context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,25 @@ describe("getElement / getElements", () => {
);
expect(found).toHaveLength(2);
});

it("accepts custom element type via generic", () => {
type CustomEl = HTMLElement & { custom: true };
const tag = uniqueTag("ge");
define(tag, (ctx) => {
const single = ctx.getElement<CustomEl>(".item");
expectTypeOf(single).toEqualTypeOf<CustomEl>();

const list = ctx.getElements<CustomEl>(".item");
expectTypeOf(list).toEqualTypeOf<CustomEl[]>();

const container = ctx.getElement(".container");
const scoped = ctx.getElement<CustomEl>(container, ".item");
expectTypeOf(scoped).toEqualTypeOf<CustomEl>();

const scopedList = ctx.getElements<CustomEl>(container, ".item");
expectTypeOf(scopedList).toEqualTypeOf<CustomEl[]>();
});
});
});

describe("effect", () => {
Expand Down Expand Up @@ -552,7 +571,7 @@ describe("bind", () => {
const parentTag = uniqueTag("bind-parent");
const $val = atom("from-parent");
define(parentTag, (ctx) => {
const child = ctx.getElement(childTag);
const child = ctx.getElement<HTMLElement>(childTag);
ctx.bind($val, child, { prop: "value", event: "change" });
});
const el = mount(`<${parentTag}><${childTag}></${childTag}></${parentTag}>`);
Expand Down Expand Up @@ -595,7 +614,7 @@ describe("bind", () => {
const tag = uniqueTag("bind");
const $theme = atom("dark");
define(tag, (ctx) => {
const ctrl = ctx.getElement(controlTag);
const ctrl = ctx.getElement<HTMLElement>(controlTag);
ctx.bind($theme, ctrl, { prop: "theme", event: "change" });
});
const el = mount(`<${tag}><${controlTag}></${controlTag}></${tag}>`);
Expand Down
47 changes: 27 additions & 20 deletions packages/nanotags/src/setup-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,34 +147,41 @@ export class Context<
}

/** Queries a single required element by CSS selector. Throws if not found. */
getElement<E extends keyof HTMLElementTagNameMap>(selector: E | string): HTMLElementTagNameMap[E];
getElement<E extends keyof HTMLElementTagNameMap>(
getElement<const Tag extends keyof HTMLElementTagNameMap>(
selector: Tag,
): HTMLElementTagNameMap[Tag];
getElement<const Tag extends keyof HTMLElementTagNameMap>(
root: DocumentFragment | Element,
selector: E | string,
): HTMLElementTagNameMap[E];
getElement<E extends keyof HTMLElementTagNameMap>(
selectorOrRoot: E | string | DocumentFragment | Element,
maybeSelector?: E | string,
): HTMLElementTagNameMap[E] {
return this.getElements<E>(selectorOrRoot as any, maybeSelector as any)[0]!;
selector: Tag,
): HTMLElementTagNameMap[Tag];
getElement<E extends Element>(selector: string): E;
getElement<E extends Element>(root: DocumentFragment | Element, selector: string): E;
getElement(selector: string): Element;
getElement(root: DocumentFragment | Element, selector: string): Element;
getElement(selectorOrRoot: string | DocumentFragment | Element, maybeSelector?: string): Element {
return this.getElements(selectorOrRoot as any, maybeSelector as any)[0]!;
}

/** Queries all matching elements by CSS selector. Throws if none found. */
getElements<E extends keyof HTMLElementTagNameMap>(
selector: E | string,
): HTMLElementTagNameMap[E][];
getElements<E extends keyof HTMLElementTagNameMap>(
getElements<const Tag extends keyof HTMLElementTagNameMap>(
selector: Tag,
): HTMLElementTagNameMap[Tag][];
getElements<const Tag extends keyof HTMLElementTagNameMap>(
root: DocumentFragment | Element,
selector: E | string,
): HTMLElementTagNameMap[E][];
getElements<E extends keyof HTMLElementTagNameMap>(
selectorOrRoot: E | string | DocumentFragment | Element,
maybeSelector?: E | string,
): HTMLElementTagNameMap[E][] {
selector: Tag,
): HTMLElementTagNameMap[Tag][];
getElements<E extends Element>(selector: string): E[];
getElements<E extends Element>(root: DocumentFragment | Element, selector: string): E[];
getElements(selector: string): Element[];
getElements(root: DocumentFragment | Element, selector: string): Element[];
getElements(
selectorOrRoot: string | DocumentFragment | Element,
maybeSelector?: string,
): Element[] {
const hasRoot = maybeSelector !== undefined;
const root = hasRoot ? (selectorOrRoot as DocumentFragment | Element) : this.host;
const selector = (hasRoot ? maybeSelector : selectorOrRoot) as string;
const elements = Array.from(root.querySelectorAll<HTMLElementTagNameMap[E]>(selector));
const elements = Array.from(root.querySelectorAll(selector));
invariant(elements.length > 0, `${this.host.localName}: missing ${selector}`);
return elements;
}
Expand Down
Loading