@vielzeug/craftit 1.0.1 → 2.0.1
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.
- package/README.md +112 -401
- package/dist/core/component.cjs +2 -0
- package/dist/core/component.cjs.map +1 -0
- package/dist/core/component.d.ts +172 -0
- package/dist/core/component.d.ts.map +1 -0
- package/dist/core/component.js +2 -0
- package/dist/core/component.js.map +1 -0
- package/dist/core/host.cjs +2 -0
- package/dist/core/host.cjs.map +1 -0
- package/dist/core/host.d.ts +77 -0
- package/dist/core/host.d.ts.map +1 -0
- package/dist/core/host.js +2 -0
- package/dist/core/host.js.map +1 -0
- package/dist/core/internal.cjs +2 -0
- package/dist/core/internal.cjs.map +1 -0
- package/dist/core/internal.d.ts +107 -0
- package/dist/core/internal.d.ts.map +1 -0
- package/dist/core/internal.js +2 -0
- package/dist/core/internal.js.map +1 -0
- package/dist/core/runtime-bindings.cjs +2 -0
- package/dist/core/runtime-bindings.cjs.map +1 -0
- package/dist/core/runtime-bindings.d.ts +6 -0
- package/dist/core/runtime-bindings.d.ts.map +1 -0
- package/dist/core/runtime-bindings.js +2 -0
- package/dist/core/runtime-bindings.js.map +1 -0
- package/dist/core/runtime-lifecycle.cjs +2 -0
- package/dist/core/runtime-lifecycle.cjs.map +1 -0
- package/dist/core/runtime-lifecycle.d.ts +116 -0
- package/dist/core/runtime-lifecycle.d.ts.map +1 -0
- package/dist/core/runtime-lifecycle.js +2 -0
- package/dist/core/runtime-lifecycle.js.map +1 -0
- package/dist/core/runtime.cjs +1 -0
- package/dist/core/runtime.d.ts +3 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +1 -0
- package/dist/core/template-bindings.cjs +2 -0
- package/dist/core/template-bindings.cjs.map +1 -0
- package/dist/core/template-bindings.d.ts +59 -0
- package/dist/core/template-bindings.d.ts.map +1 -0
- package/dist/core/template-bindings.js +2 -0
- package/dist/core/template-bindings.js.map +1 -0
- package/dist/core/template-compiler.cjs +2 -0
- package/dist/core/template-compiler.cjs.map +1 -0
- package/dist/core/template-compiler.d.ts +25 -0
- package/dist/core/template-compiler.d.ts.map +1 -0
- package/dist/core/template-compiler.js +2 -0
- package/dist/core/template-compiler.js.map +1 -0
- package/dist/core/template-dom.cjs +2 -0
- package/dist/core/template-dom.cjs.map +1 -0
- package/dist/core/template-dom.d.ts +13 -0
- package/dist/core/template-dom.d.ts.map +1 -0
- package/dist/core/template-dom.js +2 -0
- package/dist/core/template-dom.js.map +1 -0
- package/dist/core/template-html.cjs +2 -0
- package/dist/core/template-html.cjs.map +1 -0
- package/dist/core/template-html.d.ts +26 -0
- package/dist/core/template-html.d.ts.map +1 -0
- package/dist/core/template-html.js +2 -0
- package/dist/core/template-html.js.map +1 -0
- package/dist/core/template.cjs +2 -0
- package/dist/core/template.cjs.map +1 -0
- package/dist/core/template.d.ts +11 -0
- package/dist/core/template.d.ts.map +1 -0
- package/dist/core/template.js +2 -0
- package/dist/core/template.js.map +1 -0
- package/dist/core/utilities.cjs +2 -0
- package/dist/core/utilities.cjs.map +1 -0
- package/dist/core/utilities.d.ts +68 -0
- package/dist/core/utilities.d.ts.map +1 -0
- package/dist/core/utilities.js +2 -0
- package/dist/core/utilities.js.map +1 -0
- package/dist/craftit.cjs +2 -18
- package/dist/craftit.cjs.map +1 -1
- package/dist/craftit.js +2 -580
- package/dist/craftit.js.map +1 -1
- package/dist/directives/attr.cjs +2 -0
- package/dist/directives/attr.cjs.map +1 -0
- package/dist/directives/attr.d.ts +14 -0
- package/dist/directives/attr.d.ts.map +1 -0
- package/dist/directives/attr.js +2 -0
- package/dist/directives/attr.js.map +1 -0
- package/dist/directives/bind.cjs +2 -0
- package/dist/directives/bind.cjs.map +1 -0
- package/dist/directives/bind.d.ts +30 -0
- package/dist/directives/bind.d.ts.map +1 -0
- package/dist/directives/bind.js +2 -0
- package/dist/directives/bind.js.map +1 -0
- package/dist/directives/choose.cjs +2 -0
- package/dist/directives/choose.cjs.map +1 -0
- package/dist/directives/choose.d.ts +34 -0
- package/dist/directives/choose.d.ts.map +1 -0
- package/dist/directives/choose.js +2 -0
- package/dist/directives/choose.js.map +1 -0
- package/dist/directives/classes.cjs +2 -0
- package/dist/directives/classes.cjs.map +1 -0
- package/dist/directives/classes.d.ts +20 -0
- package/dist/directives/classes.d.ts.map +1 -0
- package/dist/directives/classes.js +2 -0
- package/dist/directives/classes.js.map +1 -0
- package/dist/directives/each.cjs +2 -0
- package/dist/directives/each.cjs.map +1 -0
- package/dist/directives/each.d.ts +68 -0
- package/dist/directives/each.d.ts.map +1 -0
- package/dist/directives/each.js +2 -0
- package/dist/directives/each.js.map +1 -0
- package/dist/directives/index.cjs +1 -0
- package/dist/directives/index.d.ts +14 -0
- package/dist/directives/index.d.ts.map +1 -0
- package/dist/directives/index.js +1 -0
- package/dist/directives/match.cjs +2 -0
- package/dist/directives/match.cjs.map +1 -0
- package/dist/directives/match.d.ts +31 -0
- package/dist/directives/match.d.ts.map +1 -0
- package/dist/directives/match.js +2 -0
- package/dist/directives/match.js.map +1 -0
- package/dist/directives/memo.cjs +2 -0
- package/dist/directives/memo.cjs.map +1 -0
- package/dist/directives/memo.d.ts +23 -0
- package/dist/directives/memo.d.ts.map +1 -0
- package/dist/directives/memo.js +2 -0
- package/dist/directives/memo.js.map +1 -0
- package/dist/directives/on.cjs +2 -0
- package/dist/directives/on.cjs.map +1 -0
- package/dist/directives/on.d.ts +25 -0
- package/dist/directives/on.d.ts.map +1 -0
- package/dist/directives/on.js +2 -0
- package/dist/directives/on.js.map +1 -0
- package/dist/directives/raw.cjs +2 -0
- package/dist/directives/raw.cjs.map +1 -0
- package/dist/directives/raw.d.ts +25 -0
- package/dist/directives/raw.d.ts.map +1 -0
- package/dist/directives/raw.js +2 -0
- package/dist/directives/raw.js.map +1 -0
- package/dist/directives/spread.cjs +2 -0
- package/dist/directives/spread.cjs.map +1 -0
- package/dist/directives/spread.d.ts +14 -0
- package/dist/directives/spread.d.ts.map +1 -0
- package/dist/directives/spread.js +2 -0
- package/dist/directives/spread.js.map +1 -0
- package/dist/directives/style.cjs +2 -0
- package/dist/directives/style.cjs.map +1 -0
- package/dist/directives/style.d.ts +22 -0
- package/dist/directives/style.d.ts.map +1 -0
- package/dist/directives/style.js +2 -0
- package/dist/directives/style.js.map +1 -0
- package/dist/directives/until.cjs +2 -0
- package/dist/directives/until.cjs.map +1 -0
- package/dist/directives/until.d.ts +26 -0
- package/dist/directives/until.d.ts.map +1 -0
- package/dist/directives/until.js +2 -0
- package/dist/directives/until.js.map +1 -0
- package/dist/directives/when.cjs +2 -0
- package/dist/directives/when.cjs.map +1 -0
- package/dist/directives/when.d.ts +17 -0
- package/dist/directives/when.d.ts.map +1 -0
- package/dist/directives/when.js +2 -0
- package/dist/directives/when.js.map +1 -0
- package/dist/index.cjs +1 -2
- package/dist/index.d.ts +10 -265
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -13
- package/dist/labs/a11y.cjs +2 -0
- package/dist/labs/a11y.cjs.map +1 -0
- package/dist/labs/a11y.d.ts +61 -0
- package/dist/labs/a11y.d.ts.map +1 -0
- package/dist/labs/a11y.js +2 -0
- package/dist/labs/a11y.js.map +1 -0
- package/dist/labs/index.d.ts +8 -0
- package/dist/labs/index.d.ts.map +1 -0
- package/dist/labs/list.cjs +2 -0
- package/dist/labs/list.cjs.map +1 -0
- package/dist/labs/list.d.ts +26 -0
- package/dist/labs/list.d.ts.map +1 -0
- package/dist/labs/list.js +2 -0
- package/dist/labs/list.js.map +1 -0
- package/dist/labs/observers.cjs +2 -0
- package/dist/labs/observers.cjs.map +1 -0
- package/dist/labs/observers.d.ts +42 -0
- package/dist/labs/observers.d.ts.map +1 -0
- package/dist/labs/observers.js +2 -0
- package/dist/labs/observers.js.map +1 -0
- package/dist/labs/overlay.cjs +2 -0
- package/dist/labs/overlay.cjs.map +1 -0
- package/dist/labs/overlay.d.ts +35 -0
- package/dist/labs/overlay.d.ts.map +1 -0
- package/dist/labs/overlay.js +2 -0
- package/dist/labs/overlay.js.map +1 -0
- package/dist/labs/selectable.cjs +2 -0
- package/dist/labs/selectable.cjs.map +1 -0
- package/dist/labs/selectable.d.ts +70 -0
- package/dist/labs/selectable.d.ts.map +1 -0
- package/dist/labs/selectable.js +2 -0
- package/dist/labs/selectable.js.map +1 -0
- package/dist/labs/selection.cjs +2 -0
- package/dist/labs/selection.cjs.map +1 -0
- package/dist/labs/selection.d.ts +68 -0
- package/dist/labs/selection.d.ts.map +1 -0
- package/dist/labs/selection.js +2 -0
- package/dist/labs/selection.js.map +1 -0
- package/dist/labs.cjs +1 -0
- package/dist/labs.js +1 -0
- package/dist/test/index.d.ts +2 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/test.cjs +2 -0
- package/dist/test/test.cjs.map +1 -0
- package/dist/test/test.d.ts +198 -0
- package/dist/test/test.d.ts.map +1 -0
- package/dist/test/test.js +2 -0
- package/dist/test/test.js.map +1 -0
- package/dist/test.cjs +1 -0
- package/dist/test.js +1 -0
- package/package.json +37 -9
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,449 +1,160 @@
|
|
|
1
1
|
# @vielzeug/craftit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Functional web components with signals, typed props, and template bindings
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@vielzeug/craftit) [](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
-
**Craftit**
|
|
7
|
+
**Craftit** provides a compact API for authoring custom elements with fine-grained reactivity. It builds on `@vielzeug/stateit` (re-exported from the main entry) and adds component lifecycle, templating, typed props, context, slots/emits, form-associated helpers, and observer utilities.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Installation
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
// Vanilla Custom Elements - verbose and manual
|
|
15
|
-
class MyCounter extends HTMLElement {
|
|
16
|
-
#count = 0;
|
|
17
|
-
#shadow: ShadowRoot;
|
|
18
|
-
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
this.#shadow = this.attachShadow({ mode: 'open' });
|
|
22
|
-
this.render();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
connectedCallback() {
|
|
26
|
-
this.#shadow.querySelector('button')?.addEventListener('click', () => {
|
|
27
|
-
this.#count++;
|
|
28
|
-
this.render(); // Manual re-render
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
render() {
|
|
33
|
-
this.#shadow.innerHTML = `
|
|
34
|
-
<div>Count: ${this.#count}</div>
|
|
35
|
-
<button>Increment</button>
|
|
36
|
-
`; // Loses event listeners!
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
customElements.define('my-counter', MyCounter);
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### The Solution
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
// Craftit - reactive and automatic
|
|
47
|
-
import { defineElement, html } from '@vielzeug/craftit';
|
|
48
|
-
|
|
49
|
-
defineElement('my-counter', {
|
|
50
|
-
state: { count: 0 },
|
|
51
|
-
|
|
52
|
-
template: (el) => html`
|
|
53
|
-
<div>Count: ${el.state.count}</div>
|
|
54
|
-
<button>Increment</button>
|
|
55
|
-
`,
|
|
56
|
-
|
|
57
|
-
onConnected(el) {
|
|
58
|
-
el.on('button', 'click', () => {
|
|
59
|
-
el.state.count++; // Automatic re-render!
|
|
60
|
-
});
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## ✨ Features
|
|
66
|
-
|
|
67
|
-
- **🔥 Reactive State** - Automatic re-renders on state changes with Proxy-based reactivity
|
|
68
|
-
- **⚡ Efficient Updates** - Smart DOM reconciliation, only updates what changed
|
|
69
|
-
- **🎯 Event Delegation** - Built-in support for dynamic element event handling
|
|
70
|
-
- **📝 Form Support** - Full ElementInternals integration for form participation
|
|
71
|
-
- **🎨 Shadow DOM** - Encapsulated styles with CSSStyleSheet support
|
|
72
|
-
- **🎭 CSS Variables** - Built-in theming support with `css.var()` and `css.theme()`
|
|
73
|
-
- **🔍 Type-Safe** - Complete TypeScript support with full type inference
|
|
74
|
-
- **📦 Tiny Bundle** - Only **~5 KB gzipped** with zero dependencies
|
|
75
|
-
- **🧪 Testable** - Built-in testing utilities (`attach`, `destroy`, `flush`)
|
|
76
|
-
- **🪝 Lifecycle Hooks** - Full control with `onConnected`, `onDisconnected`, `onUpdated`
|
|
77
|
-
- **🌐 Framework Agnostic** - Use with React, Vue, Svelte, or vanilla JS
|
|
78
|
-
|
|
79
|
-
## 📦 Installation
|
|
80
|
-
|
|
81
|
-
::: code-group
|
|
82
|
-
|
|
83
|
-
```sh [npm]
|
|
84
|
-
npm install @vielzeug/craftit
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
```sh [yarn]
|
|
88
|
-
yarn add @vielzeug/craftit
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
```sh [pnpm]
|
|
11
|
+
```sh
|
|
92
12
|
pnpm add @vielzeug/craftit
|
|
13
|
+
# npm install @vielzeug/craftit
|
|
14
|
+
# yarn add @vielzeug/craftit
|
|
93
15
|
```
|
|
94
16
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
## 🚀 Quick Start
|
|
98
|
-
|
|
99
|
-
### Basic Component
|
|
100
|
-
|
|
101
|
-
```ts
|
|
102
|
-
import { defineElement, html, css } from '@vielzeug/craftit';
|
|
103
|
-
|
|
104
|
-
defineElement('hello-world', {
|
|
105
|
-
template: html`
|
|
106
|
-
<div class="greeting">
|
|
107
|
-
<h1>Hello, World!</h1>
|
|
108
|
-
<p>Welcome to Craftit!</p>
|
|
109
|
-
</div>
|
|
110
|
-
`,
|
|
111
|
-
|
|
112
|
-
styles: [
|
|
113
|
-
css`
|
|
114
|
-
.greeting {
|
|
115
|
-
padding: 1rem;
|
|
116
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
117
|
-
color: white;
|
|
118
|
-
border-radius: 8px;
|
|
119
|
-
}
|
|
120
|
-
`,
|
|
121
|
-
],
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// Use in HTML
|
|
125
|
-
// <hello-world></hello-world>
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### With State
|
|
17
|
+
## Quick Start
|
|
129
18
|
|
|
130
19
|
```ts
|
|
131
|
-
|
|
132
|
-
state: {
|
|
133
|
-
name: 'Alice',
|
|
134
|
-
age: 30,
|
|
135
|
-
email: 'alice@example.com',
|
|
136
|
-
},
|
|
137
|
-
|
|
138
|
-
template: (el) => html`
|
|
139
|
-
<div class="profile">
|
|
140
|
-
<h2>${el.state.name}</h2>
|
|
141
|
-
<p>Age: ${el.state.age}</p>
|
|
142
|
-
<p>Email: ${el.state.email}</p>
|
|
143
|
-
</div>
|
|
144
|
-
`,
|
|
145
|
-
});
|
|
146
|
-
```
|
|
20
|
+
import { defineComponent, signal, computed, html } from '@vielzeug/craftit';
|
|
147
21
|
|
|
148
|
-
|
|
22
|
+
defineComponent({
|
|
23
|
+
setup() {
|
|
24
|
+
const count = signal(0);
|
|
25
|
+
const doubled = computed(() => count.value * 2);
|
|
149
26
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
template: (el) => html`
|
|
155
|
-
<div>
|
|
156
|
-
<p>Count: ${el.state.count}</p>
|
|
157
|
-
<button class="increment">Increment</button>
|
|
158
|
-
<button class="decrement">Decrement</button>
|
|
159
|
-
<button class="reset">Reset</button>
|
|
160
|
-
</div>
|
|
161
|
-
`,
|
|
162
|
-
|
|
163
|
-
onConnected(el) {
|
|
164
|
-
el.on('.increment', 'click', () => {
|
|
165
|
-
el.state.count++;
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
el.on('.decrement', 'click', () => {
|
|
169
|
-
el.state.count--;
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
el.on('.reset', 'click', () => {
|
|
173
|
-
el.state.count = 0;
|
|
174
|
-
});
|
|
27
|
+
return html`
|
|
28
|
+
<button @click=${() => count.value++}>Count: ${count}</button>
|
|
29
|
+
<p>Doubled: ${doubled}</p>
|
|
30
|
+
`;
|
|
175
31
|
},
|
|
32
|
+
tag: 'my-counter',
|
|
176
33
|
});
|
|
177
34
|
```
|
|
178
35
|
|
|
179
|
-
|
|
36
|
+
## Features
|
|
180
37
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
38
|
+
- ✅ **Component authoring** — `defineComponent({ tag, props, setup, ... })`
|
|
39
|
+
- ✅ **Signals included** — all `@vielzeug/stateit` exports are re-exported
|
|
40
|
+
- ✅ **Reactive templates** — `html` tagged template with text/attr/prop/event/ref bindings
|
|
41
|
+
- ✅ **Lifecycle helpers** — `onMount`, `onCleanup`, `onError`, `handle`, `watch`, `effect`, `fire.*`
|
|
42
|
+
- ✅ **Typed component APIs** — `defineComponent`, `prop`, `typed`, setup-context `emit` and `slots`
|
|
43
|
+
- ✅ **Context / DI** — `createContext`, `provide`, `inject`, `syncContextProps`
|
|
44
|
+
- ✅ **Form-associated controls** — `defineField` with `ElementInternals`
|
|
45
|
+
- ✅ **Observer utilities** — `observeResize` (main API) + `observeIntersection` / `observeMedia` (`/labs`)
|
|
46
|
+
- ✅ **Directive subpath** — `@vielzeug/craftit/directives`
|
|
47
|
+
- ✅ **Test subpath** — `@vielzeug/craftit/test`
|
|
184
48
|
|
|
185
|
-
|
|
49
|
+
## Entry Points
|
|
186
50
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
el.state.value = input.value;
|
|
193
|
-
el.form?.value(input.value);
|
|
194
|
-
});
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
// Use in forms
|
|
199
|
-
// <form>
|
|
200
|
-
// <custom-input name="username"></custom-input>
|
|
201
|
-
// <button type="submit">Submit</button>
|
|
202
|
-
// </form>
|
|
203
|
-
```
|
|
51
|
+
| Entry | Purpose |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `@vielzeug/craftit` | Main API (components + stateit re-exports) |
|
|
54
|
+
| `@vielzeug/craftit/directives` | Directive helpers like `each`, `when`, `bind`, `match`, `until` |
|
|
55
|
+
| `@vielzeug/craftit/test` | Mount/query/event testing utilities |
|
|
204
56
|
|
|
205
|
-
##
|
|
57
|
+
## Usage Highlights
|
|
206
58
|
|
|
207
|
-
###
|
|
208
|
-
|
|
209
|
-
State changes automatically trigger re-renders:
|
|
59
|
+
### Typed props + emits
|
|
210
60
|
|
|
211
61
|
```ts
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
62
|
+
import { defineComponent, html } from '@vielzeug/craftit';
|
|
63
|
+
|
|
64
|
+
defineComponent<
|
|
65
|
+
{ disabled: boolean; label: string },
|
|
66
|
+
{ change: string }
|
|
67
|
+
>({
|
|
68
|
+
props: {
|
|
69
|
+
disabled: { default: false },
|
|
70
|
+
label: { default: 'Name' },
|
|
216
71
|
},
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
// Any state change triggers re-render
|
|
226
|
-
el.state.todos.push('New todo'); // ✅ Automatic re-render
|
|
227
|
-
|
|
228
|
-
// Nested objects also reactive
|
|
229
|
-
el.state.filter = 'completed'; // ✅ Automatic re-render
|
|
72
|
+
setup({ emit, props }) {
|
|
73
|
+
return html`
|
|
74
|
+
<label>${props.label}</label>
|
|
75
|
+
<input
|
|
76
|
+
:disabled=${props.disabled}
|
|
77
|
+
@input=${(e: Event) => emit('change', (e.target as HTMLInputElement).value)}
|
|
78
|
+
/>
|
|
79
|
+
`;
|
|
230
80
|
},
|
|
81
|
+
tag: 'name-input',
|
|
231
82
|
});
|
|
232
83
|
```
|
|
233
84
|
|
|
234
|
-
###
|
|
235
|
-
|
|
236
|
-
Handle events on dynamic elements:
|
|
85
|
+
### Directives subpath
|
|
237
86
|
|
|
238
87
|
```ts
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
</
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
.join('')}
|
|
254
|
-
</ul>
|
|
255
|
-
`,
|
|
256
|
-
|
|
257
|
-
onConnected(el) {
|
|
258
|
-
// Works for dynamically added elements!
|
|
259
|
-
el.on('.delete', 'click', (e) => {
|
|
260
|
-
const index = +(e.currentTarget as HTMLElement).dataset.index!;
|
|
261
|
-
el.state.todos.splice(index, 1);
|
|
262
|
-
});
|
|
88
|
+
import { defineComponent, signal, html } from '@vielzeug/craftit';
|
|
89
|
+
import { each, when } from '@vielzeug/craftit/directives';
|
|
90
|
+
|
|
91
|
+
defineComponent({
|
|
92
|
+
setup() {
|
|
93
|
+
const todos = signal([{ id: 1, text: 'Write docs', done: false }]);
|
|
94
|
+
|
|
95
|
+
return html`
|
|
96
|
+
${when(
|
|
97
|
+
() => todos.value.length > 0,
|
|
98
|
+
() => html`<ul>${each(todos, (todo) => html`<li>${todo.text}</li>`, () => html``, { key: (t) => t.id })}</ul>`,
|
|
99
|
+
() => html`<p>No todos</p>`,
|
|
100
|
+
)}
|
|
101
|
+
`;
|
|
263
102
|
},
|
|
103
|
+
tag: 'todo-list',
|
|
264
104
|
});
|
|
265
105
|
```
|
|
266
106
|
|
|
267
|
-
###
|
|
268
|
-
|
|
269
|
-
Built-in CSS variable helpers with **automatic autocomplete**:
|
|
270
|
-
|
|
271
|
-
```ts
|
|
272
|
-
import { defineElement, html, css } from '@vielzeug/craftit';
|
|
273
|
-
|
|
274
|
-
// Create a typed theme
|
|
275
|
-
const theme = css.theme({
|
|
276
|
-
primaryColor: '#3b82f6',
|
|
277
|
-
bgColor: '#ffffff',
|
|
278
|
-
textColor: '#1f2937',
|
|
279
|
-
spacing: '1rem',
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
defineElement('themed-button', {
|
|
283
|
-
template: html`<button>Click Me</button>`,
|
|
284
|
-
|
|
285
|
-
styles: [
|
|
286
|
-
css`
|
|
287
|
-
/* Inject CSS variables */
|
|
288
|
-
${theme}
|
|
289
|
-
|
|
290
|
-
button {
|
|
291
|
-
/* ✨ Autocomplete works! Type theme. to see all properties */
|
|
292
|
-
background: ${theme.primaryColor}; /* var(--primary-color) */
|
|
293
|
-
color: ${theme.textColor}; /* var(--text-color) */
|
|
294
|
-
padding: ${theme.spacing}; /* var(--spacing) */
|
|
295
|
-
border: none;
|
|
296
|
-
border-radius: 8px;
|
|
297
|
-
}
|
|
298
|
-
`,
|
|
299
|
-
],
|
|
300
|
-
});
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
**Benefits:**
|
|
304
|
-
- ✅ **Autocomplete** - Type `theme.` and see all variables
|
|
305
|
-
- ✅ **Type-safe** - Typos caught at compile time
|
|
306
|
-
- ✅ **Refactoring** - Rename properties safely
|
|
307
|
-
- ✅ **Single import** - Just `import { css }`
|
|
308
|
-
|
|
309
|
-
### Lifecycle Hooks
|
|
107
|
+
### Form-associated field
|
|
310
108
|
|
|
311
109
|
```ts
|
|
312
|
-
|
|
313
|
-
template: html`<div>Component</div>`,
|
|
110
|
+
import { defineComponent, defineField, signal, html } from '@vielzeug/craftit';
|
|
314
111
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
112
|
+
defineComponent({
|
|
113
|
+
formAssociated: true,
|
|
114
|
+
setup() {
|
|
115
|
+
const value = signal('');
|
|
116
|
+
const field = defineField({ value });
|
|
117
|
+
|
|
118
|
+
return html`
|
|
119
|
+
<input
|
|
120
|
+
type="email"
|
|
121
|
+
:value=${value}
|
|
122
|
+
@input=${(e: Event) => {
|
|
123
|
+
value.value = (e.target as HTMLInputElement).value;
|
|
124
|
+
field.setCustomValidity(value.value.includes('@') ? '' : 'Invalid email');
|
|
125
|
+
}}
|
|
126
|
+
/>
|
|
127
|
+
`;
|
|
327
128
|
},
|
|
129
|
+
tag: 'email-field',
|
|
328
130
|
});
|
|
329
131
|
```
|
|
330
132
|
|
|
331
|
-
##
|
|
332
|
-
|
|
333
|
-
### `defineElement(name, options)`
|
|
334
|
-
|
|
335
|
-
Define and register a custom element.
|
|
336
|
-
|
|
337
|
-
```ts
|
|
338
|
-
defineElement('my-component', {
|
|
339
|
-
state: {}, // Initial state
|
|
340
|
-
template: html`...`, // Template (string, Node, or function)
|
|
341
|
-
styles: [css`...`], // CSS styles (auto-minified)
|
|
342
|
-
observedAttributes: [], // Attributes to watch
|
|
343
|
-
formAssociated: false, // Enable form participation
|
|
344
|
-
onConnected: (el) => {}, // Lifecycle: added to DOM
|
|
345
|
-
onDisconnected: (el) => {}, // Lifecycle: removed from DOM
|
|
346
|
-
onUpdated: (el) => {}, // Lifecycle: after render
|
|
347
|
-
onAttributeChanged: (name, oldVal, newVal, el) => {},
|
|
348
|
-
});
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### Component Instance API
|
|
352
|
-
|
|
353
|
-
```ts
|
|
354
|
-
// State
|
|
355
|
-
el.state.count = 10; // Direct mutation
|
|
356
|
-
await el.set({ count: 10 }); // Batch update
|
|
357
|
-
await el.set((state) => ({ ...state, count: 10 })); // Updater
|
|
358
|
-
|
|
359
|
-
// DOM Queries
|
|
360
|
-
el.find('.button'); // querySelector
|
|
361
|
-
el.findAll('.item'); // querySelectorAll
|
|
362
|
-
|
|
363
|
-
// Events
|
|
364
|
-
el.on('.button', 'click', handler); // Event delegation
|
|
365
|
-
el.emit('custom-event', { data }); // Dispatch event
|
|
366
|
-
|
|
367
|
-
// Utilities
|
|
368
|
-
el.delay(() => {}, 1000); // setTimeout with cleanup
|
|
369
|
-
el.clear(timeoutId); // clearTimeout
|
|
370
|
-
await el.flush(); // Wait for render
|
|
371
|
-
|
|
372
|
-
// Watchers
|
|
373
|
-
const unwatch = el.watch(
|
|
374
|
-
(state) => state.count,
|
|
375
|
-
(val, prev) => console.log(val, prev),
|
|
376
|
-
);
|
|
377
|
-
unwatch(); // Cleanup
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
## 🔥 Advanced Features
|
|
381
|
-
|
|
382
|
-
### Async State Updates
|
|
383
|
-
|
|
384
|
-
```ts
|
|
385
|
-
el.on('.load', 'click', async () => {
|
|
386
|
-
await el.set(async (state) => {
|
|
387
|
-
const data = await fetch('/api/data').then((r) => r.json());
|
|
388
|
-
return { ...state, data };
|
|
389
|
-
});
|
|
390
|
-
});
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
### State Watchers
|
|
394
|
-
|
|
395
|
-
```ts
|
|
396
|
-
const unwatch = el.watch(
|
|
397
|
-
(state) => state.count,
|
|
398
|
-
(count, prevCount) => {
|
|
399
|
-
console.log(`Count changed from ${prevCount} to ${count}`);
|
|
400
|
-
},
|
|
401
|
-
);
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
### Testing Utilities
|
|
405
|
-
|
|
406
|
-
```ts
|
|
407
|
-
import { attach, destroy } from '@vielzeug/craftit';
|
|
408
|
-
|
|
409
|
-
const el = document.createElement('my-component');
|
|
410
|
-
await attach(el); // Mounts and waits for render
|
|
411
|
-
|
|
412
|
-
// Test assertions
|
|
413
|
-
expect(el.find('.count')?.textContent).toBe('0');
|
|
414
|
-
|
|
415
|
-
destroy(el); // Clean removal
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
## 📖 Documentation
|
|
419
|
-
|
|
420
|
-
- [**Full Documentation**](https://vielzeug.dev/craftit)
|
|
421
|
-
- [**Usage Guide**](https://vielzeug.dev/craftit/usage)
|
|
422
|
-
- [**API Reference**](https://vielzeug.dev/craftit/api)
|
|
423
|
-
- [**Examples**](https://vielzeug.dev/craftit/examples)
|
|
424
|
-
|
|
425
|
-
## 🆚 Comparison
|
|
426
|
-
|
|
427
|
-
| Feature | Craftit | Lit | Stencil |
|
|
428
|
-
| ---------------- | --------- | -------- | --------- |
|
|
429
|
-
| Bundle Size | **~6 KB** | ~15 KB | ~10 KB |
|
|
430
|
-
| Dependencies | 0 | 0 | Many |
|
|
431
|
-
| TypeScript | Native | Good | Excellent |
|
|
432
|
-
| Reactive State | Built-in | External | Built-in |
|
|
433
|
-
| Event Delegation | ✅ | ❌ | ❌ |
|
|
434
|
-
| Form Integration | ✅ | ⚠️ | ✅ |
|
|
435
|
-
| Learning Curve | Low | Medium | High |
|
|
133
|
+
## API Summary
|
|
436
134
|
|
|
437
|
-
|
|
135
|
+
| Group | Main exports |
|
|
136
|
+
|---|---|
|
|
137
|
+
| Components | `defineComponent`, `DefineComponentOptions`, `DefineComponentSetupContext`, `BuildPropSchema` |
|
|
138
|
+
| Runtime | `onMount`, `onCleanup`, `onError`, `handle`, `aria`, `effect`, `watch`, `fire` |
|
|
139
|
+
| Props | `prop`, `typed`, `PropOptions`, `PropDef`, `InferPropsSignals` |
|
|
140
|
+
| Slots / emits | setup-context `slots`, setup-context `emit`, `onSlotChange`, `Slots`, `EmitFn` |
|
|
141
|
+
| Context | `createContext`, `provide`, `inject`, `syncContextProps`, `InjectionKey` |
|
|
142
|
+
| Form | `defineField`, `FormFieldOptions`, `FormFieldCallbacks`, `FormFieldHandle` |
|
|
143
|
+
| Observers | `observeResize`, `observeIntersection`, `observeMedia` |
|
|
144
|
+
| Utilities | `html`, `css`, `createId`, `createFormIds`, `guard`, `escapeHtml`, `toKebab` |
|
|
145
|
+
| Re-exported from stateit | `signal`, `computed`, `batch`, `untrack`, `readonly`, and more |
|
|
438
146
|
|
|
439
|
-
|
|
147
|
+
## Documentation
|
|
440
148
|
|
|
441
|
-
|
|
149
|
+
Full docs at **[vielzeug.dev/craftit](https://vielzeug.dev/craftit)**
|
|
442
150
|
|
|
443
|
-
|
|
151
|
+
| | |
|
|
152
|
+
|---|---|
|
|
153
|
+
| [Overview](https://vielzeug.dev/craftit/) | Install and architecture overview |
|
|
154
|
+
| [Usage Guide](https://vielzeug.dev/craftit/usage) | Practical patterns and subpath usage |
|
|
155
|
+
| [API Reference](https://vielzeug.dev/craftit/api) | Complete signatures and types |
|
|
156
|
+
| [Examples](https://vielzeug.dev/craftit/examples) | End-to-end component examples |
|
|
444
157
|
|
|
445
|
-
##
|
|
158
|
+
## License
|
|
446
159
|
|
|
447
|
-
|
|
448
|
-
- [GitHub](https://github.com/saatkhel/vielzeug)
|
|
449
|
-
- [NPM](https://www.npmjs.com/package/@vielzeug/craftit)
|
|
160
|
+
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu) — Part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`./internal.cjs`),t=require(`./runtime-lifecycle.cjs`),n=require(`./utilities.cjs`),r=require(`./host.cjs`),i=require(`./template-dom.cjs`);require(`./template-bindings.cjs`),require(`./template-html.cjs`);const a=require(`./template.cjs`);let o=require(`@vielzeug/stateit`);var s=new WeakMap,c=new WeakMap,l=(e,n)=>{let r=t.currentRuntime().el;if(!r.constructor.formAssociated)throw Error(`[craftit:E8] defineField() requires defineComponent({ formAssociated: true })`);let i=c.get(r)??r.attachInternals();c.set(r,i);let a=e.toFormValue??(e=>e==null?``:String(e));return(0,o.effect)(()=>{i.setFormValue(a(e.value.value))}),e.disabled&&(0,o.effect)(()=>{e.disabled.value?i.states.add(`disabled`):i.states.delete(`disabled`)}),n&&s.set(r,{...s.get(r),...n}),{checkValidity:()=>i.checkValidity(),internals:i,reportValidity:()=>i.reportValidity(),setCustomValidity:e=>e?i.setValidity({customError:!0},e):i.setValidity({}),setValidity:i.setValidity.bind(i)}},u=new Set([`default`,`omit`,`parse`,`reflect`,`type`]),d=e=>typeof e!=`object`||!e||!(`default`in e)?!1:Object.keys(e).every(e=>u.has(e)),f=new WeakMap,p=(e,r,i)=>{let a=t.currentRuntime(),s=a.el;f.has(s)||f.set(s,new Map);let c=i?.parse??(e=>i?.type===Boolean?e===``||e===`true`:typeof r==`boolean`?e!==null&&e!==`false`:e==null?r:i?.type===Number||typeof r==`number`?Number(e):e),l=(0,o.signal)(r),u=Object.prototype.hasOwnProperty.call(s,e),d=u?s[e]:void 0,p={parse:c,reflect:i?.reflect??!0,signal:l};if(u?(delete s[e],l.value=d):s.hasAttribute(e)&&(l.value=c(s.getAttribute(e))),f.get(s).set(e,p),Object.defineProperty(s,e,{configurable:!0,enumerable:!0,get:()=>l.value,set:e=>{l.value=e}}),i?.reflect??!0){let t=i?.omit??!1;a.onMount.push(()=>{a.cleanups.push((0,o.effect)(()=>{let r=l.value;r==null||r===!1||t&&r===``?s.removeAttribute(e):n.setAttr(s,e,r)}))})}return l};function m(e){let t={};for(let[r,i]of Object.entries(e)){let e=d(i)?i:{default:i},a={reflect:!(typeof e.default==`object`&&e.default!==null||Array.isArray(e.default)),...e};t[r]=p(n.toKebab(r),e.default,a)}return t}var h=(e,t)=>({...t,default:e}),g=class extends HTMLElement{static _setup;static _options;static formAssociated=!1;static observedAttributes=[];shadow;_keyedStates=new Map;_mountFns=[];_template=null;_appliedHtmlBindings=new Set;_setupDone=!1;_runtime;constructor(){super();let e=this.constructor._options;this.shadow=this.attachShadow({mode:`open`,...e?.shadow}),this._runtime={cleanups:[],el:this,errorHandlers:[],onMount:[],styles:e?.styles}}connectedCallback(){this._setupDone||this._runSetup(),this._init()}attributeChangedCallback(e,t,n){if(t===n)return;let r=f.get(this)?.get(e);if(!r)return;let i=r.parse(n);Object.is(r.signal.peek(),i)||(r.signal.value=i)}disconnectedCallback(){n.runAll(this._runtime.cleanups),this._runtime.cleanups=[],this._runtime.onMount=this._mountFns.slice(),this._appliedHtmlBindings.clear(),this._keyedStates.clear()}formAssociatedCallback(e){s.get(this)?.onAssociated?.(e)}formDisabledCallback(e){s.get(this)?.onDisabled?.(e)}formResetCallback(){s.get(this)?.onReset?.()}formStateRestoreCallback(e,t){s.get(this)?.onStateRestore?.(e,t)}_handleError(e){if(this._runtime.errorHandlers.length>0)for(let t of this._runtime.errorHandlers)t(e);else console.error(`[craftit:E3] <${this.localName}>`,e)}_runSetup(){this._setupDone=!0,t.runtimeStack.push(this._runtime);try{let{host:e}=this.constructor._options??{};if(e)for(let[t,n]of Object.entries(e))typeof n==`boolean`?n?this.setAttribute(t,``):this.removeAttribute(t):this.setAttribute(t,String(n));let t=this.constructor._setup({host:this,shadow:this.shadow});(typeof t==`string`||typeof t==`object`&&t&&`__html`in t)&&(this._template=t)}catch(e){this._handleError(e)}finally{t.runtimeStack.pop()}}_init(){let{styles:r}=this._runtime;if(r?.length&&(this.shadow.adoptedStyleSheets=r.map(n.loadStylesheet)),this._template){let t=typeof this._template==`string`?e.htmlResult(this._template):this._template;if(this.shadow.replaceChildren(i.parseHTML(t.__html)),t.__bindings.length){let e=e=>this._runtime.cleanups.push(e);a.applyBindingsInContainer(this.shadow,t.__bindings,e,{onHtml:t=>{this._appliedHtmlBindings.has(t.uid)||(this._appliedHtmlBindings.add(t.uid),a.applyHtmlBinding(this.shadow,t,e,this._keyedStates))}})}}queueMicrotask(()=>{t.runtimeStack.push(this._runtime);try{let e=this._runtime.onMount;this._mountFns=e.slice();for(let t of e){let e=t();typeof e==`function`&&this._runtime.cleanups.push(e)}}catch(e){this._handleError(e)}finally{t.runtimeStack.pop(),this._runtime.onMount=[]}})}};function _(e,t,n={}){if(!e)throw Error(`[craftit:E4] registerComponent(tag, ...) requires a tag name`);if(customElements.get(e))throw Error(`[craftit:E9] custom element already defined: ${e}`);class r extends g{static _setup=t;static _options=n;static formAssociated=n.formAssociated??!1;static observedAttributes=n.observedAttrs??[]}return customElements.define(e,r),e}function v(e){let{formAssociated:t,host:i,props:a,setup:o,shadow:s,styles:c,tag:l}=e;return _(l,e=>{let t=a?m(a):{},i=n.createEmitFn(),s=r.createSlots();return o({emit:i,host:e.host,props:t,reflect:t=>r.reflect(e.host,t),shadow:e.shadow,slots:s})},{formAssociated:t,host:i,observedAttrs:a?Object.keys(a).map(n.toKebab):[],shadow:s,styles:c})}exports.defineComponent=v,exports.defineField=l,exports.prop=p,exports.propRegistry=f,exports.typed=h;
|
|
2
|
+
//# sourceMappingURL=component.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component.cjs","names":[],"sources":["../../src/core/component.ts"],"sourcesContent":["/**\n * Component authoring API — define, props, lifecycle, and form field functionality.\n *\n * - defineComponent: Main API for building typed custom elements\n * - prop/typed/createProps: Reactive property definitions\n * - defineField: Form field integration\n */\n\nimport {\n type CleanupFn,\n type ComputedSignal,\n type ReadonlySignal,\n type Signal,\n signal,\n effect,\n} from '@vielzeug/stateit';\n\nimport { createSlots, type Slots, type ReflectConfig } from './host';\nimport { reflect } from './host';\nimport { type HTMLResult, htmlResult } from './internal';\nimport { currentRuntime, runtimeStack } from './runtime-lifecycle';\nimport { applyBindingsInContainer, applyHtmlBinding } from './template';\nimport { type RegisterCleanup } from './template-bindings';\nimport { parseHTML } from './template-dom';\nimport { type KeyedNode } from './template-html';\nimport { createEmitFn, type EmitFn, setAttr, toKebab, runAll, loadStylesheet, type CSSResult } from './utilities';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FORM FIELD API\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** @internal */\nexport const formCallbackRegistry = new WeakMap<HTMLElement, FormFieldCallbacks>();\n/** @internal */\nexport const internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n\n/**\n * Callbacks that hook into form lifecycle events. Can be passed directly to {@link defineField}\n * as a second argument to keep all form logic co-located.\n */\nexport type FormFieldCallbacks = {\n onAssociated?: (form: HTMLFormElement | null) => void;\n onDisabled?: (disabled: boolean) => void;\n onReset?: () => void;\n onStateRestore?: (state: unknown, mode: 'autocomplete' | 'restore') => void;\n};\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: Signal<boolean> | ReadonlySignal<boolean> | ComputedSignal<boolean>;\n toFormValue?: (value: T) => File | FormData | string | null;\n value: Signal<T> | ReadonlySignal<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n setCustomValidity: (message: string) => void;\n setValidity: ElementInternals['setValidity'];\n};\n\nexport const defineField = <T = unknown>(\n options: FormFieldOptions<T>,\n callbacks?: FormFieldCallbacks,\n): FormFieldHandle => {\n const rt = currentRuntime();\n const host = rt.el;\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new Error('[craftit:E8] defineField() requires defineComponent({ formAssociated: true })');\n }\n\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n\n const toFormValue = options.toFormValue ?? ((v: T) => (v == null ? '' : String(v)));\n\n effect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n if (options.disabled) {\n effect(() => {\n if (options.disabled!.value) {\n internals.states.add('disabled');\n } else {\n internals.states.delete('disabled');\n }\n });\n }\n\n if (callbacks) {\n formCallbackRegistry.set(host, { ...formCallbackRegistry.get(host), ...callbacks });\n }\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n setValidity: internals.setValidity.bind(internals),\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// PROP SYSTEM\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype PropType<T> = T extends string\n ? StringConstructor\n : T extends number\n ? NumberConstructor\n : T extends boolean\n ? BooleanConstructor\n : T extends unknown[]\n ? ArrayConstructor\n : ObjectConstructor;\n\nexport type PropOptions<T> = {\n /** When `true`, removes the host attribute instead of setting it to `\"\"` when the value is an empty string. */\n omit?: boolean;\n parse?: (value: string | null) => T;\n reflect?: boolean;\n type?: PropType<T>;\n};\n\nexport type PropDef<T> = PropOptions<T> & { default: T };\nexport type PropInputDefs = Record<string, unknown | PropDef<unknown>>;\n\ntype PropMeta<T = unknown> = {\n parse: (value: string | null) => T;\n reflect: boolean;\n signal: Signal<T>;\n};\n\nconst PROP_DEF_KEYS = new Set(['default', 'omit', 'parse', 'reflect', 'type']);\nconst isPropDef = (value: unknown): value is PropDef<unknown> => {\n if (typeof value !== 'object' || value === null || !('default' in value)) return false;\n\n return Object.keys(value).every((key) => PROP_DEF_KEYS.has(key));\n};\n\nexport const propRegistry = new WeakMap<object, Map<string, PropMeta<unknown>>>();\n\nexport const prop = <T>(name: string, defaultValue: T, options?: PropOptions<T>): Signal<T> => {\n const rt = currentRuntime();\n const el = rt.el;\n\n if (!propRegistry.has(el)) propRegistry.set(el, new Map());\n\n const parse =\n options?.parse ??\n ((v: string | null): T => {\n // Explicit Boolean type: string values 'true' / '' → boolean\n if (options?.type === Boolean) return (v === '' || v === 'true') as T;\n\n // Boolean default: treat absent or explicit \"false\" as false, anything else as true.\n // This handles frameworks (e.g. Vue) that set the attribute to the string \"false\"\n // when a reactive binding evaluates to false, rather than removing the attribute.\n if (typeof defaultValue === 'boolean') return (v !== null && v !== 'false') as T;\n\n if (v == null) return defaultValue;\n\n // Numeric — inferred from an explicit type option or default value type\n if (options?.type === Number || typeof defaultValue === 'number') return Number(v) as T;\n\n return v as unknown as T;\n });\n const s = signal<T>(defaultValue);\n const hasPreUpgradeProperty = Object.prototype.hasOwnProperty.call(el, name);\n const preUpgradeValue = hasPreUpgradeProperty ? (el as unknown as Record<string, unknown>)[name] : undefined;\n\n const meta = {\n parse,\n reflect: options?.reflect ?? true,\n signal: s as Signal<unknown>,\n };\n\n // Prefer pre-upgrade property values set before defineProperty() (common for\n // framework/host property bindings), then fall back to attributes.\n if (hasPreUpgradeProperty) {\n delete (el as unknown as Record<string, unknown>)[name];\n s.value = preUpgradeValue as T;\n } else if (el.hasAttribute(name)) {\n s.value = parse(el.getAttribute(name)) as T;\n }\n\n propRegistry.get(el)!.set(name, meta);\n\n Object.defineProperty(el, name, {\n configurable: true,\n enumerable: true,\n get: () => s.value,\n set: (value: T) => {\n s.value = value;\n },\n });\n\n if (options?.reflect ?? true) {\n const omit = options?.omit ?? false;\n\n rt.onMount.push(() => {\n rt.cleanups.push(\n effect(() => {\n const v = s.value;\n\n if (v == null || v === false || (omit && v === '')) {\n el.removeAttribute(name);\n } else {\n setAttr(el, name, v);\n }\n }),\n );\n });\n }\n\n return s;\n};\n\ntype InferPropValue<T> = T extends object\n ? Exclude<keyof T, keyof PropDef<unknown>> extends never\n ? T extends PropDef<infer U>\n ? U\n : T\n : T\n : T;\n\nexport type InferPropsSignals<T extends PropInputDefs> = {\n [K in keyof T]: Signal<InferPropValue<T[K]>>;\n};\n\nexport function createProps<D extends PropInputDefs>(defs: D): InferPropsSignals<D> {\n const result = {} as Record<string, Signal<unknown>>;\n\n for (const [name, def] of Object.entries(defs)) {\n const descriptor = isPropDef(def) ? (def as PropDef<unknown>) : { default: def };\n const hasStructuredDefault =\n (typeof descriptor.default === 'object' && descriptor.default !== null) || Array.isArray(descriptor.default);\n const propDef: PropOptions<unknown> = { reflect: !hasStructuredDefault, ...descriptor };\n\n result[name] = prop(toKebab(name), descriptor.default, propDef);\n }\n\n return result as InferPropsSignals<D>;\n}\n\n/**\n * Forces TypeScript to infer the prop signal type from `T` rather than the default\n * value's literal type. Use in `defineComponent({ props: ... })` when the default\n * is `undefined` or when you want an explicit union type.\n *\n * @example\n * defineComponent<ButtonProps>({\n * props: {\n * color: typed<ThemeColor | undefined>(undefined),\n * disabled: { default: false },\n * },\n * setup({ props }) {\n * return html`<button>${props.color}</button>`;\n * },\n * tag: 'x-button',\n * });\n */\nexport const typed = <T>(defaultValue: T, options?: PropOptions<T>): PropDef<T> => ({\n ...options,\n default: defaultValue,\n});\n\n// ─────────────────────────────────────────────────────────────────────────────\n// COMPONENT SETUP & REGISTRATION\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type ComponentSetupContext = {\n /** The host `HTMLElement` instance for this component. */\n host: HTMLElement;\n /** Shorthand for `host.shadowRoot` — the component's open shadow root. */\n shadow: ShadowRoot;\n};\n\nexport type ComponentRegistrationOptions = {\n /** Indicates if this should be a form-associated element */\n formAssociated?: boolean;\n /** Custom options for host element (e.g. for aria-*) */\n host?: Record<string, string | boolean | number>;\n /** @internal — list of attribute names to observe via attributeChangedCallback */\n observedAttrs?: string[];\n /** Shadow root init options (mode is always 'open') — use e.g. `{ delegatesFocus: true }` for form controls */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component styles applied to the shadow root. Static — set at definition time, not per-render. */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\n/**\n * Helper type to build a prop schema from a props interface type.\n * Each property maps to a PropOptions shape with a `default` value.\n */\nexport type BuildPropSchema<T> = {\n [K in keyof T]-?: PropDef<T[K]>;\n};\n\n/**\n * Unified setup context passed to `defineComponent` setup function.\n * Both Props and Events generics flow through to give full type safety.\n */\nexport type DefineComponentSetupContext<\n P extends Record<string, PropOptions<any>> = Record<string, never>,\n E extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Typed emit function — fully inferred from the Events generic */\n emit: EmitFn<E>;\n /** Host element */\n host: HTMLElement;\n /** Reactive props as signals — fully inferred from the Props generic */\n props: InferPropsSignals<P>;\n /** Reflect reactive attributes, events and classes to the host */\n reflect: (config: ReflectConfig) => void;\n /** Shadow root */\n shadow: ShadowRoot;\n /** Slots helper */\n slots: Slots<any>;\n};\n\n/**\n * Configuration object for `defineComponent()`.\n * Note: no `emits` field — declare events via the Events generic instead.\n */\nexport type DefineComponentOptions<\n PropsSchema extends Record<string, PropDef<any>> = Record<string, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Whether this element is form-associated */\n formAssociated?: boolean;\n /** Host element attributes */\n host?: Record<string, string | boolean | number>;\n /** Property definitions */\n props?: PropsSchema;\n /** Setup function — returns a template */\n setup: (ctx: DefineComponentSetupContext<PropsSchema, Emits>) => string | HTMLResult;\n /** Shadow root init options */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component styles */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n /** Custom element tag name (must include a hyphen) */\n tag: string;\n};\n\n// ─── Base custom element ──────────────────────────────────────────────────────\n\ntype ComponentRuntime = {\n cleanups: CleanupFn[];\n el: HTMLElement;\n errorHandlers: Array<(err: unknown) => void>;\n onMount: Array<() => CleanupFn | undefined | void>;\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\n// Lifecycle methods (connectedCallback, attributeChangedCallback, …) are invoked\n// by the browser runtime, not TypeScript code — suppress false-positive lint warnings.\n\nclass BaseElement extends HTMLElement {\n static _setup: (ctx: ComponentSetupContext) => string | HTMLResult;\n static _options?: ComponentRegistrationOptions;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n shadow: ShadowRoot;\n private _keyedStates = new Map<string, Map<string | number, KeyedNode>>();\n private _mountFns: (() => CleanupFn | undefined | void)[] = [];\n private _template: string | HTMLResult | null = null;\n private _appliedHtmlBindings = new Set<string>();\n private _setupDone = false;\n private _runtime: ComponentRuntime;\n\n constructor() {\n super();\n\n const options = (this.constructor as typeof BaseElement)._options;\n\n this.shadow = this.attachShadow({ mode: 'open', ...options?.shadow });\n this._runtime = {\n cleanups: [],\n el: this,\n errorHandlers: [],\n onMount: [],\n styles: options?.styles,\n };\n }\n\n connectedCallback(): void {\n if (!this._setupDone) this._runSetup();\n\n this._init();\n }\n\n // Fires synchronously on observed attribute change — no MutationObserver needed.\n // observedAttributes is set at class-definition time from the prop schema.\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const meta = propRegistry.get(this)?.get(name);\n\n if (!meta) return;\n\n const parsed = meta.parse(newValue);\n\n if (!Object.is(meta.signal.peek(), parsed)) meta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n runAll(this._runtime.cleanups);\n this._runtime.cleanups = [];\n this._runtime.onMount = this._mountFns.slice(); // restore for reconnect\n this._appliedHtmlBindings.clear();\n this._keyedStates.clear();\n }\n\n formAssociatedCallback(form: HTMLFormElement | null): void {\n formCallbackRegistry.get(this)?.onAssociated?.(form);\n }\n\n formDisabledCallback(disabled: boolean): void {\n formCallbackRegistry.get(this)?.onDisabled?.(disabled);\n }\n\n formResetCallback(): void {\n formCallbackRegistry.get(this)?.onReset?.();\n }\n\n formStateRestoreCallback(state: unknown, mode: 'autocomplete' | 'restore'): void {\n formCallbackRegistry.get(this)?.onStateRestore?.(state, mode);\n }\n\n private _handleError(err: unknown): void {\n if (this._runtime.errorHandlers.length > 0) {\n for (const fn of this._runtime.errorHandlers) fn(err);\n } else {\n console.error(`[craftit:E3] <${this.localName}>`, err);\n }\n }\n\n private _runSetup(): void {\n this._setupDone = true;\n runtimeStack.push(this._runtime as any);\n\n try {\n const { host: hostOptions } = (this.constructor as typeof BaseElement)._options ?? {};\n\n if (hostOptions) {\n for (const [name, value] of Object.entries(hostOptions)) {\n if (typeof value === 'boolean') {\n if (value) {\n this.setAttribute(name, '');\n } else {\n this.removeAttribute(name);\n }\n } else {\n this.setAttribute(name, String(value));\n }\n }\n }\n\n const res = (this.constructor as typeof BaseElement)._setup({ host: this, shadow: this.shadow });\n\n if (typeof res === 'string' || (typeof res === 'object' && res !== null && '__html' in res)) {\n this._template = res as string | HTMLResult;\n }\n } catch (err) {\n this._handleError(err);\n } finally {\n runtimeStack.pop();\n }\n }\n\n private _init(): void {\n const { styles } = this._runtime;\n\n // Apply styles synchronously before rendering to prevent FOUC.\n if (styles?.length) this.shadow.adoptedStyleSheets = styles.map(loadStylesheet);\n\n if (this._template) {\n const result: HTMLResult = typeof this._template === 'string' ? htmlResult(this._template) : this._template;\n\n this.shadow.replaceChildren(parseHTML(result.__html));\n\n if (result.__bindings.length) {\n const registerCleanup: RegisterCleanup = (fn) => this._runtime.cleanups.push(fn);\n\n applyBindingsInContainer(this.shadow, result.__bindings, registerCleanup, {\n onHtml: (b) => {\n if (!this._appliedHtmlBindings.has(b.uid)) {\n this._appliedHtmlBindings.add(b.uid);\n applyHtmlBinding(this.shadow, b, registerCleanup, this._keyedStates);\n }\n },\n });\n }\n }\n\n // Defer onMount callbacks to a microtask for deterministic timing.\n // Components that depend on layout/paint should schedule rAF inside onMount.\n queueMicrotask(() => {\n runtimeStack.push(this._runtime as any);\n\n try {\n const fns = this._runtime.onMount;\n\n this._mountFns = fns.slice(); // snapshot for reconnect\n\n for (const fn of fns) {\n const cleanup = fn();\n\n if (typeof cleanup === 'function') this._runtime.cleanups.push(cleanup);\n }\n } catch (err) {\n this._handleError(err);\n } finally {\n runtimeStack.pop();\n this._runtime.onMount = [];\n }\n });\n }\n}\n\n// ─── Component registration ───────────────────────────────────────────────────\n\n/** @internal — use `defineComponent` instead. */\nexport function registerComponent(\n tag: string,\n setup: (ctx: ComponentSetupContext) => string | HTMLResult,\n options: ComponentRegistrationOptions = {},\n): string {\n if (!tag) throw new Error('[craftit:E4] registerComponent(tag, ...) requires a tag name');\n\n if (customElements.get(tag)) {\n throw new Error(`[craftit:E9] custom element already defined: ${tag}`);\n }\n\n class Element extends BaseElement {\n static override _setup = setup;\n static override _options = options;\n static override formAssociated = options.formAssociated ?? false;\n static override observedAttributes = options.observedAttrs ?? [];\n }\n\n customElements.define(tag, Element);\n\n return tag;\n}\n\n/**\n * Defines a custom element with a cohesive, type-safe API.\n *\n * Pass your Props and Events interfaces as generics — everything in `setup`\n * is fully typed with zero boilerplate.\n *\n * @example\n * ```ts\n * type MyProps = { checked?: boolean; disabled?: boolean };\n * type MyEvents = { change: { checked: boolean } };\n *\n * defineComponent<MyProps, MyEvents>({\n * tag: 'my-checkbox',\n * props: {\n * checked: { default: false },\n * disabled: { default: false },\n * },\n * setup({ props, emit }) {\n * // props.checked → Signal<boolean> ✅\n * // emit('change', { checked: true }) ✅\n * },\n * });\n * ```\n */\nexport function defineComponent<\n PropsType = Record<string, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n>(options: DefineComponentOptions<BuildPropSchema<PropsType>, EventsType>): string {\n const { formAssociated, host: hostOptions, props: propDefs, setup, shadow: shadowOptions, styles, tag } = options;\n\n // Derive observed attribute names from prop schema at definition time so\n // attributeChangedCallback fires correctly — no MutationObserver needed.\n const observedAttrs = propDefs ? Object.keys(propDefs).map(toKebab) : [];\n\n return registerComponent(\n tag,\n (ctx) => {\n const props = propDefs\n ? createProps(propDefs as BuildPropSchema<PropsType>)\n : ({} as InferPropsSignals<BuildPropSchema<PropsType>>);\n const emit = createEmitFn<EventsType>();\n const slots = createSlots<any>();\n\n return setup({\n emit: emit as EmitFn<EventsType>,\n host: ctx.host,\n props,\n reflect: (config: ReflectConfig) => reflect(ctx.host, config),\n shadow: ctx.shadow,\n slots,\n } as DefineComponentSetupContext<BuildPropSchema<PropsType>, EventsType>);\n },\n { formAssociated, host: hostOptions, observedAttrs, shadow: shadowOptions, styles },\n );\n}\n"],"mappings":"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"}
|