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.
Files changed (117) hide show
  1. package/.github/workflows/ci.yml +24 -0
  2. package/.github/workflows/deploy-docs.yml +47 -0
  3. package/.prettierrc +3 -0
  4. package/LICENSE.md +21 -0
  5. package/README.md +33 -0
  6. package/ci/check-size.js +8 -0
  7. package/dist/array_mutation.d.ts +16 -0
  8. package/dist/array_mutation.js +75 -0
  9. package/dist/array_mutation.js.map +1 -0
  10. package/dist/bundle.d.ts +1126 -0
  11. package/dist/bundle.js +1074 -0
  12. package/dist/bundle.min.js +1 -0
  13. package/dist/component.d.ts +253 -0
  14. package/dist/component.js +256 -0
  15. package/dist/component.js.map +1 -0
  16. package/dist/context.d.ts +21 -0
  17. package/dist/context.js +34 -0
  18. package/dist/context.js.map +1 -0
  19. package/dist/create_element.d.ts +43 -0
  20. package/dist/create_element.js +43 -0
  21. package/dist/create_element.js.map +1 -0
  22. package/dist/dom.d.ts +602 -0
  23. package/dist/dom.js +97 -0
  24. package/dist/dom.js.map +1 -0
  25. package/dist/intrinsic/ClassComponent.d.ts +2 -0
  26. package/dist/intrinsic/ClassComponent.js +10 -0
  27. package/dist/intrinsic/ClassComponent.js.map +1 -0
  28. package/dist/intrinsic/Dynamic.d.ts +33 -0
  29. package/dist/intrinsic/Dynamic.js +53 -0
  30. package/dist/intrinsic/Dynamic.js.map +1 -0
  31. package/dist/intrinsic/ErrorBoundary.d.ts +14 -0
  32. package/dist/intrinsic/ErrorBoundary.js +36 -0
  33. package/dist/intrinsic/ErrorBoundary.js.map +1 -0
  34. package/dist/intrinsic/For.d.ts +10 -0
  35. package/dist/intrinsic/For.js +81 -0
  36. package/dist/intrinsic/For.js.map +1 -0
  37. package/dist/intrinsic/Fragment.d.ts +23 -0
  38. package/dist/intrinsic/Fragment.js +28 -0
  39. package/dist/intrinsic/Fragment.js.map +1 -0
  40. package/dist/intrinsic/If.d.ts +24 -0
  41. package/dist/intrinsic/If.js +47 -0
  42. package/dist/intrinsic/If.js.map +1 -0
  43. package/dist/intrinsic/Portal.d.ts +6 -0
  44. package/dist/intrinsic/Portal.js +15 -0
  45. package/dist/intrinsic/Portal.js.map +1 -0
  46. package/dist/intrinsic/Style.d.ts +7 -0
  47. package/dist/intrinsic/Style.js +70 -0
  48. package/dist/intrinsic/Style.js.map +1 -0
  49. package/dist/intrinsic/TagComponent.d.ts +4 -0
  50. package/dist/intrinsic/TagComponent.js +67 -0
  51. package/dist/intrinsic/TagComponent.js.map +1 -0
  52. package/dist/intrinsic/Text.d.ts +6 -0
  53. package/dist/intrinsic/Text.js +16 -0
  54. package/dist/intrinsic/Text.js.map +1 -0
  55. package/dist/intrinsic/mod.d.ts +5 -0
  56. package/dist/intrinsic/mod.js +6 -0
  57. package/dist/intrinsic/mod.js.map +1 -0
  58. package/dist/jsx-runtime/mod.d.ts +23 -0
  59. package/dist/jsx-runtime/mod.js +11 -0
  60. package/dist/jsx-runtime/mod.js.map +1 -0
  61. package/dist/mod.d.ts +8 -0
  62. package/dist/mod.js +7 -0
  63. package/dist/mod.js.map +1 -0
  64. package/dist/renderer.d.ts +13 -0
  65. package/dist/renderer.js +25 -0
  66. package/dist/renderer.js.map +1 -0
  67. package/dist/scope.d.ts +138 -0
  68. package/dist/scope.js +228 -0
  69. package/dist/scope.js.map +1 -0
  70. package/dist/template.d.ts +10 -0
  71. package/dist/template.js +7 -0
  72. package/dist/template.js.map +1 -0
  73. package/dist/utils.d.ts +6 -0
  74. package/dist/utils.js +13 -0
  75. package/dist/utils.js.map +1 -0
  76. package/package.json +71 -0
  77. package/src/array_mutation.ts +118 -0
  78. package/src/component.ts +624 -0
  79. package/src/context.ts +70 -0
  80. package/src/create_element.ts +89 -0
  81. package/src/dom.ts +819 -0
  82. package/src/intrinsic/ClassComponent.ts +17 -0
  83. package/src/intrinsic/For.ts +122 -0
  84. package/src/intrinsic/Fragment.ts +38 -0
  85. package/src/intrinsic/If.ts +73 -0
  86. package/src/intrinsic/Portal.ts +25 -0
  87. package/src/intrinsic/Style.ts +120 -0
  88. package/src/intrinsic/TagComponent.ts +102 -0
  89. package/src/intrinsic/Text.ts +24 -0
  90. package/src/intrinsic/mod.ts +5 -0
  91. package/src/jsx-runtime/mod.ts +41 -0
  92. package/src/mod.ts +37 -0
  93. package/src/renderer.ts +45 -0
  94. package/src/scope.ts +404 -0
  95. package/src/template.ts +16 -0
  96. package/src/utils.ts +29 -0
  97. package/terser.config.json +16 -0
  98. package/tsconfig.json +18 -0
  99. package/web/README.md +41 -0
  100. package/web/babel.config.js +3 -0
  101. package/web/dist/shingo.min.d.ts +1131 -0
  102. package/web/dist/shingo.min.js +1 -0
  103. package/web/docusaurus.config.ts +151 -0
  104. package/web/package-lock.json +14850 -0
  105. package/web/package.json +54 -0
  106. package/web/sidebars.ts +31 -0
  107. package/web/src/components/monacoEditor.tsx +72 -0
  108. package/web/src/components/playground.tsx +89 -0
  109. package/web/src/components/playgroundComponent.tsx +168 -0
  110. package/web/src/css/custom.css +37 -0
  111. package/web/src/pages/index.module.css +31 -0
  112. package/web/src/pages/index.tsx +73 -0
  113. package/web/src/pages/playground.tsx +64 -0
  114. package/web/static/.nojekyll +0 -0
  115. package/web/static/dist/bundle.d.ts +1126 -0
  116. package/web/static/dist/bundle.min.js +1 -0
  117. 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 {};
@@ -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
+ };