mono-jsx 0.8.2 → 0.9.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 +22 -11
- package/jsx-runtime.mjs +2 -2
- package/package.json +1 -1
- package/types/jsx.d.ts +2 -2
- package/types/mono.d.ts +2 -2
package/README.md
CHANGED
|
@@ -559,11 +559,11 @@ function Counter(
|
|
|
559
559
|
You can define app signals by adding the `app` prop to the root `<html>` element. The app signals are available in all components via `this.app.<SignalName>`. Changes to the app signals will trigger re-renders in all components that use them:
|
|
560
560
|
|
|
561
561
|
```tsx
|
|
562
|
-
interface
|
|
562
|
+
interface IAppSignals {
|
|
563
563
|
themeColor: string;
|
|
564
564
|
}
|
|
565
565
|
|
|
566
|
-
function Header(this:
|
|
566
|
+
function Header(this: WithAppSignals<FC, IAppSignals>) {
|
|
567
567
|
return (
|
|
568
568
|
<header>
|
|
569
569
|
<h1 style={{ color: this.app.themeColor }}>Welcome to mono-jsx!</h1>
|
|
@@ -571,7 +571,7 @@ function Header(this: App<FC, AppSignals>) {
|
|
|
571
571
|
)
|
|
572
572
|
}
|
|
573
573
|
|
|
574
|
-
function Footer(this:
|
|
574
|
+
function Footer(this: WithAppSignals<FC, IAppSignals>) {
|
|
575
575
|
return (
|
|
576
576
|
<footer>
|
|
577
577
|
<p style={{ color: this.app.themeColor }}>(c) 2025 mono-jsx.</p>
|
|
@@ -579,7 +579,7 @@ function Footer(this: App<FC, AppSignals>) {
|
|
|
579
579
|
)
|
|
580
580
|
}
|
|
581
581
|
|
|
582
|
-
function Main(this:
|
|
582
|
+
function Main(this: WithAppSignals<FC, IAppSignals>) {
|
|
583
583
|
return (
|
|
584
584
|
<main>
|
|
585
585
|
<p>
|
|
@@ -879,20 +879,31 @@ The `this` object has the following built-in properties:
|
|
|
879
879
|
- `request`: The request object from the `fetch` handler.
|
|
880
880
|
- `session`: The session storage.
|
|
881
881
|
- `refs`: A map of refs defined in the component.
|
|
882
|
-
- `computed`: A method to create a computed signal.
|
|
883
|
-
-
|
|
882
|
+
- `computed(fn)`: A method to create a computed signal.
|
|
883
|
+
- `$(fn)`: A shortcut for `computed(fn)`.
|
|
884
|
+
- `effect(fn)`: A method to create side effects.
|
|
884
885
|
|
|
885
886
|
```ts
|
|
886
|
-
type FC<Signals = {}, Refs = {}
|
|
887
|
+
type FC<Signals = {}, Refs = {}> = {
|
|
887
888
|
readonly app: AppSignals & { refs: AppRefs; url: WithParams<URL> }
|
|
888
889
|
readonly context: Context;
|
|
889
890
|
readonly request: WithParams<Request>;
|
|
890
891
|
readonly session: Session;
|
|
891
892
|
readonly refs: Refs;
|
|
892
893
|
readonly computed: <T = unknown>(fn: () => T) => T;
|
|
893
|
-
readonly $: FC["computed"];
|
|
894
|
+
readonly $: FC["computed"]; // A shortcut for `FC.computed`.
|
|
894
895
|
readonly effect: (fn: () => void | (() => void)) => void;
|
|
895
896
|
} & Signals;
|
|
897
|
+
|
|
898
|
+
// define `AppSignals` type
|
|
899
|
+
function Component(this: WithAppSignals<FC, { title: string }>) {
|
|
900
|
+
this.app.title // type: 'string'
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// define `Context` type
|
|
904
|
+
function Component(this: WithContext<FC, { secret: string }>) {
|
|
905
|
+
this.context.secret // type: 'string'
|
|
906
|
+
}
|
|
896
907
|
```
|
|
897
908
|
|
|
898
909
|
### Using Signals
|
|
@@ -904,7 +915,7 @@ See the [Using Signals](#using-signals) section for more details on how to use s
|
|
|
904
915
|
You can use `this.refs` to access refs in your components. Refs are defined using the `ref` attribute in JSX, and they allow you to access DOM elements directly. The `refs` object is a map of ref names to DOM elements.
|
|
905
916
|
|
|
906
917
|
```tsx
|
|
907
|
-
function App(this:
|
|
918
|
+
function App(this: WithRefs<FC, { input?: HTMLInputElement }>) {
|
|
908
919
|
this.effect(() => {
|
|
909
920
|
this.refs.input?.addEventListener("input", (evt) => {
|
|
910
921
|
console.log("Input changed:", evt.target.value);
|
|
@@ -946,7 +957,7 @@ The `<component>` element also supports the `ref` attribute, which allows you to
|
|
|
946
957
|
```tsx
|
|
947
958
|
import type { ComponentElement } from "mono-jsx";
|
|
948
959
|
|
|
949
|
-
function App(this:
|
|
960
|
+
function App(this: WithRefs<FC, { component: ComponentElement }>) {
|
|
950
961
|
this.effect(() => {
|
|
951
962
|
// updating the component name and props will trigger a re-render of the component
|
|
952
963
|
this.refs.component.name = "Foo";
|
|
@@ -971,7 +982,7 @@ function App(this: Refs<FC, { component: ComponentElement }>) {
|
|
|
971
982
|
You can use the `context` property in `this` to access context values in your components. The context is defined on the root `<html>` element:
|
|
972
983
|
|
|
973
984
|
```tsx
|
|
974
|
-
function Dash(this:
|
|
985
|
+
function Dash(this: WithContext<FC, { auth: { uuid: string; name: string } }>) {
|
|
975
986
|
const { auth } = this.context;
|
|
976
987
|
return (
|
|
977
988
|
<div>
|
package/jsx-runtime.mjs
CHANGED
|
@@ -26,7 +26,7 @@ var STYLE_JS = `{var f=/^(-|f[lo].*[^se]$|g.{5,}[^ps]$|z|o[pr]|(W.{5})?[lL]i.*(t
|
|
|
26
26
|
var RENDER_ATTR_JS = `{var s=(l,n,r)=>{let e=l.parentElement;return e.tagName==="M-GROUP"&&(e=e.previousElementSibling),()=>{let t=r();n==="value"?e.value=String(t):n==="checked"?e.checked=!!t:typeof t=="boolean"?e.toggleAttribute(n,t):t==null?e.removeAttribute(n):typeof t=="object"?n==="class"?e.setAttribute(n,$cx(t)):n==="style"?$applyStyle(e,t):e.setAttribute(n,JSON.stringify(t)):e.setAttribute(n,String(t))}};window.$renderAttr=s;}`;
|
|
27
27
|
var RENDER_TOGGLE_JS = `{var i=(e,s)=>{let t,l=()=>e.replaceChildren(...s()?t:[]);return()=>{if(!t){let n=e.firstElementChild;n&&n.tagName==="TEMPLATE"&&n.hasAttribute("m-slot")?t=[...n.content.childNodes]:t=[...e.childNodes]}e.hasAttribute("vt")&&document.startViewTransition?document.startViewTransition(l):l()}};window.$renderToggle=i;}`;
|
|
28
28
|
var RENDER_SWITCH_JS = `{var a=(l,u)=>{let s,r=l.getAttribute("value"),t,i,o=e=>t.get(e)??t.set(e,[]).get(e),d=()=>l.replaceChildren(...t.has(s)?t.get(s):i);return()=>{if(!t){t=new Map,i=[];for(let e of l.childNodes)if(e.nodeType===1&&e.tagName==="TEMPLATE"&&e.hasAttribute("m-slot")){for(let n of e.content.childNodes)n.nodeType===1&&n.hasAttribute("slot")?o(n.getAttribute("slot")).push(n):i.push(n);e.remove()}else r?o(r).push(e):i.push(e)}s=""+u(),l.hasAttribute("vt")&&document.startViewTransition?document.startViewTransition(d):d()}};window.$renderSwitch=a;}`;
|
|
29
|
-
var SIGNALS_JS = `{let h;const
|
|
29
|
+
var SIGNALS_JS = `{let h;const a=window,b=document,y=new Map,E=new Map,k=new Map,v=new Map,$=new Map,m=new Map,l=n=>y.get(n)??y.set(n,V(n)).get(n),F=()=>Object.create(null),p=(n,e)=>n.getAttribute(e),V=n=>{const e=F(),t=(o,c)=>{e[o]=c},s=new Map,r=(o,c)=>{let u=s.get(o);return u||(u=new Set,s.set(o,u)),u.add(c),()=>{u.delete(c),u.size===0&&s.delete(o)}},i=new Proxy(F(),{get:(o,c)=>b.querySelector("[data-ref='"+n+":"+c+"']")});return new Proxy(e,{get:(o,c,u)=>{switch(c){case"$init":return t;case"$watch":return r;case"app":return l(0);case"refs":return i;default:return h?.(n,c),Reflect.get(o,c,u)}},set:(o,c,u,g)=>{if(u!==Reflect.get(o,c,g)){const f=s.get(c);return f&&queueMicrotask(()=>f.forEach(d=>d())),Reflect.set(o,c,u,g)}return!1}})},M=(n,e,t)=>{switch(e){case"toggle":return $renderToggle(n,t);case"switch":return $renderSwitch(n,t);case"html":return()=>n.innerHTML=""+t()}if(e&&e.length>2&&e.startsWith("[")&&e.endsWith("]"))return $renderAttr(n,e.slice(1,-1),t);const s=n.parentElement,r=()=>n.textContent=""+t();if(b.startViewTransition&&s.hasAttribute("data-vt")){const i=s.getAttribute("data-vt");return i&&(s.style.viewTransitionName=i),()=>b.startViewTransition(r)}return r},S=n=>{const e=n.indexOf(":");return e>0?[Number(n.slice(0,e)),n.slice(e+1)]:null},q=(n,e,t,s)=>{const r=n.get(t);if(r!==void 0){s(r);return}const i=e.get(t);i?i.push(s):e.set(t,[s])},N=(n,e)=>{const t=a.$fmap?.get(n);if(t){e(t);return}const s=m.get(n);s?s.push(e):m.set(n,[e])};if(typeof a.$F=="function"){const n=a.$F;a.$F=(e,t)=>{n(e,t);const s=m.get(e);s&&(m.delete(e),s.forEach(r=>r(t)))}}const T=n=>typeof n=="function"&&n(),A=(n,e)=>customElements.define(n,class extends HTMLElement{disposes=[];connectedCallback(){e(this)}disconnectedCallback(){this.disposes.forEach(t=>t()),this.disposes.length=0}});A("m-signal",n=>{const e=Number(p(n,"scope")),t=l(e),s=p(n,"key");if(s)n.disposes.push(t.$watch(s,M(n,p(n,"mode"),()=>t[s])));else{const r=Number(p(n,"computed")),i=e+":"+r;q(E,v,i,o=>{N(r,c=>{const u=M(n,p(n,"mode"),c.bind(t));o.forEach(g=>{const[f,d]=S(g);n.disposes.push(l(f).$watch(d,u))})})})}}),A("m-effect",n=>{const{disposes:e}=n,t=Number(p(n,"scope"));q(k,$,t,s=>{const r=s.length,i=new Array(r);e.push(()=>{i.forEach(T),i.length=0});for(let o=0;o<r;o++)N(s[o],c=>{const u=[],g=l(t),f=()=>{T(i[o]),i[o]=c.call(g)};h=(d,w)=>u.push([d,w]),f(),h=void 0;for(const[d,w]of u)e.push(l(d).$watch(w,f))})})}),a.$S=(n,e)=>{const[t,s]=S(n);l(t).$init(s,e)},a.$C=(n,e,t)=>{const s=n+":"+e;E.set(s,t);const r=v.get(s);r&&(v.delete(s),r.forEach(i=>i(t)))},a.$E=(n,...e)=>{k.set(n,e);const t=$.get(n);t&&($.delete(n),t.forEach(s=>s(e)))},a.$patch=(n,...e)=>{for(const[t,...s]of e){let r=s.pop(),i=n;for(const o of s)i=i[o];i[r]=t}return n},a.$signals=n=>n!==void 0?l(n):void 0;}`;
|
|
30
30
|
var SUSPENSE_JS = `{const i=new Map,o=e=>e.getAttribute("chunk-id"),l=(e,t)=>customElements.define(e,class extends HTMLElement{connectedCallback(){t(this)}});l("m-portal",e=>{i.set(o(e),e)}),l("m-chunk",e=>{setTimeout(()=>{const t=o(e),n=i.get(t),s=e.firstChild?.content.childNodes;n&&(e.hasAttribute("next")?s&&n.before(...s):(e.hasAttribute("done")?n.remove():s&&n.replaceWith(...s),i.delete(t)),e.remove())})});}`;
|
|
31
31
|
var COMPONENT_JS = `{const e=document,a=(t,s)=>t.getAttribute(s);customElements.define("m-component",class extends HTMLElement{static observedAttributes=["name","props"];#t;#s;#r;#h;#i;#e=new Map;#a=!0;async#l(){if(!this.#t){this.#n("");return}const t=this.#s||"{}",s=this.#t+t,i={"x-component":this.#t,"x-props":t,"x-flags":$FLAGS},n=new AbortController;if(this.#h?.abort(),this.#h=n,this.#e.has(s)){this.#n(this.#e.get(s));return}this.#r?.length&&this.#n(this.#r);const r=await fetch(location.href,{headers:i,signal:n.signal});if(!r.ok)throw this.#n(""),new Error("Failed to fetch component '"+this.#t+"'");const[h,o]=await r.json();this.#e.set(s,h),this.#n(h),o&&(e.body.appendChild(e.createElement("script")).textContent=o)}#n(t){const s=()=>typeof t=="string"?this.innerHTML=t:this.replaceChildren(...t);this.hasAttribute("vt")&&e.startViewTransition&&!this.#a?e.startViewTransition(s):s(),this.#a=!1}get name(){return this.#t??null}set name(t){t&&t!==this.#t&&(this.#t=t,this.#o())}get props(){return this.#s?JSON.parse(this.#s):void 0}set props(t){const s=typeof t=="string"?t:JSON.stringify(t);s&&s!==this.#s&&(this.#s=s,this.#o())}attributeChangedCallback(t,s,i){this.#t&&i&&(t==="name"?this.name=i:t==="props"&&(this.props=i))}connectedCallback(){setTimeout(()=>{if(!this.#r){const t=a(this,"props");this.#t=a(this,"name"),this.#s=t?.startsWith("base64,")?atob(t.slice(7)):void 0,this.#r=[...this.childNodes]}this.#l()})}disconnectedCallback(){this.#e.clear(),this.#h?.abort(),this.#h=void 0,this.#i&&clearTimeout(this.#i),this.#i=void 0}#o(){this.#i&&clearTimeout(this.#i),this.#i=setTimeout(()=>{this.#i=void 0,this.#l()},50)}refresh(){this.#t&&this.#e.delete(this.#t+(this.#s||"{}")),this.#o()}});}`;
|
|
32
32
|
var ROUTER_JS = `{const n=document,a=location,o=t=>t.split("#",1)[0],l=t=>o(t)===o(a.href);customElements.define("m-router",class extends HTMLElement{#t;#s;#i;#n;#e=new Map;#r=!0;async#c(t){const s=new AbortController,i={"x-route":"true","x-flags":$FLAGS};this.#n?.abort(),this.#n=s;const e=await fetch(t,{headers:i,signal:s.signal});if(e.status===404)return null;if(!e.ok)throw this.replaceChildren(),new Error("Failed to fetch route: "+e.status+" "+e.statusText);return e.json()}#a(t){const s=()=>typeof t=="string"?this.innerHTML=t:this.replaceChildren(...t);this.hasAttribute("vt")&&n.startViewTransition&&!this.#r?n.startViewTransition(s):s(),this.#r=!1}#o(){n.querySelectorAll("nav a").forEach(t=>{const{href:s,classList:i}=t,e=t.closest("nav")?.getAttribute("data-active-class")??"active";l(s)?i.add(e):i.remove(e)})}async#l(t,s){const i=this.#c(t).then(e=>{if(e){const[r,c]=e;return this.#e.set(t,r),this.#a(r),c}else this.#e.delete(t),this.#a(this.#t??[]),typeof $signals<"u"&&($signals(0).url=new URL(t))});this.#e.has(t)?this.#a(this.#e.get(t)):await i,history[s?.replace?"replaceState":"pushState"]({},"",t),this.#o(),window.scrollTo(0,0),i.then(e=>{e&&(n.body.appendChild(n.createElement("script")).textContent=e)})}navigate(t,s){const i=new URL(t,a.href);if(i.origin!==a.origin){a.href=t;return}l(i.href)||this.#l(t,s)}connectedCallback(){setTimeout(()=>{if(!this.#t)if(this.hasAttribute("fallback"))this.removeAttribute("fallback"),this.#t=[...this.childNodes];else{this.#t=[];for(const t of this.childNodes)if(t.nodeType===1&&t.tagName==="TEMPLATE"&&t.hasAttribute("m-fallback")){this.#t.push(...t.content.childNodes),t.remove();break}}}),this.#s=t=>{if(t.defaultPrevented||t.altKey||t.ctrlKey||t.metaKey||t.shiftKey||!(t.target instanceof HTMLAnchorElement))return;const{download:s,href:i,rel:e,target:r}=t.target;s||e==="external"||r==="_blank"||!i.startsWith(a.origin)||(t.preventDefault(),this.navigate(i))},this.#i=()=>this.#l(a.href),addEventListener("popstate",this.#i),n.addEventListener("click",this.#s),setTimeout(()=>this.#o()),globalThis.$router=this}disconnectedCallback(){removeEventListener("popstate",this.#i),n.removeEventListener("click",this.#s),delete globalThis.$router,this.#n?.abort(),this.#n=void 0,this.#e.clear(),this.#s=void 0,this.#i=void 0}});}`;
|
|
@@ -176,7 +176,7 @@ var $vnode = Symbol.for("jsx.vnode");
|
|
|
176
176
|
var $setup = Symbol.for("mono.setup");
|
|
177
177
|
|
|
178
178
|
// version.ts
|
|
179
|
-
var VERSION = "0.8.
|
|
179
|
+
var VERSION = "0.8.2";
|
|
180
180
|
|
|
181
181
|
// render.ts
|
|
182
182
|
var FunctionIdGenerator = class extends Map {
|
package/package.json
CHANGED
package/types/jsx.d.ts
CHANGED
|
@@ -106,12 +106,12 @@ declare global {
|
|
|
106
106
|
effect(fn: () => (() => void) | void): void;
|
|
107
107
|
}
|
|
108
108
|
& FCExtension<FC>
|
|
109
|
-
& Omit<Omit<Signals, "
|
|
109
|
+
& Omit<Omit<Signals, "refs" | "init" | "computed" | "$" | "effect">, keyof FCExtension>;
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
112
|
* Defines the `this.refs` type.
|
|
113
113
|
*/
|
|
114
|
-
type
|
|
114
|
+
type WithRefs<T, R extends {}> = T extends FC<infer S> ? FC<S, R> : never;
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
117
|
* The JSX namespace object.
|
package/types/mono.d.ts
CHANGED
|
@@ -279,7 +279,7 @@ declare global {
|
|
|
279
279
|
/**
|
|
280
280
|
* Defines the `this.app` type.
|
|
281
281
|
*/
|
|
282
|
-
type
|
|
282
|
+
type WithAppSignals<T, AppSignals = {}, AppRefs = Record<string, HTMLElement>> = T extends FC<infer S, infer R> ? FC<S, R> & {
|
|
283
283
|
/**
|
|
284
284
|
* The global signals shared across the application.
|
|
285
285
|
*/
|
|
@@ -302,7 +302,7 @@ declare global {
|
|
|
302
302
|
/**
|
|
303
303
|
* Defines the `this.context` type.
|
|
304
304
|
*/
|
|
305
|
-
type
|
|
305
|
+
type WithContext<T, Context = {}> = T extends FC<infer S, infer R> ? FC<S, R> & {
|
|
306
306
|
/**
|
|
307
307
|
* The rendering context object.
|
|
308
308
|
*
|