@neuralfog/elemix-storybook 0.0.1
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 +19 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/src/elemixDecorator.d.ts +2 -0
- package/dist/src/elemixStory.d.ts +23 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## Notes
|
|
2
|
+
|
|
3
|
+
bash
|
|
4
|
+
```
|
|
5
|
+
npx storybook@latest init --type web_components
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
Storybook wizard is ass, so have to create `tsconfig.json` first in order to bootstrap typescript project.
|
|
9
|
+
|
|
10
|
+
## TODO
|
|
11
|
+
|
|
12
|
+
- [x] This was easy just works
|
|
13
|
+
- [] Cant have globals in stories it will mess up concurrent runs of stories:
|
|
14
|
+
- [] Application context is static class, needs changing
|
|
15
|
+
- [] Application context inject in stories somehow
|
|
16
|
+
- [] Signals are also global states that may be used by multiple components
|
|
17
|
+
- [] Need to find a way to stub signals per story, this is not easy, it is
|
|
18
|
+
but ergonomics matter, at moment signal are injected at the decorator stage :thinking:
|
|
19
|
+
- [] Write helpers in testing package to pierce shadow dom and wait for element
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var R={},d={},O;function se(){if(O)return d;O=1;const m="₥";var u=(o=>(o[o.EVENT=0]="EVENT",o[o.PROP=1]="PROP",o[o.MODEL=2]="MODEL",o[o.STD=3]="STD",o[o.REF=4]="REF",o[o.EMIT=5]="EMIT",o[o.BIND_ATTRS=6]="BIND_ATTRS",o[o.BIND_EVENTS=7]="BIND_EVENTS",o[o.DIRECT_CLASS=8]="DIRECT_CLASS",o))(u||{});const p=o=>{const f=new RegExp(`${m}(\\d+)`),g=o.match(f);if(!g)throw new Error("Unable to extract index from hole comment");return Number(g[1])},c=o=>`<!--${m}${o}-->`,l=o=>o.replace(/<([a-zA-Z][^\s/>]*)([\s\S]*?)\/>/g,(f,g,S)=>g.includes("-")?`<${g}${S}></${g}>`:f),T=o=>o.replace(/(\S+)=((<!--[\s\S]*?-->)|([^\s">]+))/g,'$1="$2"'),y=o=>o.replace(/([A-Z])/g,f=>"-"+f.toLowerCase()),N=(o,f)=>Array.from(new Set([...o.split(" "),...f.split(" ")].filter(Boolean))).join(" ").trim();return d.Attributes=u,d.TEMPLATE_MARKER_GLYPH=m,d.camelToKebab=y,d.fixAttributeQuotes=T,d.fixSelfClosingTags=l,d.getIndexFromComment=p,d.makeMarkerComment=c,d.mergeClasses=N,d}var $;function ie(){return $||($=1,(function(m){var u=Object.defineProperty,p=(r,e,s)=>e in r?u(r,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):r[e]=s,c=(r,e,s)=>p(r,typeof e!="symbol"?e+"":e,s);Object.defineProperty(m,Symbol.toStringTag,{value:"Module"});const l=se(),T=r=>{const e=r;return e.$cache||(e.$cache={template:new Map}),e.$cache};class y{constructor(e,s){c(this,"key",""),this.strings=e,this.values=s}}class N{constructor(e,s){c(this,"initialClass"),this.node=e,this.definition=s,this.initialClass=e.getAttribute("class")||""}setValue(e){if(e==null||typeof e!="object")return;const{node:s}=this,t=e;for(const[i,n]of Object.entries(t)){const a=l.camelToKebab(i);if(n==null||n===!1){s.removeAttribute(a),this.initialClass.length&&s.setAttribute("class",String(this.initialClass));continue}if(a==="class"){s.setAttribute("class",l.mergeClasses(this.initialClass,String(n)));continue}s.setAttribute(a,String(n))}}}class o{constructor(e,s){this.node=e,this.definition=s}setValue(e){if(e!=null&&typeof e=="object")for(const[s,t]of Object.entries(e))this.node[`on${s}`]=t}}class f{constructor(e,s){c(this,"initialClass"),this.node=e,this.definition=s,this.initialClass=e.getAttribute("class")||""}setValue(e){const{node:s}=this;if(e==null&&this.initialClass.length&&s.setAttribute("class",String(this.initialClass)),typeof e=="string"&&s.setAttribute("class",l.mergeClasses(this.initialClass,String(e))),typeof e=="object"){const t=Object.entries(e).filter(([,i])=>!!i).map(([i])=>i).join(" ");s.setAttribute("class",l.mergeClasses(this.initialClass,t))}}}class g{constructor(e,s){this.node=e,this.definition=s}setValue(e){if(e===void 0)return;const{name:s}=this.definition,t=this.node;t.$emits&&t.$emits.set(s.slice(s.indexOf(":")+1),e)}}class S{constructor(e,s){this.node=e,this.definition=s}setValue(e){if(e===void 0)return;const s=this.definition.name.slice(1);this.node[`on${s}`]=e}}class _{constructor(e,s){this.node=e,this.definition=s}setValue(e){if(e===void 0)return;const s=t=>{e.value=t.target.value};this.node.oninput||(this.node.value=e.value,this.node.oninput=s)}}class j{constructor(e,s){this.node=e,this.definition=s}setValue(e){const s=this.definition.name.slice(1),t=this.node;t.$props&&t.$props.set(s,e)}}class P{constructor(e,s){this.node=e,this.definition=s}setValue(e){e!==void 0&&(e.value=this.node)}}let x=class{constructor(r,e){this.node=r,this.definition=e}setValue(r){r!==void 0&&this.node.setAttribute(this.definition.name,String(r))}};const F=(r,e)=>{const s=/(\S+)(?==(?:["']?)$)/,t=r.match(s);if(t){const i={index:e,name:t[1],value:l.makeMarkerComment(e),virtual:!1,type:l.Attributes.STD};switch(t[1][0]){case"@":return t[1].startsWith("@emits:")?(i.type=l.Attributes.EMIT,i.virtual=!0,i):(i.type=l.Attributes.EVENT,i.virtual=!0,i);case":":return t[1].endsWith(":ref")?(i.type=l.Attributes.REF,i.virtual=!0,i):(i.type=l.Attributes.PROP,i.virtual=!0,i);case"~":return t[1].startsWith("~model")&&(i.type=l.Attributes.MODEL,i.virtual=!0),i;case".":return t[1].startsWith(".bind-attrs")?(i.type=l.Attributes.BIND_ATTRS,i.virtual=!0,i):t[1].startsWith(".bind-events")?(i.type=l.Attributes.BIND_EVENTS,i.virtual=!0,i):(t[1].startsWith(".class")&&(i.type=l.Attributes.DIRECT_CLASS,i.virtual=!0),i);default:return i}}},K=(r,e)=>{const s=r.querySelector(W(e.name,e.value));if(s)switch(e.virtual&&s.removeAttribute(e.name),e.type){case l.Attributes.EVENT:return new S(s,e);case l.Attributes.PROP:return new j(s,e);case l.Attributes.MODEL:return new _(s,e);case l.Attributes.REF:return new P(s,e);case l.Attributes.EMIT:return new g(s,e);case l.Attributes.BIND_ATTRS:return new N(s,e);case l.Attributes.DIRECT_CLASS:return new f(s,e);case l.Attributes.BIND_EVENTS:return new o(s,e);default:return new x(s,e)}},B=r=>{let e="";for(let s=0;s<r.length;s++){const t=r.charAt(s),i=t.charCodeAt(0);i>=48&&i<=57||i>=65&&i<=90||i>=97&&i<=122||t==="-"||t==="_"?e+=t:e+=`\\${t}`}return e},W=(r,e)=>`[${B(r)}='${e}']`,q=(r,e)=>{const s=r.length,t=e.length,i=Object.create(null);let n,a,h;for(n=0;n<s;n++)a=r[n].key,i[a]=n;const b=new Array(t),v=[],A=[],k=Object.create(null);for(n=0;n<t;n++){const E=e[n].key;k[E]=!0;const M=i[E];M===void 0?b[n]=-1:(b[n]=M,v.push(M),A.push(n))}const L=G(v),C=new Array(t);for(n=0;n<t;n++)C[n]=!1;const te=L.length;for(n=0;n<te;n++)C[A[L[n]]]=!0;const I=[],D=[],V=[];for(n=0;n<s;n++)h=r[n].key,k[h]!==!0&&I.push({key:h});for(n=0;n<t;n++){h=e[n].key;const E=n+1<t?e[n+1].key:void 0;b[n]===-1?D.push({key:h,value:e[n],beforeKey:E}):C[n]||V.push({key:h,beforeKey:E})}return{deletes:I,inserts:D,moves:V}},G=r=>{const e=r.length,s=new Array(e),t=[];let i,n,a,h;for(i=0;i<e;i++){for(n=0,a=t.length;n<a;)h=n+a>>>1,r[t[h]]<r[i]?n=h+1:a=h;n===t.length?t.push(i):t[n]=i,s[i]=n>0?t[n-1]:-1}const b=t.length,v=new Array(b);let A=t[b-1];for(i=b-1;i>=0;i--)v[i]=A,A=s[A];return v};class Q{constructor(e){c(this,"cache",{listTemplate:new Map,listNodes:new Map,listHtmlTemplate:[]}),this.commentNode=e}renderListElement(e,s){if(!this.commentNode)throw new Error("renderList method needs to accept instance of HTMLElement");if(!e.key)throw new Error("use repeat directive when rendering the lists");let t=this.cache.listTemplate.get(e.key);return t||(t=new w(e),this.cache.listTemplate.set(e.key,t),t.mountListElement(this.commentNode,e.key,e.values,this.cache,s)),t}renderAllItems(e){const s=e.length;for(let t=0;t<s;t++)this.renderListElement(e[t]).update(e[t].values)}emptyList(){for(const[,e]of this.cache.listNodes)e.remove();this.cache.listTemplate.clear(),this.cache.listNodes.clear()}deleteNodes(e){const s=e.length;for(let t=s-1;t>=0;t--){const i=this.cache.listNodes.get(e[t].key);i&&i.remove(),this.cache.listNodes.delete(e[t].key),this.cache.listTemplate.delete(e[t].key)}}moveNodes(e){const s=e.length;for(let t=s-1;t>=0;t--){const i=this.cache.listNodes.get(e[t].key),n=this.cache.listNodes.get(e[t].beforeKey);i&&n&&n?.before(i),!n&&i&&this.commentNode.before(i)}}insertNodes(e){const s=e.length;for(let t=s-1;t>=0;t--){const i=this.cache.listNodes.get(e[t].beforeKey);this.renderListElement(e[t].value,i)}}updateAllItems(e){const s=e.length;for(let t=0;t<s;t++){const i=this.cache.listTemplate.get(e[t].key);i?.update(e[t].values)}}render(e){if(!this.cache.listHtmlTemplate.length){this.renderAllItems(e),this.cache.listHtmlTemplate=e;return}if(!e.length){this.emptyList(),this.cache.listHtmlTemplate=e;return}const{deletes:s,inserts:t,moves:i}=q(this.cache.listHtmlTemplate,e);if(s.length===e.length||t.length===e.length){this.emptyList(),this.renderAllItems(e),this.cache.listHtmlTemplate=e;return}s.length&&this.deleteNodes(s),i.length&&this.moveNodes(i),t.length&&this.insertNodes(t),this.updateAllItems(e),this.cache.listHtmlTemplate=e}}class U{constructor(e){c(this,"renderer"),this.commentNode=e,this.renderer=new Q(e)}setValue(e){this.renderer.render(e)}}class Y{constructor(e){c(this,"node",document.createTextNode("")),this.commentNode=e,e.before(this.node)}setValue(e){const s=e!=null?String(e):"";this.node.textContent!==s&&(this.node.textContent=s)}}class z{constructor(e){c(this,"cache",{nodes:[]}),this.commentNode=e}removeNodes(){if(!this.cache.nodes.length)return;const e=this.cache.nodes.length;for(let s=0;s<e;s++)this.cache.nodes[s].remove();this.cache.nodes=[]}render(e){this.cache.strings!==e.strings&&(this.cache.fragment=void 0,this.removeNodes()),this.cache.fragment||(this.cache.fragment=new w(e),this.cache.strings=e.strings,this.cache.nodes=this.cache.fragment.mountTemplate(this.commentNode,e.values)),this.cache.fragment.update(e.values)}}class Z{constructor(e){c(this,"renderer"),this.commentNode=e,this.renderer=new z(e)}setValue(e){this.renderer.render(e)}}const J=(r,e)=>Array.isArray(r)?new U(e):r instanceof y?new Z(e):new Y(e);class w{constructor(e){c(this,"holes",new Map),c(this,"htmlString",""),c(this,"attributeMap",[]),this.parse(e.strings)}parse(e){const s=e.length;for(let t=0;t<s;t++)if(this.htmlString+=e[t],t<e.length-1){const i=F(this.htmlString,t);i&&this.attributeMap.push(i),this.htmlString+=l.makeMarkerComment(t)}this.htmlString=l.fixSelfClosingTags(this.htmlString),this.htmlString=l.fixAttributeQuotes(this.htmlString)}initFragment(){const e=document.createElement("template");return e.innerHTML=this.htmlString,e.content}hydrateAttributes(e){const s=this.attributeMap.length;for(let t=0;t<s;t++){const i=K(e,this.attributeMap[t]);i&&this.holes.set(this.attributeMap[t].index,i)}return e}hydrateTemplateHoles(e,s){var t;const i=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT,null);for(;i.nextNode();){const n=i.currentNode;if((t=n.nodeValue)!=null&&t.includes(l.TEMPLATE_MARKER_GLYPH)){const a=l.getIndexFromComment(n.nodeValue),h=J(s[a],n);this.holes.set(a,h)}}return e}mount(e,s){const t=this.initFragment();this.hydrateTemplateHoles(t,s),this.hydrateAttributes(t),e.appendChild(t)}mountTemplate(e,s){const t=this.initFragment();this.hydrateTemplateHoles(t,s),this.hydrateAttributes(t);const i=Array.from(t.childNodes);return e.before(t),i}mountListElement(e,s,t,i,n){const a=this.initFragment();this.hydrateTemplateHoles(a,t),this.hydrateAttributes(a),n?n.before(a):e.before(a);const h=n?n.previousSibling:e.previousSibling;h&&i&&i.listNodes.set(s,h)}update(e){for(const[s,t]of this.holes)t.setValue(e[s])}}const X=(r,...e)=>new y(r,e),ee=(r,e)=>{if(!e)throw new Error("render method needs to accept instance of HTMLElement");const s=T(e);let t=s.template.get(r.strings);t||(t=new w(r),s.template.set(r.strings,t),t.mount(e,r.values)),t.update(r.values)};m.html=X,m.render=ee})(R)),R}var ne=ie();const H=new Map,re=(m,u)=>{const p=u.parameters?.elemix??{};if(p.setup&&!H.has(u.id)){const y=p.setup(u);H.set(u.id,y)}const c=document.createElement("div");c.setAttribute("data-elemix-root","");const l=document.getElementById("storybook-root")??document.body;l.innerHTML="",l.appendChild(c),p.beforeRender?.(u);const T=m(u);return ne.render(T,c),p.afterRender?.(u),c};exports.elemixDecorator=re;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HtmlTemplate } from '@neuralfog/elemix-renderer';
|
|
2
|
+
import type { StoryContext, Parameters, Meta } from '@storybook/web-components-vite';
|
|
3
|
+
export type ElemixTeardown = () => void;
|
|
4
|
+
export type ElemixParams<TArgs = Record<string, never>> = {
|
|
5
|
+
setup?: (ctx: StoryContext<TArgs>) => ElemixTeardown | undefined;
|
|
6
|
+
beforeRender?: (ctx: StoryContext<TArgs>) => void;
|
|
7
|
+
afterRender?: (ctx: StoryContext<TArgs>) => void;
|
|
8
|
+
};
|
|
9
|
+
export type ElemixStoryParameters<TArgs = Record<string, never>> = Parameters & {
|
|
10
|
+
elemix?: ElemixParams<TArgs>;
|
|
11
|
+
};
|
|
12
|
+
export type ElemixStoryFn<TArgs = Record<string, never>> = (args: TArgs, context: StoryContext<TArgs>) => HtmlTemplate;
|
|
13
|
+
export type ElemixStory<TArgs = Record<string, never>> = {
|
|
14
|
+
render: ElemixStoryFn<TArgs>;
|
|
15
|
+
args?: Partial<TArgs>;
|
|
16
|
+
argTypes?: Record<string, unknown>;
|
|
17
|
+
parameters?: ElemixStoryParameters<TArgs>;
|
|
18
|
+
};
|
|
19
|
+
export type ElemixMeta<TArgs = Record<string, never>> = Omit<Meta<TArgs>, 'parameters'> & {
|
|
20
|
+
parameters?: Parameters & {
|
|
21
|
+
elemix?: ElemixParams<TArgs>;
|
|
22
|
+
};
|
|
23
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@neuralfog/elemix-storybook",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"author": "brownhounds",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": ["./dist/**/*"],
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"clean": "rm -rf ./dist",
|
|
14
|
+
"emit-declarations": "tsc --emitDeclarationOnly --declaration --outDir ./dist",
|
|
15
|
+
"build-lib": "vite build",
|
|
16
|
+
"build": "npm run clean && npm run build-lib && npm run emit-declarations",
|
|
17
|
+
"storybook": "storybook dev -p 6006",
|
|
18
|
+
"build-storybook": "storybook build",
|
|
19
|
+
"lint": "tsc --noEmit && biome format && biome lint",
|
|
20
|
+
"lint:fix": "biome format --write . && biome lint --write . && tsc --noEmit",
|
|
21
|
+
"test": "vitest",
|
|
22
|
+
"test:watch": "vitest --watch",
|
|
23
|
+
"test:coverage": "vitest run --coverage",
|
|
24
|
+
"release": "npm run clean && npm run build && npm publish --access public"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@chromatic-com/storybook": "5.0.0",
|
|
28
|
+
"@neuralfog/biome-config": "0.1.2",
|
|
29
|
+
"@neuralfog/elemix": "0.1.8",
|
|
30
|
+
"@neuralfog/elemix-renderer": "0.1.8",
|
|
31
|
+
"@neuralfog/ts-config": "0.1.2",
|
|
32
|
+
"@storybook/addon-a11y": "10.2.1",
|
|
33
|
+
"@storybook/addon-docs": "10.2.1",
|
|
34
|
+
"@storybook/addon-vitest": "10.2.1",
|
|
35
|
+
"@storybook/web-components-vite": "10.2.1",
|
|
36
|
+
"@types/node": "25.1.0",
|
|
37
|
+
"@vitest/browser-playwright": "4.0.18",
|
|
38
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
39
|
+
"playwright": "1.58.0",
|
|
40
|
+
"storybook": "10.2.1",
|
|
41
|
+
"typescript": "5.9.3",
|
|
42
|
+
"vitest": "4.0.18"
|
|
43
|
+
}
|
|
44
|
+
}
|