sinho 0.1.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/.github/workflows/ci.yml +24 -0
- package/.github/workflows/deploy-docs.yml +47 -0
- package/.prettierrc +3 -0
- package/LICENSE.md +21 -0
- package/README.md +33 -0
- package/ci/check-size.js +8 -0
- package/dist/array_mutation.d.ts +16 -0
- package/dist/array_mutation.js +75 -0
- package/dist/array_mutation.js.map +1 -0
- package/dist/bundle.d.ts +1126 -0
- package/dist/bundle.js +1074 -0
- package/dist/bundle.min.js +1 -0
- package/dist/component.d.ts +253 -0
- package/dist/component.js +256 -0
- package/dist/component.js.map +1 -0
- package/dist/context.d.ts +21 -0
- package/dist/context.js +34 -0
- package/dist/context.js.map +1 -0
- package/dist/create_element.d.ts +43 -0
- package/dist/create_element.js +43 -0
- package/dist/create_element.js.map +1 -0
- package/dist/dom.d.ts +602 -0
- package/dist/dom.js +97 -0
- package/dist/dom.js.map +1 -0
- package/dist/intrinsic/ClassComponent.d.ts +2 -0
- package/dist/intrinsic/ClassComponent.js +10 -0
- package/dist/intrinsic/ClassComponent.js.map +1 -0
- package/dist/intrinsic/Dynamic.d.ts +33 -0
- package/dist/intrinsic/Dynamic.js +53 -0
- package/dist/intrinsic/Dynamic.js.map +1 -0
- package/dist/intrinsic/ErrorBoundary.d.ts +14 -0
- package/dist/intrinsic/ErrorBoundary.js +36 -0
- package/dist/intrinsic/ErrorBoundary.js.map +1 -0
- package/dist/intrinsic/For.d.ts +10 -0
- package/dist/intrinsic/For.js +81 -0
- package/dist/intrinsic/For.js.map +1 -0
- package/dist/intrinsic/Fragment.d.ts +23 -0
- package/dist/intrinsic/Fragment.js +28 -0
- package/dist/intrinsic/Fragment.js.map +1 -0
- package/dist/intrinsic/If.d.ts +24 -0
- package/dist/intrinsic/If.js +47 -0
- package/dist/intrinsic/If.js.map +1 -0
- package/dist/intrinsic/Portal.d.ts +6 -0
- package/dist/intrinsic/Portal.js +15 -0
- package/dist/intrinsic/Portal.js.map +1 -0
- package/dist/intrinsic/Style.d.ts +7 -0
- package/dist/intrinsic/Style.js +70 -0
- package/dist/intrinsic/Style.js.map +1 -0
- package/dist/intrinsic/TagComponent.d.ts +4 -0
- package/dist/intrinsic/TagComponent.js +67 -0
- package/dist/intrinsic/TagComponent.js.map +1 -0
- package/dist/intrinsic/Text.d.ts +6 -0
- package/dist/intrinsic/Text.js +16 -0
- package/dist/intrinsic/Text.js.map +1 -0
- package/dist/intrinsic/mod.d.ts +5 -0
- package/dist/intrinsic/mod.js +6 -0
- package/dist/intrinsic/mod.js.map +1 -0
- package/dist/jsx-runtime/mod.d.ts +23 -0
- package/dist/jsx-runtime/mod.js +11 -0
- package/dist/jsx-runtime/mod.js.map +1 -0
- package/dist/mod.d.ts +8 -0
- package/dist/mod.js +7 -0
- package/dist/mod.js.map +1 -0
- package/dist/renderer.d.ts +13 -0
- package/dist/renderer.js +25 -0
- package/dist/renderer.js.map +1 -0
- package/dist/scope.d.ts +138 -0
- package/dist/scope.js +228 -0
- package/dist/scope.js.map +1 -0
- package/dist/template.d.ts +10 -0
- package/dist/template.js +7 -0
- package/dist/template.js.map +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +13 -0
- package/dist/utils.js.map +1 -0
- package/package.json +71 -0
- package/src/array_mutation.ts +118 -0
- package/src/component.ts +624 -0
- package/src/context.ts +70 -0
- package/src/create_element.ts +89 -0
- package/src/dom.ts +819 -0
- package/src/intrinsic/ClassComponent.ts +17 -0
- package/src/intrinsic/For.ts +122 -0
- package/src/intrinsic/Fragment.ts +38 -0
- package/src/intrinsic/If.ts +73 -0
- package/src/intrinsic/Portal.ts +25 -0
- package/src/intrinsic/Style.ts +120 -0
- package/src/intrinsic/TagComponent.ts +102 -0
- package/src/intrinsic/Text.ts +24 -0
- package/src/intrinsic/mod.ts +5 -0
- package/src/jsx-runtime/mod.ts +41 -0
- package/src/mod.ts +37 -0
- package/src/renderer.ts +45 -0
- package/src/scope.ts +404 -0
- package/src/template.ts +16 -0
- package/src/utils.ts +29 -0
- package/terser.config.json +16 -0
- package/tsconfig.json +18 -0
- package/web/README.md +41 -0
- package/web/babel.config.js +3 -0
- package/web/dist/shingo.min.d.ts +1131 -0
- package/web/dist/shingo.min.js +1 -0
- package/web/docusaurus.config.ts +151 -0
- package/web/package-lock.json +14850 -0
- package/web/package.json +54 -0
- package/web/sidebars.ts +31 -0
- package/web/src/components/monacoEditor.tsx +72 -0
- package/web/src/components/playground.tsx +89 -0
- package/web/src/components/playgroundComponent.tsx +168 -0
- package/web/src/css/custom.css +37 -0
- package/web/src/pages/index.module.css +31 -0
- package/web/src/pages/index.tsx +73 -0
- package/web/src/pages/playground.tsx +64 -0
- package/web/static/.nojekyll +0 -0
- package/web/static/dist/bundle.d.ts +1126 -0
- package/web/static/dist/bundle.min.js +1 -0
- package/web/tsconfig.json +8 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=t=>({t:t,o:[],i:[],l:{...t?.l},u(t){const n=o;o=this;try{return t()}finally{o=n}},h(){for(let t=this.i.length-1;t>=0;t--)this.i[t].h();this.i=[];for(let t=this.o.length-1;t>=0;t--){const n=this.o[t];n._?.(),n.p.forEach((t=>t.o.delete(n))),n.p.clear()}this.o=[]}});let n,e,o=t(),s=!1;const r=()=>o,c=(t,o)=>{const r=()=>(!s&&n&&(n.p.add(r),r.o.add(n)),r.peek());r.o=new Set,r.peek=()=>t;const c=(n,s)=>{if(s={...o,...s},e){const o="function"==typeof n?n(r.peek()):n;(s?.force||o!==r.peek())&&(s?.force?t=o:e.m.push((()=>t=o)),s?.silent||r.o.forEach((t=>e.o.add(t))))}else i((()=>c(n,s)))};return[r,c]},i=t=>{const n=e;e={m:[],o:new Set};try{const n=t();for(;e.m.length>0||e.o.size>0;){const t=e.o;e.o=new Set,t.forEach((t=>t._?.())),e.m.forEach((t=>t())),e.m=[],t.forEach((t=>t.u()))}return n}finally{e=n}},l=(t,e)=>{const r=!!e,c={v:o,p:new Set,u(){const o=n,c=s;n=this;try{e?this.p.size||e.forEach((t=>t())):(this.p.forEach((t=>t.o.delete(this))),this.p.clear()),s=r,this._?.();const n=this.v.u((()=>i(t)));this._=n?()=>{this.v.u((()=>i(n))),this._=null}:null}finally{n=o,s=c}}};c.p.forEach((t=>t.o.add(c))),o.o.push(c),c.u(),c.p.size||c._||o.o.pop()},u=(t,n)=>{const[e,o]=c();let s=!0;return l((()=>{o(t,s?{...n,force:!0}:n),s=!1})),e},f=(n,e)=>{const s=o,r=t(s);Object.assign(r.l,e?.details),s.i.push(r);return[r.u(n),()=>{const t=s.i.indexOf(r);t>=0&&s.i.splice(t,1),r.h()}]},a=(t,n)=>{const[e,o]=c(t,n);return e.set=o,e},d={upgrade:t=>()=>d.get(t),get:t=>"function"==typeof t?t():t,peek(t){const n=s;s=!0;try{return this.get(t)}finally{s=n}}},h=(t={})=>({S:[],M(t){return this.k?.next().value??t()},...t}),_=()=>{const t=r();return t.l.C??=h()},p=(t,n)=>{const e=_(),o=h({...e,...t}),[s,r]=f(n,{details:{C:o}});return l((()=>r)),s},m=t=>(t[0]??"").toLowerCase()+t.slice(1).replace(/[A-Z]/g,(t=>"-"+t.toLowerCase())),y=t=>t.startsWith("on:")?t.slice(3):m(t.slice(2)),w=Symbol(),b=(t,n)=>({[w]:Math.random().toString(36).slice(2),N:t,j:n}),g=t=>!!t?.[w],v=(t,n,e)=>{n.addEventListener(t[w],(t=>{const n=d.get(e);void 0!==n&&(t.stopPropagation(),t.detail(n))}))},x=t=>{const n=_();return u((()=>{let e=t.N;return n.H?.dispatchEvent(new CustomEvent(t[w],{detail:t=>e=t,bubbles:!0,composed:!0})),e}))},S=(t,n)=>({L:"p",T:t,...n}),M=(t=CustomEvent)=>({L:"e",A:t}),k=Symbol();let C;const E=(t,n)=>{C?C.push([t,n]):l(t,n)},N=(t,n={},e={})=>{const o=[],s=new Map;for(const t in n){const e=n[t];if("p"==e.L&&e.attribute){"function"==typeof e.attribute&&(e.attribute={transform:e.attribute});const n=e.attribute={name:m(t),static:!1,transform:t=>t,...e.attribute};s.set(n.name,{name:t,meta:e}),n.static||o.push(n.name)}}e.shadow??={mode:"open"};class i extends HTMLElement{static[k]={O:t};static observedAttributes=o;props={};events={};[k]={};constructor(){super();for(const t in n){const e=n[t];if("p"==e.L){const n=g(e.T)?e.T:null,[o,s]=c(n?void 0:e.T);this.props[t]=o,n&&v(n,this,o),Object.defineProperty(this,t,{get:o.peek,set:t=>s((()=>t),{force:!0})})}else if("e"==e.L&&t.startsWith("on")){const n=y(t);this.events[t]=t=>this.dispatchEvent(new e.A(n,t))}}}connectedCallback(){const t=(n=this,e.shadow?n.shadowRoot??n.attachShadow(e.shadow):n);var n;this[k].D=f((()=>p({I:!1,H:this,k:t.childNodes.values()},(()=>{this[k].v=r();const n=C;C=[];try{t?.append(...this.render().build()),C.forEach((([t,n])=>l(t,n)))}finally{C=n}}))))[1]}disconnectedCallback(){this[k].D?.()}attributeChangedCallback(t,n,e){const o=s.get(t);o&&(this[o.name]=null!=e?o.meta.attribute.transform.call(this,e):g(o.meta.T)?void 0:o.meta.T)}}return i},j=t=>!!t?.[k],H=(...t)=>{const[n,e]="string"==typeof t[0]?[t[0],t.slice(1)]:["",t];for(const t of e)customElements.define(n+t[k].O,t)},L=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,T=(t,n,e)=>{"-"==n[0]?t.style.setProperty(n,""+e):t.style[n]=null==e?"":"number"!=typeof e||L.test(n)?""+e:e+"px"},A=(t,n,e,o)=>{const s=null==e||!1===e&&!n.includes("-");if(n.startsWith("prop:"))t[n]=e;else if(n.startsWith("attr:"))s?t.removeAttribute(n):t.setAttribute(n,e);else if(!["innerHTML","outerHTML"].includes(n)){if(!["tabIndex","role",...o?["width","height","href","list","form","download","rowSpan","colSpan"]:[]].includes(n)&&n in t)try{return void(t[n]=e??"")}catch(t){}"function"==typeof e||(s?t.removeAttribute(n):t.setAttribute(n,e))}},O=t=>({build(){const n=t();return n.build?.()??n}}),D=({text:t,marker:n})=>O((()=>{const e=_(),o=n&&e.M((()=>document.createComment(""))),s=e.M((()=>document.createTextNode("")));return l((()=>{const n=""+(d.get(t)??"");s.textContent!=n&&(s.textContent=n)})),o?[o,s]:[s]})),I=({children:t})=>O((()=>Array.isArray(t)?t.flatMap((t=>I({children:t}).build())):null==t?[]:"object"==typeof t?t:D({text:t}))),$=(t,n,e,o)=>{const{ref:s,style:c,children:u,dangerouslySetInnerHTML:f,...a}=e;for(const n in c??{}){const e=c[n];l((()=>{T(t,n,d.get(e))}))}for(const n in a){const e=a[n];if(n.startsWith("on")){const o=r(),s=t=>{o.u((()=>i((()=>e(t)))))},c=y(n);l((()=>(t.addEventListener(c,s),()=>t.removeEventListener(c,s))))}else l((()=>{A(t,n,d.get(e),o)}))}return f&&l((()=>{const n=d.get(f).__html;t.innerHTML!=n&&(t.innerHTML=n)})),s&&l((()=>(s.set(t),()=>s.set(void 0)))),null!=e.children&&t.append(...p({I:n,k:t.childNodes.values()},(()=>I({children:e.children}).build()))),t},z=(t,n={},e)=>(null!=e&&(n.children=e),j(t)?((t,n)=>O((()=>{const e=_().M((()=>new t));return customElements.upgrade(e),$(e,!1,n),[e]})))(t,n):"function"==typeof t?O((()=>t(n))):((t,n={})=>O((()=>{const e=_(),o="svg"==t||!!e.I;return[$(e.M((()=>o?document.createElementNS("http://www.w3.org/2000/svg",t):document.createElement(t))),o,n,!0)]})))(t,n)),P=new Proxy(z,{get:(t,n)=>(e,o)=>t(n,e,o)}),V=(t,n)=>{const[e,o]=c({$:[],P:new Map});let s=new Map;return l((()=>{const e=[],r=s,c=((t,n)=>{const e=new Map;for(let o=0;o<t.length;o++){const s=n(t[o],o);if(e.has(s))throw Error(`Duplicate key '${s}'`);e.set(s,o)}return e})(t(),n),i=(t=NaN)=>e.map((t=>"r"==t.V?n=>n<t.Z?n:n==t.Z?NaN:n-1:"a"==t.V?n=>n<t.Z?n:n+1:"m"==t.V?n=>t.q<=n&&n<t.B?n+1:n==t.B?t.q:n:t=>t)).reduce(((t,n)=>n(t)),t);for(const t of r.keys()){const n=i(r.get(t));c.has(t)||e.push({V:"r",F:t,Z:n})}for(let o=0;o<t().length;o++){const s=n(t()[o],o),c=i(r.get(s));isNaN(c)?e.push({V:"a",F:s,Z:o}):c!=o&&e.push({V:"m",F:s,B:c,q:o})}e.length>0&&o({$:e,P:c}),s=c})),e},Z=t=>O((()=>{const n=_(),e=d.upgrade(t.each??[]),o=n.M((()=>document.createComment(""))),s=t.key??((t,n)=>n),r=[o],i=new Map,u=V(e,s),a=t=>{for(let n=t-1;n>=0;n--){const n=s(e()[t-1],t-1),o=i.get(n)?.G??[];if(o.length>0)return o[o.length-1]}return o};return l((()=>{for(const n of u().$)if("r"==n.V){const{G:t=[],D:e}=i.get(n.F)??{};e?.();const o=r.indexOf(t[0]);o>0&&r.splice(o,t.length),t.forEach((t=>t.parentNode?.removeChild(t))),i.delete(n.F)}else if("a"==n.V){let o=[];const[,s]=f((()=>{const[s,i]=c(n.Z),[f,d]=c(e()[n.Z]);l((()=>{0<=s()&&s()<e().length&&d((()=>e()[s()]))})),l((()=>{const t=u().P.get(n.F);null!=t&&i(t)})),o=t.children?.(f,s,e).build()??[];const h=a(n.Z),_=r.indexOf(h);_>=0&&r.splice(_+1,0,...o),o.forEach((t=>h.parentNode?.insertBefore(t,h.nextSibling)))}));i.set(n.F,{G:o,D:s})}else if("m"==n.V){const{G:t=[]}=i.get(n.F)??{},e=r.indexOf(t[0]);e>=0&&r.splice(e,t.length);const o=a(n.q),s=r.indexOf(o);s>=0&&r.splice(s+1,0,...t),t.forEach((t=>o.parentNode?.insertBefore(t,o.nextSibling)))}}),[u]),r})),q=t=>(_().S=[],B({condition:t.condition,children:t.children})),B=t=>{const n=_(),e=n.S,o=u((()=>e.every((t=>!t()))&&d.get(t.condition)));return n.S=[...e,o],p({S:[]},(()=>O((()=>{const e=n.M((()=>document.createComment(""))),s=[e],r=u((()=>o()?I({children:t.children}):null));let c=[];return l((()=>{c.forEach((t=>t.parentNode?.removeChild(t))),s.length=1;const[,t]=f((()=>{c=r()?.build()??[],e.after(...c),s.push(...c)}));return t}),[r]),s}))))},F=({children:t})=>B({condition:!0,children:t}),G=({mount:t,children:n})=>O((()=>p({k:void 0},(()=>{const e=I({children:n}).build();return l((()=>(e.forEach((n=>t.appendChild(n))),()=>{e.forEach((t=>t.parentNode?.removeChild(t)))}))),[]})))),J=Symbol(),K=new Map,Q=t=>{const n=t.children;if("function"==typeof n){const e=z("style",{},D({text:n,marker:!1}));return t.light?G({mount:document.head,children:e}):e}if(n){const o=_(),s=t.light?document:o.H?.shadowRoot??document,r=((t,n,e)=>{if(!K.has(n)){const t=new CSSStyleSheet;t.replaceSync(n),K.set(n,{J:t,K:0})}const o=K.get(n);o.K++,t.has(n)||t.set(n,{J:o.J,K:0});const s=t.get(n);return s.K++,l((()=>()=>{--s.K||(t.delete(n),e()),--o.K||K.delete(n)})),s.J})((e=s,e[J]??=new Map),n,(()=>{s.adoptedStyleSheets=s.adoptedStyleSheets.filter((t=>t!=r))}));s.adoptedStyleSheets.push(r)}var e;return I({})},R=(t,...n)=>{const e=()=>t.reduce(((t,e,o)=>t+e+(d.get(n[o])??"")),"");return n.some((t=>"function"==typeof t))?e:e()},U=(t,n,e)=>(n&&null!=e&&(n.key=e),z(t,n));export{N as Component,F as Else,B as ElseIf,Z as For,I as Fragment,q as If,d as MaybeSignal,G as Portal,Q as Style,b as createContext,z as createElement,R as css,H as defineComponents,M as event,P as h,j as isComponent,U as jsx,U as jsxDEV,U as jsxs,S as prop,i as useBatch,x as useContext,E as useEffect,u as useMemo,a as useRef,c as useSignal};
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { Cleanup, MaybeSignal, Signal } from "./scope.js";
|
|
2
|
+
import type { DomEventProps, DomProps } from "./dom.js";
|
|
3
|
+
import { JsxPropNameToEventName } from "./utils.js";
|
|
4
|
+
import { useScope } from "./scope.js";
|
|
5
|
+
import { Context } from "./context.js";
|
|
6
|
+
import { Template } from "./template.js";
|
|
7
|
+
interface Tagged<in out T> {
|
|
8
|
+
_tag: T;
|
|
9
|
+
}
|
|
10
|
+
type OmitNever<T> = Omit<T, {
|
|
11
|
+
[K in keyof T]: T[K] extends never ? K : never;
|
|
12
|
+
}[keyof T]>;
|
|
13
|
+
type PartialRequire<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
14
|
+
/** @ignore */
|
|
15
|
+
export interface PropMeta<T> extends PropOptions<T>, Tagged<"p"> {
|
|
16
|
+
_type?: [T];
|
|
17
|
+
_defaultOrContext: T;
|
|
18
|
+
}
|
|
19
|
+
export interface AttributeOptions<T> {
|
|
20
|
+
/**
|
|
21
|
+
* The name of the attribute to observe.
|
|
22
|
+
*
|
|
23
|
+
* Defaults to the kebab-case version of the prop.
|
|
24
|
+
*/
|
|
25
|
+
name?: string;
|
|
26
|
+
/**
|
|
27
|
+
* A function to transform the attribute value to the prop value.
|
|
28
|
+
*/
|
|
29
|
+
transform: (value: string) => T;
|
|
30
|
+
/**
|
|
31
|
+
* Set to `true` to not observe the attribute for changes.
|
|
32
|
+
*
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
static?: boolean;
|
|
36
|
+
}
|
|
37
|
+
type PartialPartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
38
|
+
export interface PropOptions<T> {
|
|
39
|
+
attribute?: ((value: string) => T) | (string extends T ? PartialPartial<AttributeOptions<T>, "transform"> : AttributeOptions<T>);
|
|
40
|
+
}
|
|
41
|
+
type Props<M> = OmitNever<{
|
|
42
|
+
readonly [K in keyof M]: M[K] extends PropMeta<infer T> ? Signal<T> : never;
|
|
43
|
+
}>;
|
|
44
|
+
export type EventConstructor<T = any, E = Event> = new (name: string, arg: T) => E;
|
|
45
|
+
/** @ignore */
|
|
46
|
+
export interface EventMeta<out E extends EventConstructor> extends Tagged<"e"> {
|
|
47
|
+
_event: E;
|
|
48
|
+
}
|
|
49
|
+
type Events<M> = OmitNever<Omit<{
|
|
50
|
+
readonly [K in keyof M]: K extends `on${string}` ? M[K] extends EventMeta<infer E> ? E : never : never;
|
|
51
|
+
}, `on${Lowercase<keyof HTMLElementEventMap>}`>>;
|
|
52
|
+
type GeneralJsxProps<T> = Partial<OmitNever<{
|
|
53
|
+
[K in keyof T]: K extends typeof jsxPropsSym | keyof DomProps<any> | `on${string}` | `${Uppercase<infer _>}${string}` | "accessKeyLabel" | "offsetHeight" | "offsetLeft" | "offsetParent" | "offsetTop" | "offsetWidth" | "attributes" | "classList" | "clientHeight" | "clientLeft" | "clientTop" | "clientWidth" | "localName" | "namespaceURI" | "ownerDocument" | "part" | "prefix" | "scrollHeight" | "scrollWidth" | "shadowRoot" | "tagName" | "baseURI" | "childNodes" | "firstChild" | "isConnected" | "lastChild" | "nextSibling" | "nodeName" | "nodeType" | "parentElement" | "parentNode" | "previousSibling" | "nextElementSibling" | "previousElementSibling" | "childElementCount" | "firstElementChild" | "lastElementChild" | "assignedSlot" | "attributeStyleMap" | "isContentEditable" | "dataset" ? never : T[K] extends Function ? never : MaybeSignal<T[K]>;
|
|
54
|
+
}>> & DomProps<any> & DomEventProps<never> & Record<string, any>;
|
|
55
|
+
export type JsxProps<T extends HTMLElement> = typeof jsxPropsSym extends keyof T ? NonNullable<T[typeof jsxPropsSym]> : any;
|
|
56
|
+
type ComponentJsxProps<M> = Partial<OmitNever<{
|
|
57
|
+
[K in keyof Props<M>]: Props<M>[K] extends Signal<infer T> ? MaybeSignal<T> : never;
|
|
58
|
+
}> & {
|
|
59
|
+
[K in keyof Events<M>]: (evt: InstanceType<Events<M>[K]>) => void;
|
|
60
|
+
}> & GeneralJsxProps<HTMLElement>;
|
|
61
|
+
type EventEmitters<M> = OmitNever<Omit<{
|
|
62
|
+
[K in keyof Events<M>]: Events<M>[K] extends EventConstructor<infer E> ? undefined extends E ? (arg?: E) => boolean : (arg: E) => boolean : never;
|
|
63
|
+
}, `on${Lowercase<keyof HTMLElementEventMap>}`>>;
|
|
64
|
+
/**
|
|
65
|
+
* Defines a property in your component metadata that can be set from outside
|
|
66
|
+
* of the component.
|
|
67
|
+
*
|
|
68
|
+
* Make sure to avoid conflicts with native `HTMLElement` properties.
|
|
69
|
+
*
|
|
70
|
+
* You can get properties by accessing the {@link Signal} in `this.props`.
|
|
71
|
+
* It's also possible to set the properties directly on the component instance.
|
|
72
|
+
*
|
|
73
|
+
* It's also possible to define an attribute for the property by setting the
|
|
74
|
+
* `attribute` option. By default, the attribute name is the kebab-case version
|
|
75
|
+
* of the property name. The attribute will be observed and the signal updated
|
|
76
|
+
* on changes. You can also provide a custom name and a transform function to
|
|
77
|
+
* convert the attribute value to the property value.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```tsx
|
|
81
|
+
* class App extends Component("x-app", {
|
|
82
|
+
* greetingMessage: prop<string>("Hello, world!", {
|
|
83
|
+
* attribute: {
|
|
84
|
+
* name: "greeting",
|
|
85
|
+
* }
|
|
86
|
+
* }),
|
|
87
|
+
* }) {
|
|
88
|
+
* render() {
|
|
89
|
+
* return <h1>{this.props.greetingMessage}</h1>;
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
*
|
|
93
|
+
* defineComponents(App);
|
|
94
|
+
*
|
|
95
|
+
* const app = new App();
|
|
96
|
+
* app.greetingMessage = "Hello, universe!";
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare const prop: (<T>(context: Context<T>, opts?: PropOptions<T>) => PropMeta<T | undefined>) & (<T>(defaultValue: T, opts?: PropOptions<T>) => PropMeta<T>) & (<T>(defaultValue?: T, opts?: PropOptions<T | undefined>) => PropMeta<T | undefined>);
|
|
100
|
+
type _CustomEventContructor<T> = undefined extends T ? typeof CustomEvent<T> : EventConstructor<PartialRequire<CustomEventInit<T>, "detail">, CustomEvent<T>>;
|
|
101
|
+
/**
|
|
102
|
+
* Defines an event in your component metadata that can be dispatched by
|
|
103
|
+
* the component.
|
|
104
|
+
*
|
|
105
|
+
* Make sure your event name starts with `on` and to avoid conflicts with
|
|
106
|
+
* native `HTMLElement` events. The event name will be converted to kebab-case.
|
|
107
|
+
*
|
|
108
|
+
* You can dispatch events either using `HTMLElement.dispatchEvent` or by
|
|
109
|
+
* calling the event emitter function in `this.events` inside the `render`
|
|
110
|
+
* function of a component.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```tsx
|
|
114
|
+
* class App extends Component("x-app", {
|
|
115
|
+
* onSomethingHappen: event<string>(),
|
|
116
|
+
* // Event name will be `something-happen`
|
|
117
|
+
* }) {
|
|
118
|
+
* render() {
|
|
119
|
+
* // …
|
|
120
|
+
* this.events.onSomethingHappen({ detail: "Something happened! "});
|
|
121
|
+
* }
|
|
122
|
+
* }
|
|
123
|
+
*
|
|
124
|
+
* const app = new App();
|
|
125
|
+
* app.addEventListener("something-happen", (evt) => {
|
|
126
|
+
* // `evt` is `CustomEvent<string>`
|
|
127
|
+
* console.log(evt.detail);
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* You can also provide a custom event constructor:
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```tsx
|
|
135
|
+
* class App extends Component("x-app", {
|
|
136
|
+
* onSomethingClick: event(() => MouseEvent),
|
|
137
|
+
* }) {
|
|
138
|
+
* render() {
|
|
139
|
+
* return (
|
|
140
|
+
* <button onclick={evt => this.events.onSomethingClick(evt)}>
|
|
141
|
+
* Click me!
|
|
142
|
+
* </button>
|
|
143
|
+
* );
|
|
144
|
+
* }
|
|
145
|
+
* }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export declare const event: (() => EventMeta<_CustomEventContructor<undefined>>) & (<T>() => EventMeta<_CustomEventContructor<T>>) & (<E extends EventConstructor>(eventConstructor: E) => EventMeta<E>);
|
|
149
|
+
export type Metadata = {
|
|
150
|
+
[K in keyof ComponentInner<any> | "props" | "events"]?: never;
|
|
151
|
+
} & {
|
|
152
|
+
[K in keyof DomProps<any>]?: never;
|
|
153
|
+
} & {
|
|
154
|
+
[K in keyof HTMLElement]?: never;
|
|
155
|
+
} & {
|
|
156
|
+
[name: string]: PropMeta<any> | EventMeta<any>;
|
|
157
|
+
};
|
|
158
|
+
export declare const componentSym: unique symbol;
|
|
159
|
+
export declare const jsxPropsSym: unique symbol;
|
|
160
|
+
declare abstract class ComponentInner<M extends Metadata> {
|
|
161
|
+
protected props: Props<M>;
|
|
162
|
+
protected events: EventEmitters<M>;
|
|
163
|
+
readonly [jsxPropsSym]?: ComponentJsxProps<M>;
|
|
164
|
+
readonly [componentSym]: {
|
|
165
|
+
_scope?: ReturnType<typeof useScope>;
|
|
166
|
+
_destroy?: (() => void) | void;
|
|
167
|
+
};
|
|
168
|
+
connectedCallback(): void;
|
|
169
|
+
disconnectedCallback(): void;
|
|
170
|
+
attributeChangedCallback(name: string, oldValue: string | null, value: string | null): void;
|
|
171
|
+
addEventListener<K extends keyof Events<M> & string>(type: JsxPropNameToEventName<K>, listener: (event: InstanceType<Events<M>[K]>) => void, options?: boolean | AddEventListenerOptions): void;
|
|
172
|
+
removeEventListener<K extends keyof Events<M> & string>(type: JsxPropNameToEventName<K>, listener: (event: InstanceType<Events<M>[K]>) => void, options?: boolean | EventListenerOptions): void;
|
|
173
|
+
abstract render(): Template;
|
|
174
|
+
}
|
|
175
|
+
export type Component<M extends Metadata = {}> = {
|
|
176
|
+
-readonly [K in keyof Props<M>]: Props<M>[K] extends Signal<infer T> ? T : never;
|
|
177
|
+
} & ComponentInner<M> & HTMLElement;
|
|
178
|
+
export interface ComponentConstructor<M extends Metadata = {}> {
|
|
179
|
+
/** @ignore */
|
|
180
|
+
readonly [componentSym]: {
|
|
181
|
+
readonly _tagName: string;
|
|
182
|
+
};
|
|
183
|
+
readonly observedAttributes: readonly string[];
|
|
184
|
+
new (): Component<M>;
|
|
185
|
+
}
|
|
186
|
+
export interface ComponentOptions {
|
|
187
|
+
/**
|
|
188
|
+
* Shadow DOM options. Set to `false` to disable shadow DOM.
|
|
189
|
+
*
|
|
190
|
+
* @default { mode: "open" }
|
|
191
|
+
*/
|
|
192
|
+
shadow?: ShadowRootInit | false;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Creates an effect which will rerun when any accessed signal changes.
|
|
196
|
+
*
|
|
197
|
+
* If used inside of a component and the component is not yet mounted, the
|
|
198
|
+
* effect will run only after the component is mounted. Otherwise, the effect
|
|
199
|
+
* will run immediately.
|
|
200
|
+
*
|
|
201
|
+
* @param fn The function to run; it may return a cleanup function.
|
|
202
|
+
*/
|
|
203
|
+
export declare const useMountEffect: (fn: () => Cleanup, deps?: Signal<unknown>[]) => void;
|
|
204
|
+
/**
|
|
205
|
+
* Creates a new web component class.
|
|
206
|
+
*
|
|
207
|
+
* Specify props and events using the `metadata` parameter.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```tsx
|
|
211
|
+
* class MyComponent extends Component("my-component", {
|
|
212
|
+
* myProp: prop<string>("Hello, world!"),
|
|
213
|
+
* onMyEvent: event(),
|
|
214
|
+
* }) {
|
|
215
|
+
* render() {
|
|
216
|
+
* return (
|
|
217
|
+
* <>
|
|
218
|
+
* <h1>{this.props.myProp}</h1>
|
|
219
|
+
* <button onclick={() => this.events.onMyEvent()}>Click me</button>
|
|
220
|
+
* </>
|
|
221
|
+
* );
|
|
222
|
+
* },
|
|
223
|
+
* }
|
|
224
|
+
*
|
|
225
|
+
* customElements.define("my-component", MyComponent);
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
export declare const Component: ((tagName: string) => ComponentConstructor<{}>) & (<const M extends Metadata>(tagName: string, metadata: M, opts?: ComponentOptions) => ComponentConstructor<M>);
|
|
229
|
+
/**
|
|
230
|
+
* Determines whether the given value is a component created by
|
|
231
|
+
* extending {@link ComponentConstructor}.
|
|
232
|
+
*/
|
|
233
|
+
export declare const isComponent: (value: any) => value is ComponentConstructor<{}> | Component<{}>;
|
|
234
|
+
/**
|
|
235
|
+
* Represents a functional component.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```tsx
|
|
239
|
+
* const MyComponent: FunctionalComponent<{
|
|
240
|
+
* name: MaybeSignal<string>;
|
|
241
|
+
* }> = ({ name }) => {
|
|
242
|
+
* return <h1>Hello, {name}!</h1>;
|
|
243
|
+
* };
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
export interface FunctionalComponent<in P extends object = {}> {
|
|
247
|
+
(props: P): Template;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Defines a set of components with the given prefix.
|
|
251
|
+
*/
|
|
252
|
+
export declare const defineComponents: ((...components: ComponentConstructor[]) => void) & ((prefix: string, ...components: ComponentConstructor[]) => void);
|
|
253
|
+
export {};
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { useEffect, useSubscope, useSignal, } from "./scope.js";
|
|
2
|
+
import { runWithRenderer } from "./renderer.js";
|
|
3
|
+
import { camelCaseToKebabCase, jsxPropNameToEventName, } from "./utils.js";
|
|
4
|
+
import { useScope } from "./scope.js";
|
|
5
|
+
import { isContext, provideContext } from "./context.js";
|
|
6
|
+
/**
|
|
7
|
+
* Defines a property in your component metadata that can be set from outside
|
|
8
|
+
* of the component.
|
|
9
|
+
*
|
|
10
|
+
* Make sure to avoid conflicts with native `HTMLElement` properties.
|
|
11
|
+
*
|
|
12
|
+
* You can get properties by accessing the {@link Signal} in `this.props`.
|
|
13
|
+
* It's also possible to set the properties directly on the component instance.
|
|
14
|
+
*
|
|
15
|
+
* It's also possible to define an attribute for the property by setting the
|
|
16
|
+
* `attribute` option. By default, the attribute name is the kebab-case version
|
|
17
|
+
* of the property name. The attribute will be observed and the signal updated
|
|
18
|
+
* on changes. You can also provide a custom name and a transform function to
|
|
19
|
+
* convert the attribute value to the property value.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* class App extends Component("x-app", {
|
|
24
|
+
* greetingMessage: prop<string>("Hello, world!", {
|
|
25
|
+
* attribute: {
|
|
26
|
+
* name: "greeting",
|
|
27
|
+
* }
|
|
28
|
+
* }),
|
|
29
|
+
* }) {
|
|
30
|
+
* render() {
|
|
31
|
+
* return <h1>{this.props.greetingMessage}</h1>;
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* defineComponents(App);
|
|
36
|
+
*
|
|
37
|
+
* const app = new App();
|
|
38
|
+
* app.greetingMessage = "Hello, universe!";
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export const prop = (defaultOrContext, opts) => ({
|
|
42
|
+
_tag: "p",
|
|
43
|
+
_defaultOrContext: defaultOrContext,
|
|
44
|
+
...opts,
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* Defines an event in your component metadata that can be dispatched by
|
|
48
|
+
* the component.
|
|
49
|
+
*
|
|
50
|
+
* Make sure your event name starts with `on` and to avoid conflicts with
|
|
51
|
+
* native `HTMLElement` events. The event name will be converted to kebab-case.
|
|
52
|
+
*
|
|
53
|
+
* You can dispatch events either using `HTMLElement.dispatchEvent` or by
|
|
54
|
+
* calling the event emitter function in `this.events` inside the `render`
|
|
55
|
+
* function of a component.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* class App extends Component("x-app", {
|
|
60
|
+
* onSomethingHappen: event<string>(),
|
|
61
|
+
* // Event name will be `something-happen`
|
|
62
|
+
* }) {
|
|
63
|
+
* render() {
|
|
64
|
+
* // …
|
|
65
|
+
* this.events.onSomethingHappen({ detail: "Something happened! "});
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
*
|
|
69
|
+
* const app = new App();
|
|
70
|
+
* app.addEventListener("something-happen", (evt) => {
|
|
71
|
+
* // `evt` is `CustomEvent<string>`
|
|
72
|
+
* console.log(evt.detail);
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* You can also provide a custom event constructor:
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* class App extends Component("x-app", {
|
|
81
|
+
* onSomethingClick: event(() => MouseEvent),
|
|
82
|
+
* }) {
|
|
83
|
+
* render() {
|
|
84
|
+
* return (
|
|
85
|
+
* <button onclick={evt => this.events.onSomethingClick(evt)}>
|
|
86
|
+
* Click me!
|
|
87
|
+
* </button>
|
|
88
|
+
* );
|
|
89
|
+
* }
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export const event = ((eventConstructor = CustomEvent) => ({
|
|
94
|
+
_tag: "e",
|
|
95
|
+
_event: eventConstructor,
|
|
96
|
+
}));
|
|
97
|
+
export const componentSym = Symbol("Component");
|
|
98
|
+
let mountEffects;
|
|
99
|
+
/**
|
|
100
|
+
* Creates an effect which will rerun when any accessed signal changes.
|
|
101
|
+
*
|
|
102
|
+
* If used inside of a component and the component is not yet mounted, the
|
|
103
|
+
* effect will run only after the component is mounted. Otherwise, the effect
|
|
104
|
+
* will run immediately.
|
|
105
|
+
*
|
|
106
|
+
* @param fn The function to run; it may return a cleanup function.
|
|
107
|
+
*/
|
|
108
|
+
export const useMountEffect = (fn, deps) => {
|
|
109
|
+
if (mountEffects) {
|
|
110
|
+
mountEffects.push([fn, deps]);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
useEffect(fn, deps);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Creates a new web component class.
|
|
118
|
+
*
|
|
119
|
+
* Specify props and events using the `metadata` parameter.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```tsx
|
|
123
|
+
* class MyComponent extends Component("my-component", {
|
|
124
|
+
* myProp: prop<string>("Hello, world!"),
|
|
125
|
+
* onMyEvent: event(),
|
|
126
|
+
* }) {
|
|
127
|
+
* render() {
|
|
128
|
+
* return (
|
|
129
|
+
* <>
|
|
130
|
+
* <h1>{this.props.myProp}</h1>
|
|
131
|
+
* <button onclick={() => this.events.onMyEvent()}>Click me</button>
|
|
132
|
+
* </>
|
|
133
|
+
* );
|
|
134
|
+
* },
|
|
135
|
+
* }
|
|
136
|
+
*
|
|
137
|
+
* customElements.define("my-component", MyComponent);
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export const Component = ((tagName, metadata = {}, opts = {}) => {
|
|
141
|
+
// Extract attribute information
|
|
142
|
+
const observedAttributes = [];
|
|
143
|
+
const attributePropMap = new Map();
|
|
144
|
+
for (const name in metadata) {
|
|
145
|
+
const meta = metadata[name];
|
|
146
|
+
if (meta._tag == "p" && meta.attribute) {
|
|
147
|
+
if (typeof meta.attribute == "function") {
|
|
148
|
+
meta.attribute = { transform: meta.attribute };
|
|
149
|
+
}
|
|
150
|
+
const attribute = (meta.attribute = {
|
|
151
|
+
name: camelCaseToKebabCase(name),
|
|
152
|
+
static: false,
|
|
153
|
+
transform: (x) => x,
|
|
154
|
+
...meta.attribute,
|
|
155
|
+
});
|
|
156
|
+
attributePropMap.set(attribute.name, {
|
|
157
|
+
name,
|
|
158
|
+
meta: meta,
|
|
159
|
+
});
|
|
160
|
+
if (!attribute.static) {
|
|
161
|
+
observedAttributes.push(attribute.name);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Create base class
|
|
166
|
+
opts.shadow ??= { mode: "open" };
|
|
167
|
+
const getRenderParent = (component) => opts.shadow
|
|
168
|
+
? component.shadowRoot ?? component.attachShadow(opts.shadow)
|
|
169
|
+
: component;
|
|
170
|
+
class _Component extends HTMLElement {
|
|
171
|
+
static [componentSym] = {
|
|
172
|
+
_tagName: tagName,
|
|
173
|
+
};
|
|
174
|
+
static observedAttributes = observedAttributes;
|
|
175
|
+
props = {};
|
|
176
|
+
events = {};
|
|
177
|
+
[componentSym] = {};
|
|
178
|
+
constructor() {
|
|
179
|
+
super();
|
|
180
|
+
for (const name in metadata) {
|
|
181
|
+
const meta = metadata[name];
|
|
182
|
+
if (meta._tag == "p") {
|
|
183
|
+
const context = isContext(meta._defaultOrContext)
|
|
184
|
+
? meta._defaultOrContext
|
|
185
|
+
: null;
|
|
186
|
+
const [getter, setter] = useSignal(context ? undefined : meta._defaultOrContext);
|
|
187
|
+
this.props[name] = getter;
|
|
188
|
+
if (context) {
|
|
189
|
+
provideContext(context, this, getter);
|
|
190
|
+
}
|
|
191
|
+
Object.defineProperty(this, name, {
|
|
192
|
+
get: getter.peek,
|
|
193
|
+
set: (value) => setter(() => value, { force: true }),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
else if (meta._tag == "e" && name.startsWith("on")) {
|
|
197
|
+
const eventName = jsxPropNameToEventName(name);
|
|
198
|
+
this.events[name] = (arg) => this.dispatchEvent(new meta._event(eventName, arg));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
connectedCallback() {
|
|
203
|
+
const renderParent = getRenderParent(this);
|
|
204
|
+
this[componentSym]._destroy = useSubscope(() => runWithRenderer({
|
|
205
|
+
_svg: false,
|
|
206
|
+
_component: this,
|
|
207
|
+
_nodes: renderParent.childNodes.values(),
|
|
208
|
+
}, () => {
|
|
209
|
+
this[componentSym]._scope = useScope();
|
|
210
|
+
// Render
|
|
211
|
+
const prevMountEffects = mountEffects;
|
|
212
|
+
mountEffects = [];
|
|
213
|
+
try {
|
|
214
|
+
renderParent?.append(...this.render().build());
|
|
215
|
+
// Run mount effects
|
|
216
|
+
mountEffects.forEach(([fn, opts]) => useEffect(fn, opts));
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
mountEffects = prevMountEffects;
|
|
220
|
+
}
|
|
221
|
+
}))[1];
|
|
222
|
+
}
|
|
223
|
+
disconnectedCallback() {
|
|
224
|
+
this[componentSym]._destroy?.();
|
|
225
|
+
}
|
|
226
|
+
attributeChangedCallback(name, _, value) {
|
|
227
|
+
const prop = attributePropMap.get(name);
|
|
228
|
+
if (prop) {
|
|
229
|
+
this[prop.name] =
|
|
230
|
+
value != null
|
|
231
|
+
? prop.meta.attribute.transform.call(this, value)
|
|
232
|
+
: isContext(prop.meta._defaultOrContext)
|
|
233
|
+
? undefined
|
|
234
|
+
: prop.meta._defaultOrContext;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return _Component;
|
|
239
|
+
});
|
|
240
|
+
/**
|
|
241
|
+
* Determines whether the given value is a component created by
|
|
242
|
+
* extending {@link ComponentConstructor}.
|
|
243
|
+
*/
|
|
244
|
+
export const isComponent = (value) => !!value?.[componentSym];
|
|
245
|
+
/**
|
|
246
|
+
* Defines a set of components with the given prefix.
|
|
247
|
+
*/
|
|
248
|
+
export const defineComponents = (...args) => {
|
|
249
|
+
const [prefix, components] = typeof args[0] == "string"
|
|
250
|
+
? [args[0], args.slice(1)]
|
|
251
|
+
: ["", args];
|
|
252
|
+
for (const component of components) {
|
|
253
|
+
customElements.define(prefix + component[componentSym]._tagName, component);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
//# sourceMappingURL=component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Signal, SetSignalOptions, MaybeSignal } from "./scope.js";
|
|
2
|
+
declare const contextSym: unique symbol;
|
|
3
|
+
/**
|
|
4
|
+
* A value that can be passed through the component tree without having to be
|
|
5
|
+
* explicitly passed as a prop.
|
|
6
|
+
*/
|
|
7
|
+
export interface Context<in out T> {
|
|
8
|
+
readonly [contextSym]: string;
|
|
9
|
+
/** @ignore */
|
|
10
|
+
readonly _init: T;
|
|
11
|
+
/** @ignore */
|
|
12
|
+
readonly _opts?: SetSignalOptions;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new context with the given value.
|
|
16
|
+
*/
|
|
17
|
+
export declare const createContext: (<T>(value: T, opts?: SetSignalOptions) => Context<T>) & (<T>(value?: T, opts?: SetSignalOptions) => Context<T | undefined>);
|
|
18
|
+
export declare const isContext: (value: any) => value is Context<unknown>;
|
|
19
|
+
export declare const provideContext: <T>(context: Context<T>, element: Element, value: MaybeSignal<T | undefined>) => void;
|
|
20
|
+
export declare const useContext: <T>(context: Context<T>) => Signal<T>;
|
|
21
|
+
export {};
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useRenderer } from "./renderer.js";
|
|
2
|
+
import { useMemo, MaybeSignal } from "./scope.js";
|
|
3
|
+
const contextSym = Symbol("Context");
|
|
4
|
+
/**
|
|
5
|
+
* Creates a new context with the given value.
|
|
6
|
+
*/
|
|
7
|
+
export const createContext = ((value, opts) => ({
|
|
8
|
+
[contextSym]: Math.random().toString(36).slice(2),
|
|
9
|
+
_init: value,
|
|
10
|
+
_opts: opts,
|
|
11
|
+
}));
|
|
12
|
+
export const isContext = (value) => !!value?.[contextSym];
|
|
13
|
+
export const provideContext = (context, element, value) => {
|
|
14
|
+
element.addEventListener(context[contextSym], (evt) => {
|
|
15
|
+
const innerValue = MaybeSignal.get(value);
|
|
16
|
+
if (innerValue !== undefined) {
|
|
17
|
+
evt.stopPropagation();
|
|
18
|
+
evt.detail(innerValue);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
export const useContext = (context) => {
|
|
23
|
+
const renderer = useRenderer();
|
|
24
|
+
return useMemo(() => {
|
|
25
|
+
let result = context._init;
|
|
26
|
+
renderer._component?.dispatchEvent(new CustomEvent(context[contextSym], {
|
|
27
|
+
detail: (value) => (result = value),
|
|
28
|
+
bubbles: true,
|
|
29
|
+
composed: true,
|
|
30
|
+
}));
|
|
31
|
+
return result;
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,OAAO,EAA4B,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5E,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAgBrC;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAI8C,CAAC,CACvE,KAAS,EACT,IAAuB,EACC,EAAE,CAAC,CAAC;IAC5B,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACjD,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,IAAI;CACZ,CAAC,CAAQ,CAAC;AAEX,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAU,EAA6B,EAAE,CACjE,CAAC,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,CAAC;AAExB,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,OAAmB,EACnB,OAAgB,EAChB,KAAiC,EACjC,EAAE;IACF,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE;QACpD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE1C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,eAAe,EAAE,CAAC;YACrB,GAAuB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAI,OAAmB,EAAa,EAAE;IAC9D,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAE3B,QAAQ,CAAC,UAAU,EAAE,aAAa,CAChC,IAAI,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;YACnC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC;YACnC,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAoB,CACtB,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { FunctionalComponent, JsxProps } from "./component.js";
|
|
2
|
+
import { DomIntrinsicElements, DomProps } from "./dom.js";
|
|
3
|
+
import { Children } from "./intrinsic/Fragment.js";
|
|
4
|
+
import { Template } from "./template.js";
|
|
5
|
+
/**
|
|
6
|
+
* Creates a template based on the given component type.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* render() {
|
|
11
|
+
* return createElement("div", { id: "app" }, [
|
|
12
|
+
* createElement("h1", {}, "Hello, World!"),
|
|
13
|
+
* ]);
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const createElement: (<K extends keyof DomIntrinsicElements & string>(type: K, props?: DomIntrinsicElements[K], children?: Children) => Template) & (<T extends HTMLElement>(...args: [
|
|
18
|
+
type: new () => T,
|
|
19
|
+
...({} extends JsxProps<T> ? [props?: JsxProps<T>] : [props: JsxProps<T>]),
|
|
20
|
+
children?: DomProps<T>["children"]
|
|
21
|
+
]) => Template) & (<P extends object>(...args: [
|
|
22
|
+
type: FunctionalComponent<P>,
|
|
23
|
+
...({} extends P ? [props?: P] : [props: P]),
|
|
24
|
+
...(P extends {
|
|
25
|
+
children?: unknown;
|
|
26
|
+
} ? undefined extends P["children"] ? [children?: P["children"]] : [children: P["children"]] : [])
|
|
27
|
+
]) => Template);
|
|
28
|
+
/**
|
|
29
|
+
* Shorthand for {@link createElement} with convenience methods for intrinsic
|
|
30
|
+
* elements.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* render() {
|
|
35
|
+
* return h.div({ id: "app" }, [
|
|
36
|
+
* h.h1({}, "Hello, World!"),
|
|
37
|
+
* ]);
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare const h: typeof createElement & {
|
|
42
|
+
[K in keyof DomIntrinsicElements]: (props?: DomIntrinsicElements[K], children?: Children) => Template;
|
|
43
|
+
};
|