Skip to content

Commit e66cca4

Browse files
committed
0.0.1
0 parents  commit e66cca4

22 files changed

+484
-0
lines changed

.github/workflows/check.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Check
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
check:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Setup Bun
19+
uses: oven-sh/setup-bun@v1
20+
with:
21+
bun-version: latest
22+
23+
- name: Install dependencies
24+
run: bun install
25+
26+
- name: Validate TypeScript types
27+
run: bun run check
28+
29+
- name: Test TypeScript types
30+
run: bun run test

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
*.lock*
3+
*.log
4+
node_modules

.vscode/settings.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"editor.codeActionsOnSave": {
3+
"source.fixAll.biome": "always",
4+
"source.organizeImports.biome": "always"
5+
},
6+
"editor.defaultFormatter": "biomejs.biome",
7+
"editor.formatOnPaste": true,
8+
"editor.formatOnSave": true,
9+
"editor.detectIndentation": false,
10+
"editor.insertSpaces": false,
11+
"editor.tabSize": 4,
12+
"files.exclude": {
13+
"node_modules": true,
14+
"bun.lock*": true
15+
},
16+
"css.lint.unknownProperties": "ignore",
17+
"html.format.extraLiners": "body",
18+
"html.format.indentInnerHtml": true,
19+
"html.format.wrapLineLength": 180,
20+
"[html]": {
21+
"editor.defaultFormatter": "vscode.html-language-features"
22+
},
23+
"[javascript]": {
24+
"editor.defaultFormatter": "biomejs.biome"
25+
},
26+
"[json]": {
27+
"editor.defaultFormatter": "biomejs.biome"
28+
},
29+
"[typescript]": {
30+
"editor.defaultFormatter": "biomejs.biome"
31+
}
32+
}

CustomElement.d.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/** Base class for a custom element. */
2+
export declare class CustomElement extends HTMLElement {
3+
/** List of attributes to observe for changes, invoking `attributeChangedCallback`. */
4+
static observedAttributes?: string[]
5+
6+
/** Indicates whether the custom element participates in form submission. */
7+
static formAssociated?: boolean
8+
9+
/** Called when one of the element's observed attributes changes. */
10+
attributeChangedCallback?(name: string, oldValue: string | null, newValue: string | null): void
11+
12+
/** Called when the element is added to a document. */
13+
connectedCallback?(): void
14+
15+
/** Called when the element is removed from a document. */
16+
disconnectedCallback?(): void
17+
18+
/** Called when the element is associated or disassociated with a form. */
19+
formAssociatedCallback?(form: HTMLFormElement | null): void
20+
21+
/** Called when the disabled state of the element changes. */
22+
formDisabledCallback?(isDisabled: boolean): void
23+
24+
/** Called when the associated form is reset. */
25+
formResetCallback?(): void
26+
27+
/** Called when the browser automatically fills out the element. */
28+
formStateRestoreCallback?(state: string | File | FormData, reason: "autocomplete" | "restore"): void
29+
}

CustomElement.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {}

CustomElementConstructor.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { CustomElement } from './CustomElement.d.ts'
2+
3+
/** Constructor interface for custom elements. */
4+
export interface CustomElementConstructor<T = CustomElement> {
5+
/** Creates a new instance of the custom element. */
6+
new (...args: any[]): HTMLElement & T
7+
8+
/** List of attributes to observe for changes, invoking `attributeChangedCallback`. */
9+
observedAttributes?: string[]
10+
11+
/** Indicates whether the custom element participates in form submission. */
12+
formAssociated?: boolean
13+
}

CustomElementConstructor.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {}

