@neuralfog/elemix 0.2.2 → 0.3.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 +34 -4
- package/dist/Reactive-CQV_s8zX.js +1 -0
- package/dist/decorators.js +1 -1
- package/dist/index.js +1 -1
- package/dist/reactive.js +1 -1
- package/dist/renderers-BBOJdSjj.js +1 -0
- package/dist/signal.js +1 -1
- package/dist/src/component/Component.d.ts +10 -0
- package/dist/src/decorators/component.d.ts +0 -2
- package/dist/src/renderers.d.ts +11 -0
- package/dist/{utilities-BN8G-efH.js → utilities-COO_YT_a.js} +1 -1
- package/dist/utilities.js +1 -1
- package/package.json +3 -5
- package/dist/Reactive-BR9C38bG.js +0 -1
- package/dist/renderers-DuXHBLlK.js +0 -1
package/README.md
CHANGED
|
@@ -61,6 +61,18 @@ export class HelloWorld extends Component {
|
|
|
61
61
|
}
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
## Cloak
|
|
65
|
+
|
|
66
|
+
Every component is created with a `data-cloak` attribute that is removed automatically once the first render completes. Use it to prevent flash of unrendered content — hide components in global CSS until they're ready:
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
[data-cloak] {
|
|
70
|
+
visibility: hidden;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Once the component mounts and finishes its first render, `data-cloak` is dropped and the element becomes visible.
|
|
75
|
+
|
|
64
76
|
## Rendering
|
|
65
77
|
|
|
66
78
|
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.
|
|
@@ -81,6 +93,22 @@ export class UserCard extends Component {
|
|
|
81
93
|
}
|
|
82
94
|
```
|
|
83
95
|
|
|
96
|
+
## Self-Closing Tags
|
|
97
|
+
|
|
98
|
+
Custom elements and other non-void HTML elements can be written in self-closing form. The renderer expands `<my-tag />` to `<my-tag></my-tag>` before parsing, so you can drop the redundant closing tag whenever the element has no children.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
template(): Template {
|
|
102
|
+
return html`
|
|
103
|
+
<pf-icon-search />
|
|
104
|
+
<pf-divider />
|
|
105
|
+
<pf-card data-variant="primary" />
|
|
106
|
+
`;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Void HTML elements (`br`, `hr`, `img`, `input`, `link`, `meta`, etc.) are left alone — they're already self-closing per the HTML spec.
|
|
111
|
+
|
|
84
112
|
## Props
|
|
85
113
|
|
|
86
114
|
Primitive props are shallow-diffed and only trigger updates when the value changes. Object props are passed through reactively. Functions are assigned once.
|
|
@@ -215,7 +243,11 @@ export class Form extends Component {
|
|
|
215
243
|
|
|
216
244
|
## Signals
|
|
217
245
|
|
|
218
|
-
Signals are reactive stores shared across components.
|
|
246
|
+
Signals are reactive stores shared across components. Read a signal's value inside a component's `template()` and the component re-renders whenever that signal changes — **no manual subscription needed**.
|
|
247
|
+
|
|
248
|
+
Subscription is fully automatic: while `template()` runs, every `signal.value.x` access tells the framework "this component depends on this signal." After the render, the component is subscribed to every signal it actually read. On the next render, stale subscriptions are dropped and current ones re-tracked, so conditional reads stay correct and nothing leaks. When the component leaves the DOM, all of its signal subscriptions are cleaned up automatically.
|
|
249
|
+
|
|
250
|
+
You don't register signals anywhere. You just read them.
|
|
219
251
|
|
|
220
252
|
### Definition
|
|
221
253
|
|
|
@@ -230,15 +262,13 @@ export const counter = signal({
|
|
|
230
262
|
|
|
231
263
|
### Usage
|
|
232
264
|
|
|
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
265
|
```typescript
|
|
236
266
|
import { Component, html, type Template } from '@neuralfog/elemix';
|
|
237
267
|
import { component } from '@neuralfog/elemix/decorators';
|
|
238
268
|
|
|
239
269
|
import { counter } from '../signals/counter';
|
|
240
270
|
|
|
241
|
-
@component(
|
|
271
|
+
@component()
|
|
242
272
|
export class CounterDisplay extends Component {
|
|
243
273
|
template(): Template {
|
|
244
274
|
const { count, label } = counter.value;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("./renderers-BBOJdSjj.js");var t=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(t){let n=this;return new Proxy(t,{get(t,i){let a=t[i];r(a);let o=e.n.active;if(o&&(n.subscribers.add(o),o.tracked.add(n)),typeof a==`object`&&a&&!n.proxySet.has(a)){let e=new Proxy(a,this);return n.proxySet.add(e),e}return a},set(e,t,i){return e[t]=i,r(e),n.notify(),!0}})}notify(){for(let e of this.subscribers)e.render(this.renderTrigger)}},n=`Reactive state does not support collections: Map, WeakMap, Set, WeakSet`,r=e=>{if(e instanceof Map||e instanceof WeakMap||e instanceof Set||e instanceof WeakSet)throw Error(n)};Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return t}});
|
package/dist/decorators.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./utilities-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./utilities-COO_YT_a.js");var n=(e,t)=>{customElements.get(e)===void 0&&customElements.define(e,t)},r=e=>r=>{let i=t.t(r.name);r.$styles=e?.styles||[],n(i,r)},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/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./renderers-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./renderers-BBOJdSjj.js"),n=require("./Reactive-CQV_s8zX.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){let r=t.n.active;t.n.active=null;let i;try{i=this.component.template()}finally{t.n.active=r}i&&(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(),this.component.removeAttribute(`data-cloak`))},0)))}render(e){for(let e of this.component.tracked)e.unsubscribe(this.component);this.component.tracked.clear();let n=t.n.active;t.n.active=this.component;try{(0,i.render)(this.component.template(),this.component.root)}finally{t.n.active=n}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;tracked=new Set;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`}),this.setAttribute(`data-cloak`,``)}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.tracked)e.unsubscribe(this);this.tracked.clear()}hasSlot(e){return Array.from(this.children).some(t=>t.getAttribute(`slot`)===e)}};exports.Component=l,exports.RenderTrigger=e.t,exports.html=e.n;
|
package/dist/reactive.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./Reactive-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./Reactive-CQV_s8zX.js");exports.Reactive=e.t,exports.UNSUPPORTED_COLLECTION_ERROR_MESSAGE=e.n;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=new Set,t={active:null};Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return e}});
|
package/dist/signal.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./Reactive-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types-v1ChTfwQ.js"),t=require("./Reactive-CQV_s8zX.js");var n=(n,r)=>new t.t(n,r||e.t.SIGNAL);exports.signal=n;
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { type RenderTriggerType, type Template } from '../types';
|
|
2
2
|
import { Styles } from './Styles';
|
|
3
|
+
type Trackable = {
|
|
4
|
+
unsubscribe(c: Component): unknown;
|
|
5
|
+
};
|
|
3
6
|
export declare class Component<ComponentProps = unknown> extends HTMLElement {
|
|
4
7
|
private $props;
|
|
5
8
|
private $renderer;
|
|
6
9
|
private $localState;
|
|
7
10
|
private $styles;
|
|
8
11
|
private $controlStyles?;
|
|
12
|
+
/**
|
|
13
|
+
* Signals auto-subscribed during template() execution via the
|
|
14
|
+
* renderTracking mechanism. Cleared and rebuilt on every render so
|
|
15
|
+
* conditional reads correctly add and remove subscriptions.
|
|
16
|
+
*/
|
|
17
|
+
tracked: Set<Trackable>;
|
|
9
18
|
get root(): HTMLElement | ShadowRoot | null;
|
|
10
19
|
get props(): ComponentProps;
|
|
11
20
|
get styles(): Styles;
|
|
@@ -23,3 +32,4 @@ export declare class Component<ComponentProps = unknown> extends HTMLElement {
|
|
|
23
32
|
private unsubscribeFromSignals;
|
|
24
33
|
hasSlot(name: string): boolean;
|
|
25
34
|
}
|
|
35
|
+
export {};
|
package/dist/src/renderers.d.ts
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
import type { Renderer } from './component/Renderer';
|
|
2
|
+
import type { Component } from './component/Component';
|
|
2
3
|
export declare const activeRenderers: Set<Renderer>;
|
|
4
|
+
/**
|
|
5
|
+
* Tracks which component is currently executing template() so that
|
|
6
|
+
* Reactive proxies can auto-subscribe the component when its template
|
|
7
|
+
* reads a signal value.
|
|
8
|
+
*
|
|
9
|
+
* Held inside an object so cross-module mutation is observable.
|
|
10
|
+
*/
|
|
11
|
+
export declare const renderTracking: {
|
|
12
|
+
active: Component | null;
|
|
13
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require("./renderers-
|
|
1
|
+
const e=require("./renderers-BBOJdSjj.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
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./chunk-NGjzN6Tu.js"),t=require("./utilities-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./chunk-NGjzN6Tu.js"),t=require("./utilities-COO_YT_a.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=new Set([`area`,`base`,`br`,`col`,`embed`,`hr`,`img`,`input`,`link`,`meta`,`source`,`track`,`wbr`]),s=/<([a-zA-Z][a-zA-Z0-9-]*)([^>]*?)\s*\/>/g,c=e=>e.replace(s,(e,t,n)=>o.has(t.toLowerCase())?e:`<${t}${n}></${t}>`),l=e=>e.replace(/([A-Z])/g,e=>`-${e.toLowerCase()}`),u=(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 i}}),Object.defineProperty(e,"i",{enumerable:!0,get:function(){return r}}),Object.defineProperty(e,"n",{enumerable:!0,get:function(){return a}}),Object.defineProperty(e,"o",{enumerable:!0,get:function(){return u}}),Object.defineProperty(e,"r",{enumerable:!0,get:function(){return c}}),Object.defineProperty(e,"s",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"t",{enumerable:!0,get:function(){return l}})})),r=e.t((e=>{Object.defineProperty(e,Symbol.toStringTag,{value:`Module`}),e.mergeClasses=n().o}))();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,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neuralfog/elemix",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "brownhounds",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"files": [
|
|
9
|
-
"./dist/**/*"
|
|
10
|
-
],
|
|
8
|
+
"files": ["./dist/**/*"],
|
|
11
9
|
"exports": {
|
|
12
10
|
".": "./dist/index.js",
|
|
13
11
|
"./decorators": "./dist/decorators.js",
|
|
@@ -45,6 +43,6 @@
|
|
|
45
43
|
"vitest": "4.1.7"
|
|
46
44
|
},
|
|
47
45
|
"peerDependencies": {
|
|
48
|
-
"@neuralfog/elemix-renderer": "0.
|
|
46
|
+
"@neuralfog/elemix-renderer": "0.4.0"
|
|
49
47
|
}
|
|
50
48
|
}
|
|
@@ -1 +0,0 @@
|
|
|
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}});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=new Set;Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return e}});
|