rip-lang 3.13.71 → 3.13.73
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 +1 -1
- package/docs/dist/rip.js +25 -2
- package/docs/dist/rip.min.js +2 -2
- package/docs/dist/rip.min.js.br +0 -0
- package/docs/ui/alert-dialog.rip +96 -0
- package/docs/ui/badge.rip +15 -0
- package/docs/ui/breadcrumb.rip +46 -0
- package/docs/ui/button-group.rip +26 -0
- package/docs/ui/card.rip +25 -0
- package/docs/ui/carousel.rip +110 -0
- package/docs/ui/collapsible.rip +50 -0
- package/docs/ui/hljs-rip.js +209 -0
- package/docs/ui/index.css +412 -19
- package/docs/ui/index.html +690 -354
- package/docs/ui/input-group.rip +28 -0
- package/docs/ui/label.rip +16 -0
- package/docs/ui/native-select.rip +32 -0
- package/docs/ui/pagination.rip +123 -0
- package/docs/ui/resizable.rip +123 -0
- package/docs/ui/skeleton.rip +22 -0
- package/docs/ui/spinner.rip +17 -0
- package/docs/ui/table.rip +27 -0
- package/docs/ui/textarea.rip +48 -0
- package/package.json +1 -1
- package/src/browser.js +23 -0
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.13.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.13.73-blue.svg" alt="Version"></a>
|
|
13
13
|
<a href="#zero-dependencies"><img src="https://img.shields.io/badge/dependencies-ZERO-brightgreen.svg" alt="Dependencies"></a>
|
|
14
14
|
<a href="#"><img src="https://img.shields.io/badge/tests-1%2C436%2F1%2C436-brightgreen.svg" alt="Tests"></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
package/docs/dist/rip.js
CHANGED
|
@@ -8751,8 +8751,8 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
|
|
|
8751
8751
|
return new CodeGenerator({}).getComponentRuntime();
|
|
8752
8752
|
}
|
|
8753
8753
|
// src/browser.js
|
|
8754
|
-
var VERSION = "3.13.
|
|
8755
|
-
var BUILD_DATE = "2026-03-02@
|
|
8754
|
+
var VERSION = "3.13.72";
|
|
8755
|
+
var BUILD_DATE = "2026-03-02@17:47:10GMT";
|
|
8756
8756
|
if (typeof globalThis !== "undefined") {
|
|
8757
8757
|
if (!globalThis.__rip)
|
|
8758
8758
|
new Function(getReactiveRuntime())();
|
|
@@ -8856,6 +8856,29 @@ ${c.js}
|
|
|
8856
8856
|
await ui.launch("", opts);
|
|
8857
8857
|
}
|
|
8858
8858
|
}
|
|
8859
|
+
if (runtimeTag?.hasAttribute("data-reload")) {
|
|
8860
|
+
let ready = false;
|
|
8861
|
+
const es = new EventSource("/watch");
|
|
8862
|
+
es.addEventListener("connected", () => {
|
|
8863
|
+
if (ready)
|
|
8864
|
+
location.reload();
|
|
8865
|
+
ready = true;
|
|
8866
|
+
});
|
|
8867
|
+
es.addEventListener("reload", (e) => {
|
|
8868
|
+
if (e.data === "styles") {
|
|
8869
|
+
const t = Date.now();
|
|
8870
|
+
document.querySelectorAll('link[rel="stylesheet"]').forEach((l) => {
|
|
8871
|
+
if (new URL(l.href).origin !== location.origin)
|
|
8872
|
+
return;
|
|
8873
|
+
const url = new URL(l.href);
|
|
8874
|
+
url.searchParams.set("_r", t);
|
|
8875
|
+
l.href = url.toString();
|
|
8876
|
+
});
|
|
8877
|
+
} else {
|
|
8878
|
+
location.reload();
|
|
8879
|
+
}
|
|
8880
|
+
});
|
|
8881
|
+
}
|
|
8859
8882
|
}
|
|
8860
8883
|
async function importRip(url) {
|
|
8861
8884
|
for (const [key, mod] of Object.entries(importRip.modules)) {
|
package/docs/dist/rip.min.js
CHANGED
|
@@ -718,13 +718,13 @@ globalThis.sleep ??= (ms) => new Promise(r => setTimeout(r, ms));
|
|
|
718
718
|
globalThis.todo ??= (msg) => { throw new Error(msg || "Not implemented"); };
|
|
719
719
|
globalThis.warn ??= console.warn;
|
|
720
720
|
globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
|
|
721
|
-
`}function z1(){return new l({}).getReactiveRuntime()}function K1(){return new l({}).getComponentRuntime()}var D2="3.13.
|
|
721
|
+
`}function z1(){return new l({}).getReactiveRuntime()}function K1(){return new l({}).getComponentRuntime()}var D2="3.13.72",M2="2026-03-02@17:47:10GMT";if(typeof globalThis<"u"){if(!globalThis.__rip)Function(z1())();if(!globalThis.__ripComponent)Function(K1())()}var x3=($)=>{let U=$.match(/^[ \t]*(?=\S)/gm),F=Math.min(...(U||[]).map((W)=>W.length));return $.replace(RegExp(`^[ ]{${F}}`,"gm"),"").trim()};async function H2(){let $=[],U=document.querySelector('script[src$="rip.min.js"], script[src$="rip.js"]'),F=U?.getAttribute("data-src");if(F){for(let u of F.trim().split(/\s+/))if(u)$.push({url:u})}for(let u of document.querySelectorAll('script[type="text/rip"]'))if(u.src)$.push({url:u.src});else{let f=x3(u.textContent);if(f)$.push({code:f})}if($.length>0){await Promise.all($.map(async(Y)=>{if(!Y.url)return;try{let A=await fetch(Y.url);if(!A.ok){console.error(`Rip: failed to fetch ${Y.url} (${A.status})`);return}Y.code=await A.text()}catch(A){console.error(`Rip: failed to fetch ${Y.url}:`,A.message)}}));let u={skipRuntimes:!0,skipExports:!0},f=[];for(let Y of $){if(!Y.code)continue;try{let A=t(Y.code,u);f.push({js:A,url:Y.url||"inline"})}catch(A){console.error(`Rip compile error in ${Y.url||"inline"}:`,A.message)}}if(f.length>0){let Y=f.map((_)=>_.js).join(`
|
|
722
722
|
`),A=U?.getAttribute("data-mount");if(A){let _=U.getAttribute("data-target")||"body";Y+=`
|
|
723
723
|
${A}.mount(${JSON.stringify(_)});`}try{await(0,eval)(`(async()=>{
|
|
724
724
|
${Y}
|
|
725
725
|
})()`)}catch(_){if(_ instanceof SyntaxError){console.error(`Rip syntax error in combined output: ${_.message}`);for(let Z of f)try{Function(`(async()=>{
|
|
726
726
|
${Z.js}
|
|
727
|
-
})()`)}catch(R){console.error(` → source: ${Z.url}`,R.message)}}else console.error("Rip runtime error:",_)}}}let W=document.querySelector("script[data-launch]");if(W&&!globalThis.__ripLaunched){let u=$1.modules?.["ui.rip"];if(u?.launch){let f=W.getAttribute("data-launch")||"",Y=W.getAttribute("data-hash"),A=W.getAttribute("data-persist"),_={hash:Y!=="false"};if(f)_.bundleUrl=f;if(A!=null)_.persist=A==="local"?"local":!0;await u.launch("",_)}}}async function $1($){for(let[Y,A]of Object.entries($1.modules))if($.includes(Y))return A;let U=await fetch($).then((Y)=>{if(!Y.ok)throw Error(`importRip: ${$} (${Y.status})`);return Y.text()}),F=t(U),W=`// ${$}
|
|
727
|
+
})()`)}catch(R){console.error(` → source: ${Z.url}`,R.message)}}else console.error("Rip runtime error:",_)}}}let W=document.querySelector("script[data-launch]");if(W&&!globalThis.__ripLaunched){let u=$1.modules?.["ui.rip"];if(u?.launch){let f=W.getAttribute("data-launch")||"",Y=W.getAttribute("data-hash"),A=W.getAttribute("data-persist"),_={hash:Y!=="false"};if(f)_.bundleUrl=f;if(A!=null)_.persist=A==="local"?"local":!0;await u.launch("",_)}}if(U?.hasAttribute("data-reload")){let u=!1,f=new EventSource("/watch");f.addEventListener("connected",()=>{if(u)location.reload();u=!0}),f.addEventListener("reload",(Y)=>{if(Y.data==="styles"){let A=Date.now();document.querySelectorAll('link[rel="stylesheet"]').forEach((_)=>{if(new URL(_.href).origin!==location.origin)return;let Z=new URL(_.href);Z.searchParams.set("_r",A),_.href=Z.toString()})}else location.reload()})}}async function $1($){for(let[Y,A]of Object.entries($1.modules))if($.includes(Y))return A;let U=await fetch($).then((Y)=>{if(!Y.ok)throw Error(`importRip: ${$} (${Y.status})`);return Y.text()}),F=t(U),W=`// ${$}
|
|
728
728
|
`,u=new Blob([W+F],{type:"application/javascript"});return await import(URL.createObjectURL(u))}$1.modules={};function q2($){try{let U=$.replace(/^/gm," "),W=t(`do ->
|
|
729
729
|
${U}`).replace(/^let\s+[^;]+;\s*\n\s*/m,"");W=W.replace(/^const\s+(\w+)\s*=/gm,"globalThis.$1 =");let u=(0,eval)(W);if(u&&typeof u.then==="function")return u.then((f)=>{if(f!==void 0)globalThis._=f;return f});if(u!==void 0)globalThis._=u;return u}catch(U){console.error("Rip compilation error:",U.message);return}}if(typeof globalThis<"u")globalThis.rip=q2,globalThis.importRip=$1,globalThis.compileToJS=t,globalThis.__ripExports={compile:I1,compileToJS:t,formatSExpr:d,getStdlibCode:X1,VERSION:D2,BUILD_DATE:M2,getReactiveRuntime:z1,getComponentRuntime:K1};if(typeof document<"u")globalThis.__ripScriptsReady=new Promise(($)=>{let U=()=>H2().then($);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",()=>queueMicrotask(U));else queueMicrotask(U)});var T1={};t1(T1,{throttle:()=>n3,stash:()=>c2,setContext:()=>j2,raw:()=>g2,launch:()=>d3,isStash:()=>k3,hold:()=>p3,hasContext:()=>S2,getContext:()=>T2,delay:()=>v2,debounce:()=>i3,createRouter:()=>x2,createResource:()=>m3,createRenderer:()=>k2,createComponents:()=>l2});var O2,i1,_1,e,N1,G2,U1,g,x1,M1,H1,n1,P2,I2,E1,B1,E2,B2,N2,k1,m1,T2,L2,p1,S2,D1,d1,h2,V2,j2,C2,y2,r1,b2;globalThis.abort??=($)=>{if($)console.error($);process.exit(1)};globalThis.assert??=($,U)=>{if(!$)throw Error(U||"Assertion failed")};globalThis.exit??=($)=>process.exit($||0);globalThis.kind??=($)=>$!=null?($.constructor?.name||Object.prototype.toString.call($).slice(8,-1)).toLowerCase():String($);globalThis.noop??=()=>{};globalThis.p??=console.log;globalThis.pp??=($)=>{return console.log(JSON.stringify($,null,2)),$};globalThis.raise??=($,U)=>{throw U!==void 0?new $(U):Error($)};globalThis.rand??=($,U)=>U!==void 0?($>U&&([$,U]=[U,$]),Math.floor(Math.random()*(U-$+1)+$)):$?Math.floor(Math.random()*$):Math.random();globalThis.sleep??=($)=>new Promise((U)=>setTimeout(U,$));globalThis.todo??=($)=>{throw Error($||"Not implemented")};globalThis.warn??=console.warn;globalThis.zip??=(...$)=>$[0].map((U,F)=>$.map((W)=>W[F]));({__state:g,__effect:U1,__batch:G2}=globalThis.__rip);({setContext:j2,getContext:T2,hasContext:S2}=globalThis.__ripComponent||{});N1=Symbol("stash");e=Symbol("signals");_1=Symbol("raw");i1=new WeakMap;x1=0;n1=g(0);p1=function($,U){let F;if(!$[e])Object.defineProperty($,e,{value:new Map,enumerable:!1});if(F=$[e].get(U),!F)F=g($[U]),$[e].set(U,F);return F};D1=function($){return p1($,Symbol.for("keys"))};b2=function($){let U;if(!($!=null&&typeof $==="object"))return $;if($[N1])return $;if($ instanceof Date||$ instanceof RegExp||$ instanceof Map||$ instanceof Set||$ instanceof Promise)return $;if(U=i1.get($),U)return U;return d1($)};d1=function($){let U,F;return F=null,U={get:function(W,u){let f,Y;if(u===N1)return!0;if(u===_1)return W;if(typeof u==="symbol")return Reflect.get(W,u);if(u==="length"&&Array.isArray(W))return D1(W).value,W.length;if(u==="get")return function(A){return C2(F,A)};if(u==="set")return function(A,_){return y2(F,A,_)};if(f=p1(W,u),Y=f.value,Y!=null&&typeof Y==="object")return b2(Y);return Y},set:function(W,u,f){let Y,A;if(Y=W[u],A=f?.[_1]?f[_1]:f,A===Y)return!0;if(W[u]=A,W[e]?.has(u))W[e].get(u).value=A;if(Y===void 0&&A!==void 0)D1(W).value=++x1;return n1.value++,!0},deleteProperty:function(W,u){let f;if(delete W[u],f=W[e]?.get(u),f!=null)f.value=void 0;return D1(W).value=++x1,!0},ownKeys:function(W){return D1(W).value,Reflect.ownKeys(W)}},F=new Proxy($,U),i1.set($,F),F};O2=/([./][^./\[\s]+|\[[-+]?\d+\]|\[(?:"[^"]+"|'[^']+')\])/;r1=function($){let U,F,W,u,f;W=("."+$).split(O2),W.shift(),f=[],F=0;while(F<W.length){if(u=W[F],U=u[0],U==="."||U==="/")f.push(u.slice(1));else if(U==="[")if(u[1]==='"'||u[1]==="'")f.push(u.slice(2,-2));else f.push(+u.slice(1,-1));F+=2}return f};C2=function($,U){let F,W;W=r1(U),F=$;for(let u of W){if(F==null)return;F=F[u]}return F};y2=function($,U,F){let W,u;u=r1(U),W=$;for(let f=0;f<u.length;f++){let Y=u[f];if(f===u.length-1)W[Y]=F;else{if(W[Y]==null)W[Y]={};W=W[Y]}}return F};var c2=function($={}){return d1($)},g2=function($){return $?.[_1]?$[_1]:$},k3=function($){return $?.[N1]===!0},m3=function($,U={}){let F,W,u,f,Y;if(F=g(U.initial||null),u=g(!1),W=g(null),f=async function(){let A;return u.value=!0,W.value=null,(async()=>{try{return A=await $(),F.value=A}catch(_){return W.value=_}finally{u.value=!1}})()},Y={data:void 0,loading:void 0,error:void 0,refetch:f},Object.defineProperty(Y,"data",{get:function(){return F.value}}),Object.defineProperty(Y,"loading",{get:function(){return u.value}}),Object.defineProperty(Y,"error",{get:function(){return W.value}}),!U.lazy)f();return Y};H1=function($){return typeof $==="function"?$:function(){return $.value}};M1=function($,U){let F;return F={read:function(){return $.read()}},Object.defineProperty(F,"value",{get:function(){return $.value},set:function(W){return U.value=W}}),F};var v2=function($,U){let F,W;return F=H1(U),W=g(!!F()),U1(function(){let u;if(F())return u=setTimeout(function(){return W.value=!0},$),function(){return clearTimeout(u)};else return W.value=!1}),typeof U!=="function"?M1(W,U):W},i3=function($,U){let F,W;return F=H1(U),W=g(F()),U1(function(){let u,f;return f=F(),u=setTimeout(function(){return W.value=f},$),function(){return clearTimeout(u)}}),typeof U!=="function"?M1(W,U):W},n3=function($,U){let F,W,u;return F=H1(U),u=g(F()),W=0,U1(function(){let f,Y,A,_;if(_=F(),f=Date.now(),Y=$-(f-W),Y<=0)return u.value=_,W=f;else return A=setTimeout(function(){return u.value=F(),W=Date.now()},Y),function(){return clearTimeout(A)}}),typeof U!=="function"?M1(u,U):u},p3=function($,U){let F,W;return F=H1(U),W=g(!!F()),U1(function(){let u;if(F())return W.value=!0;else return u=setTimeout(function(){return W.value=!1},$),function(){return clearTimeout(u)}}),typeof U!=="function"?M1(W,U):W},l2=function(){let $,U,F,W;return U=new Map,W=[],$=new Map,F=function(u,f){for(let Y of W)Y(u,f)},{read:function(u){return U.get(u)},write:function(u,f){let Y;return Y=!U.has(u),U.set(u,f),$.delete(u),F(Y?"create":"change",u)},del:function(u){return U.delete(u),$.delete(u),F("delete",u)},exists:function(u){return U.has(u)},size:function(){return U.size},list:function(u=""){let f,Y,A;A=[],f=u?u+"/":"";for(let[_]of U)if(_.startsWith(f)){if(Y=_.slice(f.length),Y.includes("/"))continue;A.push(_)}return A},listAll:function(u=""){let f,Y;Y=[],f=u?u+"/":"";for(let[A]of U)if(A.startsWith(f))Y.push(A);return Y},load:function(u){for(let f in u){let Y=u[f];U.set(f,Y)}},watch:function(u){return W.push(u),function(){return W.splice(W.indexOf(u),1)}},getCompiled:function(u){return $.get(u)},setCompiled:function(u,f){return $.set(u,f)}}};N2=function($){let U;if(U=$.replace(/\.rip$/,""),U=U.replace(/\[\.\.\.(\w+)\]/g,"*$1"),U=U.replace(/\[(\w+)\]/g,":$1"),U==="index")return"/";return U=U.replace(/\/index$/,""),"/"+U};V2=function($){let U,F;return U=[],F=$.replace(/\*(\w+)/g,function(W,u){return U.push(u),"(.+)"}).replace(/:(\w+)/g,function(W,u){return U.push(u),"([^/]+)"}),{regex:new RegExp("^"+F+"$"),names:U}};h2=function($,U){let F,W;for(let u of U)if(F=$.match(u.regex.regex),F){W={};for(let f=0;f<u.regex.names.length;f++){let Y=u.regex.names[f];W[Y]=decodeURIComponent(F[f+1])}return{route:u,params:W}}return null};E1=function($,U="components"){let F,W,u,f,Y,A,_,Z,R;_=[],u=new Map,F=$.listAll(U);for(let Q of F){if(A=Q.slice(U.length+1),!A.endsWith(".rip"))continue;if(f=A.split("/").pop(),f==="_layout.rip"){W=A==="_layout.rip"?"":A.slice(0,-12),u.set(W,Q);continue}if(f.startsWith("_"))continue;if(Z=A.split("/"),Z.length>1&&Z.some(function(z,J){return J<Z.length-1&&z.startsWith("_")}))continue;R=N2(A),Y=V2(R),_.push({pattern:R,regex:Y,file:Q,rel:A})}return _.sort(function(Q,z){let J,D,M,X;if(D=(Q.pattern.match(/:/g)||[]).length,X=(z.pattern.match(/:/g)||[]).length,J=Q.pattern.includes("*")?1:0,M=z.pattern.includes("*")?1:0,J!==M)return J-M;if(D!==X)return D-X;return Q.pattern.localeCompare(z.pattern)}),{routes:_,layouts:u}};L2=function($,U,F){let W,u,f,Y;if(W=[],f=$.slice(U.length+1),Y=f.split("/"),u="",F.has(""))W.push(F.get(""));for(let A=0;A<Y.length;A++){let _=Y[A];if(A===Y.length-1)break;if(u=u?u+"/"+_:_,F.has(u))W.push(F.get(u))}return W};var x2=function($,U={}){let F,W,u,f,Y,A,_,Z,R,Q,z,J,D,M,X,w,K,q,O,P,G;if(K=U.root||"components",R=U.base||"",Q=U.hash||!1,D=U.onError||null,O=function(H){return R&&H.startsWith(R)?H.slice(R.length)||"/":H},Z=function(H){return R?R+H:H},X=function(){let H;if(Q){if(H=location.hash.slice(1),!H)return"/";return H[0]==="/"?H:"/"+H}else return location.pathname+location.search+location.hash},G=function(H){return Q?H==="/"?location.pathname:"#"+H.slice(1):Z(H)},Y=g(O(Q?X():location.pathname)),f=g({}),_=g(null),W=g([]),A=g({}),F=g(""),u=v2(100,g(!1)),P=E1($,K),z=new Set,$.watch(function(H,I){if(!I.startsWith(K+"/"))return;return P=E1($,K)}),w=function(H){let I,E,N,B,T;if(B=H.split("?")[0].split("#")[0],E=O(B),E=E[0]==="/"?E:"/"+E,N=H.split("?")[1]?.split("#")[0]||"",I=H.includes("#")?H.split("#")[1]:"",T=h2(E,P.routes),T){G2(function(){return Y.value=E,f.value=T.params,_.value=T.route,W.value=L2(T.route.file,K,P.layouts),A.value=Object.fromEntries(new URLSearchParams(N)),F.value=I});for(let C of z)C(q.current);return!0}if(D)D({status:404,path:E});return!1},M=function(){return w(X())},typeof window<"u")window.addEventListener("popstate",M);if(J=function(H){let I,E,N;if(H.button!==0||H.metaKey||H.ctrlKey||H.shiftKey||H.altKey)return;E=H.target;while(E&&E.tagName!=="A")E=E.parentElement;if(!E?.href)return;if(N=new URL(E.href,location.origin),N.origin!==location.origin)return;if(E.target==="_blank"||E.hasAttribute("data-external"))return;return H.preventDefault(),I=Q&&N.hash?N.hash.slice(1)||"/":N.pathname+N.search+N.hash,q.push(I)},typeof document<"u")document.addEventListener("click",J);return q={push:function(H){return w(H)?history.pushState(null,"",G(Y.read())):void 0},replace:function(H){return w(H)?history.replaceState(null,"",G(Y.read())):void 0},back:function(){return history.back()},forward:function(){return history.forward()},current:void 0,path:void 0,params:void 0,route:void 0,layouts:void 0,query:void 0,hash:void 0,navigating:void 0,onNavigate:function(H){return z.add(H),function(){return z.delete(H)}},rebuild:function(){return P=E1($,K)},routes:void 0,init:function(){return w(X()),q},destroy:function(){if(typeof window<"u")window.removeEventListener("popstate",M);if(typeof document<"u")document.removeEventListener("click",J);return z.clear()}},Object.defineProperty(q,"current",{get:function(){return{path:Y.value,params:f.value,route:_.value,layouts:W.value,query:A.value,hash:F.value}}}),Object.defineProperty(q,"path",{get:function(){return Y.value}}),Object.defineProperty(q,"params",{get:function(){return f.value}}),Object.defineProperty(q,"route",{get:function(){return _.value}}),Object.defineProperty(q,"layouts",{get:function(){return W.value}}),Object.defineProperty(q,"query",{get:function(){return A.value}}),Object.defineProperty(q,"hash",{get:function(){return F.value}}),Object.defineProperty(q,"navigating",{get:function(){return u.value},set:function(H){return u.value=H}}),Object.defineProperty(q,"routes",{get:function(){return P.routes}}),q};P2=function($,U){if($.length!==U.length)return!1;for(let F=0;F<$.length;F++)if($[F]!==U[F])return!1;return!0};m1=function($){for(let U in $){let F=$[U];if(typeof F==="function"&&(F.prototype?.mount||F.prototype?._create))return F}return typeof $.default==="function"?$.default:void 0};k1=function($){let U;U={};for(let F in $){let W=$[F];if(typeof W==="function"&&(W.prototype?.mount||W.prototype?._create))U[F]=W}return U};B2=function($){let U;return U=$.split("/").pop().replace(/\.rip$/,""),U.replace(/(^|[-_])([a-z])/g,function(F,W,u){return u.toUpperCase()})};I2=function($,U="components"){let F,W,u;W={};for(let f of $.listAll(U)){if(!f.endsWith(".rip"))continue;if(F=f.split("/").pop(),F.startsWith("_"))continue;if(u=B2(f),W[u])console.warn(`[Rip] Component name collision: ${u} (${W[u]} vs ${f})`);W[u]=f}return W};B1=async function($,U,F=null,W=null,u=null){let f,Y,A,_,Z,R,Q,z,J,D,M,X;if(F&&W){if(Y=F.getCompiled(W),Y)return Y}if(Q=U($),u){D={};for(let w in u.map){let K=u.map[w];if(K!==W&&Q.includes(`new ${w}(`)){if(!u.classes[w]){if(_=F.read(K),_){A=await B1(_,U,F,K,u),Z=k1(A);for(let q in Z){let O=Z[q];u.classes[q]=O}}}if(u.classes[w])D[w]=!0}}if(J=Object.keys(D),J.length>0)M=`const {${J.join(", ")}} = globalThis['${u.key}'];
|
|
730
730
|
`,Q=M+Q}if(R=W?`// ${W}
|
package/docs/dist/rip.min.js.br
CHANGED
|
Binary file
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# AlertDialog — accessible headless non-dismissable modal
|
|
2
|
+
#
|
|
3
|
+
# A Dialog variant that requires explicit user action to close.
|
|
4
|
+
# Cannot be dismissed by clicking outside or pressing Escape.
|
|
5
|
+
# Use for destructive confirmations, unsaved changes, etc.
|
|
6
|
+
# Ships zero CSS.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# AlertDialog open <=> showConfirm
|
|
10
|
+
# h2 "Delete account?"
|
|
11
|
+
# p "This action cannot be undone."
|
|
12
|
+
# button @click: (=> showConfirm = false), "Cancel"
|
|
13
|
+
# button @click: handleDelete, "Delete"
|
|
14
|
+
|
|
15
|
+
alertDialogStack = []
|
|
16
|
+
|
|
17
|
+
export AlertDialog = component
|
|
18
|
+
@open := false
|
|
19
|
+
@initialFocus := null
|
|
20
|
+
|
|
21
|
+
_prevFocus = null
|
|
22
|
+
_cleanupTrap = null
|
|
23
|
+
_scrollY = 0
|
|
24
|
+
_id =! "adlg-#{Math.random().toString(36).slice(2, 8)}"
|
|
25
|
+
|
|
26
|
+
_wireAria: ->
|
|
27
|
+
panel = @_panel
|
|
28
|
+
return unless panel
|
|
29
|
+
heading = panel.querySelector('h1,h2,h3,h4,h5,h6')
|
|
30
|
+
if heading
|
|
31
|
+
heading.id ?= "#{_id}-title"
|
|
32
|
+
panel.setAttribute 'aria-labelledby', heading.id
|
|
33
|
+
desc = panel.querySelector('p')
|
|
34
|
+
if desc
|
|
35
|
+
desc.id ?= "#{_id}-desc"
|
|
36
|
+
panel.setAttribute 'aria-describedby', desc.id
|
|
37
|
+
|
|
38
|
+
~>
|
|
39
|
+
if @open
|
|
40
|
+
_prevFocus = document.activeElement
|
|
41
|
+
_scrollY = window.scrollY
|
|
42
|
+
alertDialogStack.push this
|
|
43
|
+
document.body.style.position = 'fixed'
|
|
44
|
+
document.body.style.top = "-#{_scrollY}px"
|
|
45
|
+
document.body.style.width = '100%'
|
|
46
|
+
|
|
47
|
+
setTimeout =>
|
|
48
|
+
panel = @_panel
|
|
49
|
+
if panel
|
|
50
|
+
@_wireAria()
|
|
51
|
+
if @initialFocus
|
|
52
|
+
target = if typeof @initialFocus is 'string' then panel.querySelector(@initialFocus) else @initialFocus
|
|
53
|
+
target?.focus()
|
|
54
|
+
else
|
|
55
|
+
focusable = panel.querySelectorAll 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])'
|
|
56
|
+
focusable[0]?.focus()
|
|
57
|
+
_cleanupTrap = (e) ->
|
|
58
|
+
return unless e.key is 'Tab'
|
|
59
|
+
list = Array.from(panel.querySelectorAll('a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])')).filter (f) -> f.offsetParent isnt null
|
|
60
|
+
return unless list.length
|
|
61
|
+
first = list[0]
|
|
62
|
+
last = list[list.length - 1]
|
|
63
|
+
if e.shiftKey
|
|
64
|
+
if document.activeElement is first then (e.preventDefault(); last.focus())
|
|
65
|
+
else
|
|
66
|
+
if document.activeElement is last then (e.preventDefault(); first.focus())
|
|
67
|
+
panel.addEventListener 'keydown', _cleanupTrap
|
|
68
|
+
, 0
|
|
69
|
+
|
|
70
|
+
return ->
|
|
71
|
+
idx = alertDialogStack.indexOf this
|
|
72
|
+
alertDialogStack.splice(idx, 1) if idx >= 0
|
|
73
|
+
document.body.style.position = '' unless alertDialogStack.length
|
|
74
|
+
document.body.style.top = '' unless alertDialogStack.length
|
|
75
|
+
document.body.style.width = '' unless alertDialogStack.length
|
|
76
|
+
window.scrollTo 0, _scrollY unless alertDialogStack.length
|
|
77
|
+
_prevFocus?.focus()
|
|
78
|
+
else
|
|
79
|
+
idx = alertDialogStack.indexOf this
|
|
80
|
+
alertDialogStack.splice(idx, 1) if idx >= 0
|
|
81
|
+
unless alertDialogStack.length
|
|
82
|
+
document.body.style.position = ''
|
|
83
|
+
document.body.style.top = ''
|
|
84
|
+
document.body.style.width = ''
|
|
85
|
+
window.scrollTo 0, _scrollY
|
|
86
|
+
_prevFocus?.focus()
|
|
87
|
+
|
|
88
|
+
close: ->
|
|
89
|
+
@open = false
|
|
90
|
+
@emit 'close'
|
|
91
|
+
|
|
92
|
+
render
|
|
93
|
+
if @open
|
|
94
|
+
div ref: "_backdrop", $open: true
|
|
95
|
+
div ref: "_panel", role: "alertdialog", aria-modal: "true", tabindex: "-1"
|
|
96
|
+
slot
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Badge — accessible headless inline label
|
|
2
|
+
#
|
|
3
|
+
# Decorative label for status, counts, or categories.
|
|
4
|
+
# Ships zero CSS.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# Badge "New"
|
|
8
|
+
# Badge variant: "outline", "Beta"
|
|
9
|
+
|
|
10
|
+
export Badge = component
|
|
11
|
+
@variant := 'solid'
|
|
12
|
+
|
|
13
|
+
render
|
|
14
|
+
span $variant: @variant
|
|
15
|
+
slot
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Breadcrumb — accessible headless navigation breadcrumb
|
|
2
|
+
#
|
|
3
|
+
# Renders a navigation trail with separator between items.
|
|
4
|
+
# The last item is automatically marked as the current page.
|
|
5
|
+
# Ships zero CSS.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# Breadcrumb
|
|
9
|
+
# a $item: true, href: "/", "Home"
|
|
10
|
+
# a $item: true, href: "/products", "Products"
|
|
11
|
+
# span $item: true, "Widget Pro"
|
|
12
|
+
#
|
|
13
|
+
# Breadcrumb separator: ">"
|
|
14
|
+
# a $item: true, href: "/", "Home"
|
|
15
|
+
# span $item: true, "Settings"
|
|
16
|
+
|
|
17
|
+
export Breadcrumb = component
|
|
18
|
+
@separator := '/'
|
|
19
|
+
@label := 'Breadcrumb'
|
|
20
|
+
|
|
21
|
+
_ready := false
|
|
22
|
+
|
|
23
|
+
mounted: -> _ready = true
|
|
24
|
+
|
|
25
|
+
_items ~=
|
|
26
|
+
return [] unless _ready
|
|
27
|
+
return [] unless @_content
|
|
28
|
+
Array.from(@_content.querySelectorAll('[data-item]') or [])
|
|
29
|
+
|
|
30
|
+
~>
|
|
31
|
+
return unless _ready
|
|
32
|
+
items = _items
|
|
33
|
+
return unless items.length
|
|
34
|
+
items.forEach (el, idx) =>
|
|
35
|
+
isLast = idx is items.length - 1
|
|
36
|
+
if isLast
|
|
37
|
+
el.setAttribute 'aria-current', 'page'
|
|
38
|
+
el.toggleAttribute 'data-current', true
|
|
39
|
+
else
|
|
40
|
+
el.removeAttribute 'aria-current'
|
|
41
|
+
el.removeAttribute 'data-current'
|
|
42
|
+
|
|
43
|
+
render
|
|
44
|
+
nav aria-label: @label
|
|
45
|
+
ol ref: "_content"
|
|
46
|
+
slot
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ButtonGroup — accessible headless button group
|
|
2
|
+
#
|
|
3
|
+
# Groups related buttons with proper ARIA semantics.
|
|
4
|
+
# Ships zero CSS.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ButtonGroup
|
|
8
|
+
# Button "Cut"
|
|
9
|
+
# Button "Copy"
|
|
10
|
+
# Button "Paste"
|
|
11
|
+
# ButtonGroup orientation: "vertical", label: "Text formatting"
|
|
12
|
+
# Toggle pressed <=> isBold, "Bold"
|
|
13
|
+
# Toggle pressed <=> isItalic, "Italic"
|
|
14
|
+
|
|
15
|
+
export ButtonGroup = component
|
|
16
|
+
@orientation := 'horizontal'
|
|
17
|
+
@disabled := false
|
|
18
|
+
@label := ''
|
|
19
|
+
|
|
20
|
+
render
|
|
21
|
+
div role: "group"
|
|
22
|
+
aria-label: @label?!
|
|
23
|
+
aria-orientation: @orientation
|
|
24
|
+
$orientation: @orientation
|
|
25
|
+
$disabled: @disabled?!
|
|
26
|
+
slot
|
package/docs/ui/card.rip
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Card — accessible headless content container
|
|
2
|
+
#
|
|
3
|
+
# Structured container with optional header, content, and footer sections.
|
|
4
|
+
# Use $header, $content, $footer on children to mark sections.
|
|
5
|
+
# Ships zero CSS.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# Card
|
|
9
|
+
# div $header: true
|
|
10
|
+
# h3 "Title"
|
|
11
|
+
# div $content: true
|
|
12
|
+
# p "Body text"
|
|
13
|
+
# div $footer: true
|
|
14
|
+
# Button "Action"
|
|
15
|
+
#
|
|
16
|
+
# Card interactive: true, @click: handleClick
|
|
17
|
+
# p "Clickable card"
|
|
18
|
+
|
|
19
|
+
export Card = component
|
|
20
|
+
@interactive := false
|
|
21
|
+
|
|
22
|
+
render
|
|
23
|
+
div tabindex: (if @interactive then "0" else undefined)
|
|
24
|
+
$interactive: @interactive?!
|
|
25
|
+
slot
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Carousel — accessible headless slide carousel
|
|
2
|
+
#
|
|
3
|
+
# Displays one slide at a time with arrow key navigation, optional
|
|
4
|
+
# autoplay, and loop mode. Discovers slides from [data-slide] children.
|
|
5
|
+
# Ships zero CSS.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# Carousel loop: true
|
|
9
|
+
# div $slide: true
|
|
10
|
+
# img src: "slide1.jpg"
|
|
11
|
+
# div $slide: true
|
|
12
|
+
# img src: "slide2.jpg"
|
|
13
|
+
# div $slide: true
|
|
14
|
+
# img src: "slide3.jpg"
|
|
15
|
+
#
|
|
16
|
+
# Carousel autoplay: true, interval: 5000, @change: handleSlide
|
|
17
|
+
# div $slide: true, "Slide A"
|
|
18
|
+
# div $slide: true, "Slide B"
|
|
19
|
+
|
|
20
|
+
export Carousel = component
|
|
21
|
+
@orientation := 'horizontal'
|
|
22
|
+
@loop := false
|
|
23
|
+
@autoplay := false
|
|
24
|
+
@interval := 4000
|
|
25
|
+
@label := 'Carousel'
|
|
26
|
+
|
|
27
|
+
activeIndex := 0
|
|
28
|
+
_ready := false
|
|
29
|
+
_timer = null
|
|
30
|
+
|
|
31
|
+
_slides ~=
|
|
32
|
+
return [] unless _ready
|
|
33
|
+
return [] unless @_content
|
|
34
|
+
Array.from(@_content.querySelectorAll('[data-slide]') or [])
|
|
35
|
+
|
|
36
|
+
totalSlides ~= _slides.length
|
|
37
|
+
|
|
38
|
+
mounted: ->
|
|
39
|
+
_ready = true
|
|
40
|
+
@_startAutoplay() if @autoplay
|
|
41
|
+
|
|
42
|
+
beforeUnmount: ->
|
|
43
|
+
@_stopAutoplay()
|
|
44
|
+
|
|
45
|
+
_startAutoplay: ->
|
|
46
|
+
@_stopAutoplay()
|
|
47
|
+
_timer = setInterval (=> @next()), @interval
|
|
48
|
+
|
|
49
|
+
_stopAutoplay: ->
|
|
50
|
+
clearInterval _timer if _timer
|
|
51
|
+
_timer = null
|
|
52
|
+
|
|
53
|
+
goto: (idx) ->
|
|
54
|
+
count = totalSlides
|
|
55
|
+
return unless count
|
|
56
|
+
if @loop
|
|
57
|
+
idx = idx %% count
|
|
58
|
+
else
|
|
59
|
+
idx = Math.max(0, Math.min(idx, count - 1))
|
|
60
|
+
activeIndex = idx
|
|
61
|
+
@emit 'change', activeIndex
|
|
62
|
+
|
|
63
|
+
next: -> @goto(activeIndex + 1)
|
|
64
|
+
prev: -> @goto(activeIndex - 1)
|
|
65
|
+
|
|
66
|
+
onKeydown: (e) ->
|
|
67
|
+
horiz = @orientation is 'horizontal'
|
|
68
|
+
switch e.key
|
|
69
|
+
when (if horiz then 'ArrowRight' else 'ArrowDown')
|
|
70
|
+
e.preventDefault()
|
|
71
|
+
@next()
|
|
72
|
+
when (if horiz then 'ArrowLeft' else 'ArrowUp')
|
|
73
|
+
e.preventDefault()
|
|
74
|
+
@prev()
|
|
75
|
+
when 'Home'
|
|
76
|
+
e.preventDefault()
|
|
77
|
+
@goto(0)
|
|
78
|
+
when 'End'
|
|
79
|
+
e.preventDefault()
|
|
80
|
+
@goto(totalSlides - 1)
|
|
81
|
+
|
|
82
|
+
~>
|
|
83
|
+
return unless _ready
|
|
84
|
+
_slides.forEach (el, idx) =>
|
|
85
|
+
isActive = idx is activeIndex
|
|
86
|
+
el.hidden = not isActive
|
|
87
|
+
el.toggleAttribute 'data-active', isActive
|
|
88
|
+
el.setAttribute 'role', 'tabpanel'
|
|
89
|
+
el.setAttribute 'aria-roledescription', 'slide'
|
|
90
|
+
el.setAttribute 'aria-label', "Slide #{idx + 1} of #{totalSlides}"
|
|
91
|
+
|
|
92
|
+
onMouseenter: -> @_stopAutoplay() if @autoplay
|
|
93
|
+
onMouseleave: -> @_startAutoplay() if @autoplay
|
|
94
|
+
|
|
95
|
+
render
|
|
96
|
+
div role: "region", aria-roledescription: "carousel", aria-label: @label, tabindex: "0"
|
|
97
|
+
$orientation: @orientation
|
|
98
|
+
@keydown: @onKeydown
|
|
99
|
+
@mouseenter: @onMouseenter
|
|
100
|
+
@mouseleave: @onMouseleave
|
|
101
|
+
button $prev: true, aria-label: "Previous slide"
|
|
102
|
+
disabled: not @loop and activeIndex <= 0
|
|
103
|
+
$disabled: (not @loop and activeIndex <= 0)?!
|
|
104
|
+
@click: (=> @prev())
|
|
105
|
+
div ref: "_content"
|
|
106
|
+
slot
|
|
107
|
+
button $next: true, aria-label: "Next slide"
|
|
108
|
+
disabled: not @loop and activeIndex >= totalSlides - 1
|
|
109
|
+
$disabled: (not @loop and activeIndex >= totalSlides - 1)?!
|
|
110
|
+
@click: (=> @next())
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Collapsible — accessible headless expand/collapse section
|
|
2
|
+
#
|
|
3
|
+
# Single open/close section. Simpler than Accordion (no item IDs,
|
|
4
|
+
# no single/multiple mode). Exposes content dimensions as CSS
|
|
5
|
+
# custom properties for animated expand/collapse. Ships zero CSS.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# Collapsible open <=> isOpen
|
|
9
|
+
# button $trigger: true, "Show details"
|
|
10
|
+
# div $content: true
|
|
11
|
+
# p "Hidden content here"
|
|
12
|
+
|
|
13
|
+
export Collapsible = component
|
|
14
|
+
@open := false
|
|
15
|
+
@disabled := false
|
|
16
|
+
|
|
17
|
+
_ready := false
|
|
18
|
+
|
|
19
|
+
mounted: ->
|
|
20
|
+
_ready = true
|
|
21
|
+
trigger = @_root?.querySelector('[data-trigger]')
|
|
22
|
+
return unless trigger
|
|
23
|
+
trigger.addEventListener 'click', => @toggle() unless @disabled
|
|
24
|
+
trigger.addEventListener 'keydown', (e) =>
|
|
25
|
+
if e.key in ['Enter', ' '] and not @disabled
|
|
26
|
+
e.preventDefault()
|
|
27
|
+
@toggle()
|
|
28
|
+
|
|
29
|
+
toggle: ->
|
|
30
|
+
@open = not @open
|
|
31
|
+
@emit 'change', @open
|
|
32
|
+
|
|
33
|
+
~>
|
|
34
|
+
return unless _ready
|
|
35
|
+
trigger = @_root?.querySelector('[data-trigger]')
|
|
36
|
+
content = @_root?.querySelector('[data-content]')
|
|
37
|
+
if trigger
|
|
38
|
+
trigger.setAttribute 'aria-expanded', !!@open
|
|
39
|
+
trigger.setAttribute 'aria-disabled', true if @disabled
|
|
40
|
+
trigger.tabIndex = if @disabled then -1 else 0
|
|
41
|
+
if content
|
|
42
|
+
content.hidden = not @open
|
|
43
|
+
if @open
|
|
44
|
+
rect = content.getBoundingClientRect()
|
|
45
|
+
content.style.setProperty '--collapsible-height', "#{rect.height}px"
|
|
46
|
+
content.style.setProperty '--collapsible-width', "#{rect.width}px"
|
|
47
|
+
|
|
48
|
+
render
|
|
49
|
+
div ref: "_root", $open: @open?!, $disabled: @disabled?!
|
|
50
|
+
slot
|