@neuralfog/elemix 0.1.8 → 0.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.
- package/README.md +356 -1
- package/dist/App-tMVVu8H5.js +1 -0
- package/dist/Reactive-BR9C38bG.js +1 -0
- package/dist/app.js +1 -1
- package/dist/chunk-NGjzN6Tu.js +1 -0
- package/dist/decorators.js +1 -1
- package/dist/directives.d.ts +2 -2
- package/dist/directives.js +1 -1
- package/dist/index.js +1 -1
- package/dist/reactive.js +1 -1
- package/dist/renderers-DuXHBLlK.js +1 -0
- package/dist/signal.js +1 -1
- package/dist/src/Reactive.d.ts +1 -1
- package/dist/src/component/Component.d.ts +1 -3
- package/dist/test/renderer/attribute-bindings.test.d.ts +1 -0
- package/dist/test/renderer/conditionals.test.d.ts +1 -1
- package/dist/test/renderer/directives.test.d.ts +1 -0
- package/dist/test/renderer/edge-cases.test.d.ts +1 -0
- package/dist/test/renderer/event-bindings.test.d.ts +1 -0
- package/dist/test/renderer/merge-classes.test.d.ts +1 -0
- package/dist/test/renderer/multiple-root-nodes.test.d.ts +1 -1
- package/dist/types-v1ChTfwQ.js +1 -0
- package/dist/utilities-BN8G-efH.js +1 -0
- package/dist/utilities.js +1 -1
- package/package.json +11 -10
- package/dist/renderers-CTogHRY2.js +0 -1
- package/dist/src/component/Emits.d.ts +0 -4
- package/dist/test/fixtures/renderer/SelfClosed.d.ts +0 -5
- package/dist/test/fixtures/renderer/SelfClosingTags.d.ts +0 -16
- package/dist/test/renderer/self-closing.test.d.ts +0 -1
- package/dist/types-D5TcFW7H.js +0 -1
- package/dist/utilities-oGilfnVK.js +0 -1
package/README.md
CHANGED
|
@@ -1 +1,356 @@
|
|
|
1
|
-
|
|
1
|
+
# ⚡ Elemix
|
|
2
|
+
|
|
3
|
+
Reactive elements based on Custom Elements.
|
|
4
|
+
|
|
5
|
+
This is a personal project built for my own use. It is not open source and comes with no guarantees, warranties, or support.
|
|
6
|
+
|
|
7
|
+
## Why?
|
|
8
|
+
|
|
9
|
+
Because I can. The goal is a lean approach that utilizes as much of the native web platform as possible, with absolute freedom in how the application is architected by the implementer.
|
|
10
|
+
|
|
11
|
+
## Reactivity
|
|
12
|
+
|
|
13
|
+
There is no virtual DOM. Rendering is handled by [elemix-renderer](https://github.com/neuralfog/elemix-renderer) which performs direct DOM mutations. Elemix uses a pub/sub model built on JS proxies. State objects are wrapped in a `Proxy` that intercepts property mutations. When a value is set, the proxy notifies all subscribed components, triggering a re-render. Nested objects are lazily wrapped in proxies on access, so deep mutations are also reactive. Components subscribe automatically when using `@state()` or `signals`.
|
|
14
|
+
|
|
15
|
+
Render scheduling is batched via `setTimeout(0)` — multiple state mutations in the same synchronous frame are coalesced into a single render. Once a render is scheduled, further mutations are locked until the next microtask, preventing redundant DOM updates.
|
|
16
|
+
|
|
17
|
+
Collections (`Map`, `Set`, `WeakMap`, `WeakSet`) are not supported in reactive state.
|
|
18
|
+
|
|
19
|
+
## Init
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { initApp } from '@neuralfog/elemix/app';
|
|
23
|
+
import { makeCssStylesheet } from '@neuralfog/elemix/utilities';
|
|
24
|
+
|
|
25
|
+
import reset from './styles/reset.scss?inline';
|
|
26
|
+
|
|
27
|
+
initApp({
|
|
28
|
+
baseStyles: [makeCssStylesheet(reset)],
|
|
29
|
+
entryPoint: () => import('./components/MainApp'),
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Hello World Component
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { Component } from '@neuralfog/elemix';
|
|
37
|
+
import { component } from '@neuralfog/elemix/decorators';
|
|
38
|
+
import { html, type Template } from '@neuralfog/elemix/types';
|
|
39
|
+
|
|
40
|
+
@component()
|
|
41
|
+
export class HelloWorld extends Component {
|
|
42
|
+
template = (): Template => {
|
|
43
|
+
return html`<h1>Hello World!</h1>`;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Styles
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { Component, html, type Template } from '@neuralfog/elemix';
|
|
52
|
+
import { component } from '@neuralfog/elemix/decorators';
|
|
53
|
+
|
|
54
|
+
import css from './HelloWorld.scss?inline';
|
|
55
|
+
|
|
56
|
+
@component({ styles: [css] })
|
|
57
|
+
export class HelloWorld extends Component {
|
|
58
|
+
template(): Template {
|
|
59
|
+
return html`<h1>Hello World!</h1>`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Rendering
|
|
65
|
+
|
|
66
|
+
Renders are triggered implicitly by mutating `@state()` properties or subscribed signals. To trigger a render manually, call `this.render()`. This is useful when you want fine control over rendering without reactivity getting in the way.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
@component()
|
|
70
|
+
export class UserCard extends Component {
|
|
71
|
+
private name = 'John';
|
|
72
|
+
|
|
73
|
+
updateName(name: string): void {
|
|
74
|
+
this.name = name;
|
|
75
|
+
this.render();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
template(): Template {
|
|
79
|
+
return html`<p>${this.name}</p>`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Props
|
|
85
|
+
|
|
86
|
+
Primitive props are shallow-diffed and only trigger updates when the value changes. Object props are passed through reactively. Functions are assigned once.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { Component, html, type Template } from '@neuralfog/elemix';
|
|
90
|
+
import { component } from '@neuralfog/elemix/decorators';
|
|
91
|
+
|
|
92
|
+
type Props = {
|
|
93
|
+
name: string;
|
|
94
|
+
age: number;
|
|
95
|
+
handler: () => void;
|
|
96
|
+
meta: { role: string; active: boolean };
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
@component()
|
|
100
|
+
export class UserCard extends Component<Props> {
|
|
101
|
+
template(): Template {
|
|
102
|
+
const { name, age, handler, meta } = this.props;
|
|
103
|
+
|
|
104
|
+
return html`<div>
|
|
105
|
+
<p>${name}</p>
|
|
106
|
+
<p>${age}</p>
|
|
107
|
+
<p>${meta.role}</p>
|
|
108
|
+
<button @click=${handler}>Click</button>
|
|
109
|
+
</div>`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
html`<user-card
|
|
116
|
+
:name=${'John'}
|
|
117
|
+
:age=${25}
|
|
118
|
+
:handler=${() => console.log('clicked')}
|
|
119
|
+
:meta=${{ role: 'admin', active: true }}
|
|
120
|
+
/>`;
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Object props can be freely mutated — proxies retain reactivity and trigger updates for all subscribed components.
|
|
124
|
+
|
|
125
|
+
## State
|
|
126
|
+
|
|
127
|
+
Local state is managed via the `@state()` decorator. Mutating any property on the state object will automatically trigger a re-render.
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { Component, html, type Template } from '@neuralfog/elemix';
|
|
131
|
+
import { component, state } from '@neuralfog/elemix/decorators';
|
|
132
|
+
|
|
133
|
+
@component()
|
|
134
|
+
export class UserProfile extends Component {
|
|
135
|
+
@state()
|
|
136
|
+
state = { name: 'John', email: 'john@example.com', active: true };
|
|
137
|
+
|
|
138
|
+
template(): Template {
|
|
139
|
+
const { name, email, active } = this.state;
|
|
140
|
+
|
|
141
|
+
return html`<div>
|
|
142
|
+
<p>${name}</p>
|
|
143
|
+
<p>${email}</p>
|
|
144
|
+
<p>${active ? 'Online' : 'Offline'}</p>
|
|
145
|
+
</div>`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Events
|
|
151
|
+
|
|
152
|
+
Use the `@` prefix to bind native DOM events directly in templates.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
@component()
|
|
156
|
+
export class Counter extends Component {
|
|
157
|
+
@state()
|
|
158
|
+
state = { count: 0 };
|
|
159
|
+
|
|
160
|
+
template(): Template {
|
|
161
|
+
return html`<div>
|
|
162
|
+
<p>${this.state.count}</p>
|
|
163
|
+
<button @click=${() => this.state.count++}>Increment</button>
|
|
164
|
+
<input @input=${(e: Event) => console.log((e.target as HTMLInputElement).value)} />
|
|
165
|
+
</div>`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Model Binding
|
|
171
|
+
|
|
172
|
+
Use the `~model` prefix for two-way binding on input elements. The bound value must be an object with a `value` property.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
@component()
|
|
176
|
+
export class SearchBox extends Component {
|
|
177
|
+
@state()
|
|
178
|
+
state = { query: { value: '' } };
|
|
179
|
+
|
|
180
|
+
template(): Template {
|
|
181
|
+
const { query } = this.state;
|
|
182
|
+
|
|
183
|
+
return html`<div>
|
|
184
|
+
<input ~model=${query} />
|
|
185
|
+
<p>${query.value}</p>
|
|
186
|
+
</div>`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Ref
|
|
192
|
+
|
|
193
|
+
The `ref` helper creates a `{ value }` wrapper. Use `:ref` to capture a DOM element reference, or pass it to `~model` for two-way binding.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { Component, html, type Template } from '@neuralfog/elemix';
|
|
197
|
+
import { component, state } from '@neuralfog/elemix/decorators';
|
|
198
|
+
import { ref } from '@neuralfog/elemix/utilities';
|
|
199
|
+
|
|
200
|
+
@component()
|
|
201
|
+
export class Form extends Component {
|
|
202
|
+
@state()
|
|
203
|
+
input = ref('');
|
|
204
|
+
heading = ref<HTMLHeadingElement>();
|
|
205
|
+
|
|
206
|
+
template(): Template {
|
|
207
|
+
return html`<div>
|
|
208
|
+
<h1 :ref=${this.heading}>Title</h1>
|
|
209
|
+
<input ~model=${this.input} />
|
|
210
|
+
<p>${this.input.value}</p>
|
|
211
|
+
</div>`;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Signals
|
|
217
|
+
|
|
218
|
+
Signals are reactive stores shared across components. Define a signal as a standalone module and subscribe components via the `@component` decorator.
|
|
219
|
+
|
|
220
|
+
### Definition
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { signal } from '@neuralfog/elemix/signal';
|
|
224
|
+
|
|
225
|
+
export const counter = signal({
|
|
226
|
+
count: 0,
|
|
227
|
+
label: 'Clicks',
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Usage
|
|
232
|
+
|
|
233
|
+
Subscribe to a signal by passing it to the `signals` array. Access its state via `signal.value` and mutate it directly to trigger re-renders in all subscribed components.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { Component, html, type Template } from '@neuralfog/elemix';
|
|
237
|
+
import { component } from '@neuralfog/elemix/decorators';
|
|
238
|
+
|
|
239
|
+
import { counter } from '../signals/counter';
|
|
240
|
+
|
|
241
|
+
@component({ signals: [counter] })
|
|
242
|
+
export class CounterDisplay extends Component {
|
|
243
|
+
template(): Template {
|
|
244
|
+
const { count, label } = counter.value;
|
|
245
|
+
|
|
246
|
+
return html`<div>
|
|
247
|
+
<p>${label}: ${count}</p>
|
|
248
|
+
<button @click=${() => counter.value.count++}>Increment</button>
|
|
249
|
+
</div>`;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Lifecycle Hooks
|
|
255
|
+
|
|
256
|
+
Components support four lifecycle hooks: `beforeMount`, `onMount`, `onRender`, and `onDispose`.
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
@component()
|
|
260
|
+
export class Dashboard extends Component {
|
|
261
|
+
beforeMount(): void {
|
|
262
|
+
// Called before initialization
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
onMount(): void {
|
|
266
|
+
// Called after first render
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
onRender(renderTriggers?: string[]): void {
|
|
270
|
+
// Called after each render with triggers that caused the update
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
onDispose(): void {
|
|
274
|
+
// Called when component is removed from DOM
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
template(): Template {
|
|
278
|
+
return html`<div>Dashboard</div>`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Conditionals
|
|
284
|
+
|
|
285
|
+
Use ternary expressions in templates.
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
html`${isActive ? html`<p>Active</p>` : html`<p>Inactive</p>`}`;
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Repeat
|
|
292
|
+
|
|
293
|
+
Use the `repeat` directive to render lists. Pass an optional key function for efficient diffing.
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import { repeat } from '@neuralfog/elemix/directives';
|
|
297
|
+
|
|
298
|
+
@component()
|
|
299
|
+
export class UserList extends Component {
|
|
300
|
+
@state()
|
|
301
|
+
state = {
|
|
302
|
+
users: [
|
|
303
|
+
{ id: '1', name: 'Alice' },
|
|
304
|
+
{ id: '2', name: 'Bob' },
|
|
305
|
+
],
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
template(): Template {
|
|
309
|
+
const { users } = this.state;
|
|
310
|
+
|
|
311
|
+
return html`<ul>
|
|
312
|
+
${repeat(
|
|
313
|
+
users,
|
|
314
|
+
(user) => html`<li>${user.name}</li>`,
|
|
315
|
+
(user) => user.id,
|
|
316
|
+
)}
|
|
317
|
+
</ul>`;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Direct Property Assignment
|
|
323
|
+
|
|
324
|
+
Use the `.` prefix to set properties directly on HTML elements.
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
html`<input .value=${'Hello'} />`;
|
|
328
|
+
|
|
329
|
+
html`<div .textContent=${'Updated text'} />`;
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Dynamic Classes
|
|
333
|
+
|
|
334
|
+
Use the `.class` prefix to bind classes dynamically. Accepts a string or an object mapping class names to booleans.
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
html`<div .class=${'active highlight'}>String</div>`;
|
|
338
|
+
|
|
339
|
+
html`<div .class=${{ active: isActive, disabled: isDisabled }}>Object</div>`;
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Bind Attributes
|
|
343
|
+
|
|
344
|
+
Use `.bind-attrs` to dynamically set multiple attributes from an object.
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
html`<div .bind-attrs=${{ 'data-id': '123', 'aria-label': 'Card' }}>Content</div>`;
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## Bind Events
|
|
351
|
+
|
|
352
|
+
Use `.bind-events` to dynamically attach multiple event handlers from an object.
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
html`<div .bind-events=${{ click: onClick, input: onInput }}>Content</div>`;
|
|
356
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=class e{static config={};static mergeConfigs(t){e.config={...e.config,...t}}},t=t=>{e.mergeConfigs(t),e.config.entryPoint?.()};Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return e}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=class{renderTrigger;subscribers=new Set;proxy;proxySet=new WeakSet;get value(){return this.proxy}constructor(e,t){this.renderTrigger=t,this.proxy=this.create(e)}subscribe(e){return this.subscribers.has(e)||this.subscribers.add(e),this}unsubscribe(e){return this.subscribers.delete(e),this}create(e){let t=this;return new Proxy(e,{get(e,r){let i=e[r];if(n(i),typeof i==`object`&&i&&!t.proxySet.has(i)){let e=new Proxy(i,this);return t.proxySet.add(e),e}return i},set(e,r,i){return e[r]=i,n(e),t.notify(),!0}})}notify(){for(let e of this.subscribers)e.render(this.renderTrigger)}},t=`Reactive state does not support collections: Map, WeakMap, Set, WeakSet`,n=e=>{if(e instanceof Map||e instanceof WeakMap||e instanceof Set||e instanceof WeakSet)throw Error(t)};Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return e}});
|
package/dist/app.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./App-tMVVu8H5.js");exports.App=e.t,exports.initApp=e.n;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return e}});
|
package/dist/decorators.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./utilities-BN8G-efH.js");var n=(e,t)=>{customElements.get(e)===void 0&&customElements.define(e,t)},r=e=>r=>{let i=t.t(r.name),a=class extends r{constructor(){if(super(),e?.signals?.length)for(let t of e.signals)t.subscribe(this)}};r.$signals=e?.signals||[],r.$styles=e?.styles||[],n(i,a)},i=t=>(n,r)=>{n.stateProperties||=new Map,n.stateProperties.has(r)||n.stateProperties.set(r,t||e.t.LOCAL_STATE)};exports.component=r,exports.state=i;
|
package/dist/directives.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { repeat
|
|
2
|
-
export { repeat
|
|
1
|
+
import { repeat } from '@neuralfog/elemix-renderer/directives';
|
|
2
|
+
export { repeat };
|
package/dist/directives.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=require("./chunk-NGjzN6Tu.js").t((e=>{Object.defineProperty(e,Symbol.toStringTag,{value:`Module`}),e.repeat=(e,t,n)=>e.map((e,r)=>{let i=t(e,r);return i.key=n?.(e,r)||String(r),i})}))();exports.repeat=e.repeat;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./renderers-DuXHBLlK.js"),n=require("./Reactive-BR9C38bG.js"),r=require("./App-tMVVu8H5.js");let i=require("@neuralfog/elemix-renderer");var a=class{component;locked=!1;scheduledRenderTriggers=new Set;constructor(e){this.component=e}schedule(e,n=!1){this.component.template()&&(e&&this.scheduledRenderTriggers.add(e),this.locked||(this.locked=!0,t.t.add(this),setTimeout(()=>{this.render(Array.from(this.scheduledRenderTriggers)),this.scheduledRenderTriggers.clear(),this.locked=!1,t.t.delete(this),n&&this.component.onMount()},0)))}render(e){(0,i.render)(this.component.template(),this.component.root),this.component.onRender(e)}},o=class{component;constructor(e){this.component=e}initialize(){let e=this.component.constructor.prototype.stateProperties;if(e)for(let[t,r]of e){let e=this.component;e[t]=new n.t(e[t],r).subscribe(this.component).value}}},s=class{component;data={};constructor(e){this.component=e}initialize(){this.data=new n.t(this.data,e.t.PROPS).subscribe(this.component).value}setReactive(e,t){this.data[e]=t}set(e,t){if(typeof t==`object`&&t){this.setReactive(e,t);return}let n=this.data[e];if(typeof t==`function`){this.data[e]||this.setReactive(e,t);return}n!==t&&this.setReactive(e,t)}},c=class{component;styles;constructor(e){this.component=e,this.styles=this.component.constructor.$styles}initialize(){if(this.component.shadowRoot&&this.styles.length){let e=new CSSStyleSheet;e.replaceSync(this.styles.join(` `));let t=r.t.config.baseStyles||[];this.component.shadowRoot.adoptedStyleSheets=[...t,e,...this.component.controlStyles]}}},l=class extends HTMLElement{$props=new s(this);$renderer=new a(this);$localState=new o(this);$styles=new c(this);$controlStyles;get root(){return this.shadowRoot}get props(){return this.$props.data}get styles(){return this.$styles}get controlStyles(){return this.$controlStyles||[]}constructor(){super(),this.attachShadow({mode:`open`})}connectedCallback(){this.beforeMount(),this.$styles.initialize(),this.$props.initialize(),this.$localState.initialize(),this.render(e.t.ON_MOUNT,!0)}disconnectedCallback(){t.t.delete(this.$renderer),this.unsubscribeFromSignals(),this.onDispose()}template(){}onRender(e){}beforeMount(){}onMount(){}onDispose(){}render(e,t=!1){this.$renderer.schedule(e,t)}setControlStyles(e){this.$controlStyles=e}unsubscribeFromSignals(){for(let e of this.constructor.$signals)e.unsubscribe(this)}};exports.Component=l,exports.RenderTrigger=e.t,exports.html=e.n;
|
package/dist/reactive.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./Reactive-BR9C38bG.js");exports.Reactive=e.t,exports.UNSUPPORTED_COLLECTION_ERROR_MESSAGE=e.n;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=new Set;Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return e}});
|
package/dist/signal.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./Reactive-BR9C38bG.js");var n=(n,r)=>new t.t(n,r||e.t.SIGNAL);exports.signal=n;
|
package/dist/src/Reactive.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Component } from './component/Component';
|
|
|
2
2
|
import type { RenderTriggerType } from './types';
|
|
3
3
|
export declare class Reactive<State> {
|
|
4
4
|
private renderTrigger?;
|
|
5
|
-
subscribers: Set<Component<unknown
|
|
5
|
+
subscribers: Set<Component<unknown>>;
|
|
6
6
|
private proxy;
|
|
7
7
|
private proxySet;
|
|
8
8
|
get value(): State;
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { type RenderTriggerType, type Template } from '../types';
|
|
2
2
|
import { Styles } from './Styles';
|
|
3
|
-
export declare class Component<ComponentProps = unknown
|
|
3
|
+
export declare class Component<ComponentProps = unknown> extends HTMLElement {
|
|
4
4
|
private $props;
|
|
5
|
-
private $emits;
|
|
6
5
|
private $renderer;
|
|
7
6
|
private $localState;
|
|
8
7
|
private $styles;
|
|
9
8
|
private $controlStyles?;
|
|
10
9
|
get root(): HTMLElement | ShadowRoot | null;
|
|
11
10
|
get props(): ComponentProps;
|
|
12
|
-
get emits(): ComponentEmits;
|
|
13
11
|
get styles(): Styles;
|
|
14
12
|
get controlStyles(): CSSStyleSheet[];
|
|
15
13
|
constructor();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import '../fixtures/renderer/ConditionalRendering
|
|
1
|
+
import '../fixtures/renderer/ConditionalRendering';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import '../fixtures/renderer/MultilpleRootNodes
|
|
1
|
+
import '../fixtures/renderer/MultilpleRootNodes';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=require("@neuralfog/elemix-renderer").html,t={PROPS:`PROPS`,SIGNAL:`SIGNAL`,LOCAL_STATE:`LOCAL_STATE`,ON_MOUNT:`ON_MOUNT`};Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return t}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("./renderers-DuXHBLlK.js");var t=(e=void 0)=>({value:e}),n=()=>Math.floor(performance.now()*1e3).toString(36)+Math.random().toString(36).slice(2,6);function r(){return new Promise(t=>{let n=()=>{e.t.size===0?t(!1):setTimeout(n,0)};n()})}var i=e=>(e.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|[0-9]*$)|[A-Z]?[a-z]+|[A-Z]|[0-9]+/g)||[]).map(e=>e.toLowerCase()).join(`-`),a=e=>{let t=new CSSStyleSheet;return t.replaceSync(e),t};Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
|
package/dist/utilities.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./chunk-NGjzN6Tu.js"),t=require("./utilities-BN8G-efH.js");var n=e.t((e=>{var t={EVENT:0,PROP:1,MODEL:2,STD:3,REF:4,BIND_ATTRS:5,BIND_EVENTS:6,DIRECT_CLASS:7},n=RegExp(`₥(\\d+)`),r=e=>{let t=e.match(n);if(!t)throw Error(`Unable to extract index from hole comment`);return Number(t[1])},i=e=>`<!--₥${e}-->`,a=e=>e.replace(/(\S+)=((<!--[\s\S]*?-->)|([^\s">]+))/g,`$1="$2"`),o=e=>e.replace(/([A-Z])/g,e=>`-${e.toLowerCase()}`),s=(e,t)=>{let n=new Set,r=``,i=e=>{let t=e.split(` `);for(let e=0;e<t.length;e++){let i=t[e];i&&!n.has(i)&&(n.add(i),r.length&&(r+=` `),r+=i)}};return i(e),i(t),r};Object.defineProperty(e,"a",{enumerable:!0,get:function(){return s}}),Object.defineProperty(e,"i",{enumerable:!0,get:function(){return i}}),Object.defineProperty(e,"n",{enumerable:!0,get:function(){return a}}),Object.defineProperty(e,"o",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"r",{enumerable:!0,get:function(){return r}}),Object.defineProperty(e,"t",{enumerable:!0,get:function(){return o}})})),r=e.t((e=>{Object.defineProperty(e,Symbol.toStringTag,{value:`Module`}),e.mergeClasses=n().a}))();exports.camelToKebabCase=t.t,exports.fastUID=t.n,exports.makeCssStylesheet=t.r,Object.defineProperty(exports,"mergeClasses",{enumerable:!0,get:function(){return r.mergeClasses}}),exports.ref=t.i,exports.render=t.a;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neuralfog/elemix",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "brownhounds",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,20 +26,21 @@
|
|
|
26
26
|
"test-nc": "vitest run",
|
|
27
27
|
"test-ui": "npx vitest --api.host 0.0.0.0 --ui",
|
|
28
28
|
"lint": "tsc --noEmit && biome format && biome lint",
|
|
29
|
+
"lint:fix": "biome format --write && biome lint --fix",
|
|
29
30
|
"release": "npm run clean && npm run build && npm publish --access public"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@neuralfog/biome-config": "0.1.2",
|
|
33
|
-
"@neuralfog/elemix-testing": "0.
|
|
34
|
-
"@neuralfog/ts-config": "0.1.
|
|
35
|
-
"@vitest/coverage-v8": "
|
|
36
|
-
"@vitest/ui": "
|
|
37
|
-
"jsdom": "
|
|
38
|
-
"typescript": "
|
|
39
|
-
"vite": "
|
|
40
|
-
"vitest": "
|
|
34
|
+
"@neuralfog/elemix-testing": "0.2.0",
|
|
35
|
+
"@neuralfog/ts-config": "0.1.2",
|
|
36
|
+
"@vitest/coverage-v8": "4.1.7",
|
|
37
|
+
"@vitest/ui": "4.1.7",
|
|
38
|
+
"jsdom": "29.1.1",
|
|
39
|
+
"typescript": "6.0.3",
|
|
40
|
+
"vite": "8.0.14",
|
|
41
|
+
"vitest": "4.1.7"
|
|
41
42
|
},
|
|
42
43
|
"peerDependencies": {
|
|
43
|
-
"@neuralfog/elemix-renderer": "0.
|
|
44
|
+
"@neuralfog/elemix-renderer": "0.3.0"
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const e=new Set;exports.activeRenderers=e;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Component } from '../../../src/component/Component';
|
|
2
|
-
import { type Template } from '../../../src/types';
|
|
3
|
-
import './SelfClosed';
|
|
4
|
-
export declare enum State {
|
|
5
|
-
SINGLE = 0,
|
|
6
|
-
START = 1,
|
|
7
|
-
END = 2,
|
|
8
|
-
MIDDLE = 3
|
|
9
|
-
}
|
|
10
|
-
export declare class SelfClosingTags extends Component {
|
|
11
|
-
state: {
|
|
12
|
-
case: State;
|
|
13
|
-
};
|
|
14
|
-
partial: () => Template;
|
|
15
|
-
template: () => Template;
|
|
16
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import '../fixtures/renderer/SelfClosingTags';
|
package/dist/types-D5TcFW7H.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const e=require("@neuralfog/elemix-renderer"),r=e.html,t={PROPS:"PROPS",SIGNAL:"SIGNAL",LOCAL_STATE:"LOCAL_STATE",ON_MOUNT:"ON_MOUNT"};exports.RenderTrigger=t;exports.html=r;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const r=require("./renderers-CTogHRY2.js"),s=(e=void 0)=>({value:e}),n=()=>Math.floor(performance.now()*1e3).toString(36)+Math.random().toString(36).slice(2,6);function o(){return new Promise(e=>{const t=()=>{r.activeRenderers.size===0?e(!1):setTimeout(t,0)};t()})}const a=e=>(e.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|[0-9]*$)|[A-Z]?[a-z]+|[A-Z]|[0-9]+/g)||[]).map(t=>t.toLowerCase()).join("-"),c=e=>{const t=new CSSStyleSheet;return t.replaceSync(e),t};exports.camelToKebabCase=a;exports.fastUID=n;exports.makeCssStylesheet=c;exports.ref=s;exports.render=o;
|