@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 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
@@ -0,0 +1,2 @@
1
+ export { elemixDecorator } from './src/elemixDecorator';
2
+ export * from './src/elemixStory';
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,2 @@
1
+ import type { Decorator } from '@storybook/web-components-vite';
2
+ export declare const elemixDecorator: Decorator;
@@ -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
+ }