CustomElementRegistry.d.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { CustomElementConstructor } from "./CustomElementConstructor.d.ts"
2+
3+
/** Provides methods for registering custom elements and querying registered elements. [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomElementRegistry) */
4+
export declare class CustomElementRegistry {
5+
/** Adds a definition for a custom element to the custom element registry. [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomElementRegistry/define) */
6+
define(name: string, constructor: CustomElementConstructor, options?: ElementDefinitionOptions): void
7+
8+
/** Returns the constructor for a previously-defined custom element. [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomElementRegistry/get) */
9+
get(name: string): CustomElementConstructor | undefined
10+
11+
/** Returns the name for a previously-defined custom element. [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomElementRegistry/getName) */
12+
getName(constructor: CustomElementConstructor): string | null
13+
14+
/** Upgrades all shadow-containing custom elements in the given root. [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomElementRegistry/upgrade) */
15+
upgrade(root: Node): void
16+
17+
/** Returns a Promise that resolves when the named element is defined. [MDN Reference](https://developer.mozilla.org/docs/Web/API/CustomElementRegistry/whenDefined) */
18+
whenDefined(name: string): Promise<CustomElementConstructor>
19+
}

CustomElementRegistry.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {}

README.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Typed Custom Elements
2+
3+
[![NPM Version][npm-img]][npm-url]
4+
[![Build Status][cli-img]][cli-url]
5+
6+
**Typed Custom Elements** is a collection of TypeScript types to help you author type-safe Web Components, with proper type checking for custom elements, their constructors, and the custom elements registry.
7+
8+
## Features
9+
10+
- ✅ Typed custom element class definitions
11+
- ✅ Typed static properties and lifecycle methods
12+
- ✅ Typed custom element constructors
13+
- ✅ Type-safe interaction with the Custom Elements Registry
14+
- ✅ Zero dependencies
15+
- ✅ ESM compatible
16+
17+
👉 [Try it now in StackBlitz](https://stackblitz.com/github/jsxtools/typed-custom-elements/tree/main/demo)
18+
19+
## Installation
20+
21+
```shell
22+
npm install typed-custom-elements
23+
```
24+
25+
## Usage
26+
27+
### Basic Custom Elements
28+
29+
```ts
30+
import type { CustomElement } from "typed-custom-elements"
31+
32+
class MyElement extends HTMLElement implements CustomElement {
33+
// type safety and code completion for static propertes, lifecycle methods, etc.
34+
static formAssociated = true
35+
static observedAttributes = ["name"]
36+
37+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
38+
// type-safe callback handling
39+
}
40+
}
41+
```
42+
43+
### Custom Element Constructors
44+
45+
```ts
46+
import type { CustomElementConstructor } from "typed-custom-elements"
47+
48+
const MyElementConstructor: CustomElementConstructor = class extends HTMLElement {
49+
// type safety and code completion for static propertes, lifecycle methods, etc.
50+
}
51+
```
52+
53+
### Custom Elements Registry
54+
55+
```ts
56+
import type { CustomElementRegistry } from "typed-custom-elements"
57+
58+
declare const customElements: CustomElementRegistry
59+
60+
// type-safe custom element registration
61+
customElements.define('my-element', class extends HTMLElement {
62+
// type safety, code completion, you get the point
63+
})
64+
```
65+
66+
## Why Use Typed Custom Elements?
67+
68+
Working with Web Components in TypeScript often means relying on implicit or loosely typed structures.
69+
This package brings clarity and confidence to your component authoring by enforcing:
70+
71+
- Proper typing for lifecycle callbacks.
72+
- Static property inference (`formAssociated`, `observedAttributes`).
73+
- Safer registration and instantiation via constructors and registries.
74+
75+
## License
76+
77+
This project is licensed under the [MIT No Attribution License](https://opensource.org/license/mit-0).
78+
79+
[npm-img]: https://img.shields.io/npm/v/typed-custom-elements
80+
[npm-url]: https://www.npmjs.com/package/typed-custom-elements
81+
[cli-img]: https://github.com/jsxtools/typed-custom-elements/actions/workflows/check.yml/badge.svg
82+
[cli-url]: https://github.com/jsxtools/typed-custom-elements/actions/workflows/check.yml

0 commit comments

Comments
 (0)