@waveso/ui 0.0.7 → 0.0.9
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/dist/animate.d.ts +148 -0
- package/dist/animate.js +244 -0
- package/dist/animate.js.map +1 -0
- package/dist/{chunk-MO4KRZFJ.js → chunk-BKTJYX4M.js} +3 -3
- package/dist/{chunk-MO4KRZFJ.js.map → chunk-BKTJYX4M.js.map} +1 -1
- package/dist/combobox.js +1 -1
- package/dist/count.d.ts +73 -0
- package/dist/count.js +176 -0
- package/dist/count.js.map +1 -0
- package/dist/dialog.js +1 -1
- package/dist/drawer.js +2 -2
- package/dist/film-grain.d.ts +15 -0
- package/dist/film-grain.js +422 -0
- package/dist/film-grain.js.map +1 -0
- package/dist/gradient-reveal-text.d.ts +35 -0
- package/dist/gradient-reveal-text.js +206 -0
- package/dist/gradient-reveal-text.js.map +1 -0
- package/dist/input-group.d.ts +1 -1
- package/dist/pagination.js +1 -1
- package/dist/sidebar.js +3 -3
- package/dist/typewriter.d.ts +67 -0
- package/dist/typewriter.js +198 -0
- package/dist/typewriter.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/film-grain-shader.ts","../src/film-grain-webgl.ts","../src/film-grain.tsx"],"names":["w","h","onResize","pad"],"mappings":";;;;AAAO,IAAM,YAAA,GAAe;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAUrB,IAAM,cAAA,GAAiB;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA,CAAA;;;ACG9B,SAAS,SAAS,GAAA,EAA+C;AAC/D,EAAA,IAAI,CAAC,qBAAA,CAAsB,IAAA,CAAK,GAAG,CAAA,SAAU,CAAC,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,CAAA;AAChE,EAAA,IAAI,CAAA,GAAI,GAAA,CAAI,OAAA,CAAQ,GAAA,EAAK,EAAE,CAAA;AAC3B,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG,CAAA,GAAI,EAAE,KAAA,CAAM,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AAC7D,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG,CAAA,IAAK,IAAA;AACzB,EAAA,MAAM,CAAA,GAAI,QAAA,CAAS,CAAA,EAAG,EAAE,CAAA;AACxB,EAAA,OAAO,CAAE,CAAA,IAAK,EAAA,GAAM,GAAA,EAAO,CAAA,IAAK,EAAA,GAAM,GAAA,EAAO,CAAA,IAAK,CAAA,GAAK,GAAA,EAAM,CAAA,GAAI,GAAI,CAAA;AACvE;AAiBA,SAAS,UAAU,EAAA,EAAiD;AAClE,EAAA,MAAM,YAAA,GAAe,CAAC,IAAA,EAAc,MAAA,KAAmB;AACrD,IAAA,MAAM,MAAA,GAAS,EAAA,CAAG,YAAA,CAAa,IAAI,CAAA;AACnC,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,IAAA,EAAA,CAAG,YAAA,CAAa,QAAQ,MAAM,CAAA;AAC9B,IAAA,EAAA,CAAG,cAAc,MAAM,CAAA;AACvB,IAAA,IAAI,CAAC,EAAA,CAAG,kBAAA,CAAmB,MAAA,EAAQ,EAAA,CAAG,cAAc,CAAA,EAAG;AACrD,MAAA,EAAA,CAAG,aAAa,MAAM,CAAA;AACtB,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,EAAA,GAAK,YAAA,CAAa,EAAA,CAAG,aAAA,EAAe,YAAY,CAAA;AACtD,EAAA,MAAM,EAAA,GAAK,YAAA,CAAa,EAAA,CAAG,eAAA,EAAiB,cAAc,CAAA;AAC1D,EAAA,IAAI,CAAC,EAAA,IAAM,CAAC,EAAA,EAAI,OAAO,IAAA;AAEvB,EAAA,MAAM,OAAA,GAAU,GAAG,aAAA,EAAc;AACjC,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,EAAA,CAAG,YAAA,CAAa,SAAS,EAAE,CAAA;AAC3B,EAAA,EAAA,CAAG,YAAA,CAAa,SAAS,EAAE,CAAA;AAC3B,EAAA,EAAA,CAAG,YAAY,OAAO,CAAA;AAEtB,EAAA,IAAI,CAAC,EAAA,CAAG,mBAAA,CAAoB,OAAA,EAAS,EAAA,CAAG,WAAW,CAAA,EAAG;AACpD,IAAA,EAAA,CAAG,cAAc,OAAO,CAAA;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,EAAA,CAAG,WAAW,OAAO,CAAA;AAErB,EAAA,MAAM,MAAA,GAAS,GAAG,YAAA,EAAa;AAC/B,EAAA,EAAA,CAAG,UAAA,CAAW,EAAA,CAAG,YAAA,EAAc,MAAM,CAAA;AACrC,EAAA,EAAA,CAAG,UAAA;AAAA,IACD,EAAA,CAAG,YAAA;AAAA,IACH,IAAI,YAAA,CAAa,CAAC,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,IAC7C,EAAA,CAAG;AAAA,GACL;AAEA,EAAA,MAAM,QAAA,GAAW,EAAA,CAAG,iBAAA,CAAkB,OAAA,EAAS,UAAU,CAAA;AACzD,EAAA,EAAA,CAAG,wBAAwB,QAAQ,CAAA;AACnC,EAAA,EAAA,CAAG,oBAAoB,QAAA,EAAU,CAAA,EAAG,GAAG,KAAA,EAAO,KAAA,EAAO,GAAG,CAAC,CAAA;AAEzD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,EAAA,CAAG,kBAAA,CAAmB,OAAA,EAAS,OAAO,CAAA;AAAA,IAC7C,WAAA,EAAa,EAAA,CAAG,kBAAA,CAAmB,OAAA,EAAS,aAAa,CAAA;AAAA,IACzD,QAAA,EAAU,EAAA,CAAG,kBAAA,CAAmB,OAAA,EAAS,UAAU,CAAA;AAAA,IACnD,QAAA,EAAU,EAAA,CAAG,kBAAA,CAAmB,OAAA,EAAS,UAAU,CAAA;AAAA,IACnD,IAAA,EAAM,EAAA,CAAG,kBAAA,CAAmB,OAAA,EAAS,MAAM,CAAA;AAAA,IAC3C,MAAA,EAAQ,EAAA,CAAG,kBAAA,CAAmB,OAAA,EAAS,QAAQ,CAAA;AAAA,IAC/C,OAAA;AAAA,IACA,EAAA;AAAA,IACA,EAAA;AAAA,IACA;AAAA,GACF;AACF;AAGA,SAAS,YAAA,CACP,EAAA,EACA,GAAA,EACA,GAAA,EACA;AACA,EAAA,IAAI,GAAA,EAAK,EAAA,CAAG,SAAA,CAAU,GAAA,EAAK,GAAG,CAAA;AAChC;AAEA,SAAS,YAAA,CACP,EAAA,EACA,GAAA,EACA,CAAA,EACA,CAAA,EACA;AACA,EAAA,IAAI,GAAA,EAAK,EAAA,CAAG,SAAA,CAAU,GAAA,EAAK,GAAG,CAAC,CAAA;AACjC;AAEA,SAAS,YAAA,CACP,EAAA,EACA,GAAA,EACA,CAAA,EACA,GACA,CAAA,EACA;AACA,EAAA,IAAI,KAAK,EAAA,CAAG,SAAA,CAAU,GAAA,EAAK,CAAA,EAAG,GAAG,CAAC,CAAA;AACpC;AAIA,SAAS,oBAAA,CACP,KAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACmB;AACnB,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AACjD,EAAA,SAAA,CAAU,KAAA,GAAQ,KAAA;AAClB,EAAA,SAAA,CAAU,MAAA,GAAS,MAAA;AACnB,EAAA,MAAM,GAAA,GAAM,SAAA,CAAU,UAAA,CAAW,IAAI,CAAA;AACrC,EAAA,IAAI,CAAC,KAAK,OAAO,SAAA;AAEjB,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA,GAAI,SAAS,KAAK,CAAA;AACnC,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,eAAA,CAAgB,KAAA,EAAO,MAAM,CAAA;AACnD,EAAA,MAAM,MAAA,GAAS,IAAI,WAAA,CAAY,SAAA,CAAU,KAAK,MAAM,CAAA;AAEpD,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,IAAI,IAAA,CAAK,MAAA,EAAO,GAAI,OAAA,EAAS;AAC3B,MAAA,MAAM,SAAA,GAAY,KAAK,KAAA,CAAM,CAAA,IAAK,MAAM,IAAA,CAAK,MAAA,KAAW,GAAA,CAAI,CAAA;AAC5D,MAAA,MAAA,CAAO,CAAC,KAAM,SAAA,IAAa,EAAA,GAAO,KAAK,EAAA,GAAO,CAAA,IAAK,IAAK,CAAA,MAAO,CAAA;AAAA,IACjE;AAAA,EACF;AAEA,EAAA,GAAA,CAAI,YAAA,CAAa,SAAA,EAAW,CAAA,EAAG,CAAC,CAAA;AAChC,EAAA,OAAO,SAAA;AACT;AAIO,SAAS,YAAA,CAAa;AAAA,EAC3B,OAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAA,GAAM,EAAA;AAAA,EACN,KAAA,GAAQ;AACV,CAAA,EAAwB;AACtB,EAAA,MAAM,SAAA,GAAY,OAAiC,IAAI,CAAA;AACvD,EAAA,MAAM,MAAA,GAAS,OAAe,CAAC,CAAA;AAC/B,EAAA,MAAM,UAAA,GAAa,OAAO,IAAI,CAAA;AAC9B,EAAA,MAAM,eAAA,GAAkB,OAAiC,IAAI,CAAA;AAC7D,EAAA,MAAM,cAAA,GAAiB,OAA6C,IAAI,CAAA;AAExE,EAAA,MAAM,WAAW,OAAA,CAAQ,MAAM,MAAO,GAAA,EAAK,CAAC,GAAG,CAAC,CAAA;AAEhD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,SAAS,SAAA,CAAU,OAAA;AACzB,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,MAAM,YAAY,MAAA,CAAO,aAAA;AACzB,IAAA,IAAI,CAAC,SAAA,EAAW;AAEhB,IAAA,MAAM,uBAAuB,MAAA,CAAO,UAAA;AAAA,MAClC;AAAA,KACF,CAAE,OAAA;AAGF,IAAA,MAAM,kBAAkB,IAAI,oBAAA;AAAA,MAC1B,CAAC,OAAA,KAAY;AACX,QAAA,MAAM,KAAA,GAAQ,QAAQ,CAAC,CAAA;AACvB,QAAA,IAAI,KAAA,EAAO,UAAA,CAAW,OAAA,GAAU,KAAA,CAAM,cAAA;AAAA,MACxC,CAAA;AAAA,MACA,EAAE,WAAW,IAAA;AAAK,KACpB;AACA,IAAA,eAAA,CAAgB,QAAQ,SAAS,CAAA;AAEjC,IAAA,MAAM,gBAAgB,MAAM;AAC1B,MAAA,MAAM,GAAA,GAAM,OAAO,gBAAA,IAAoB,CAAA;AACvC,MAAA,OAAO;AAAA,QACL,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,cAAc,GAAG,CAAA;AAAA,QACtC,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,eAAe,GAAG,CAAA;AAAA,QACvC;AAAA,OACF;AAAA,IACF,CAAA;AAIA,IAAA,MAAM,KACJ,MAAA,CAAO,UAAA,CAAW,OAAO,CAAA,IACxB,MAAA,CAAO,WAAW,oBAAoB,CAAA;AACzC,IAAA,MAAM,QAAA,GAAW,EAAA,GAAK,SAAA,CAAU,EAAE,CAAA,GAAI,IAAA;AAEtC,IAAA,IAAI,MAAM,QAAA,EAAU;AAClB,MAAA,IAAI,WAAA,GAAc,KAAA;AAElB,MAAA,MAAM,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,GAAI,SAAS,KAAK,CAAA;AACnC,MAAA,MAAM,cAAc,MAAM;AACxB,QAAA,YAAA,CAAa,EAAA,EAAI,QAAA,CAAS,QAAA,EAAU,OAAO,CAAA;AAC3C,QAAA,YAAA,CAAa,EAAA,EAAI,QAAA,CAAS,QAAA,EAAU,OAAO,CAAA;AAC3C,QAAA,YAAA,CAAa,EAAA,EAAI,QAAA,CAAS,IAAA,EAAM,GAAG,CAAA;AACnC,QAAA,YAAA,CAAa,EAAA,EAAI,SAAS,MAAA,EAAQ,EAAA,GAAK,KAAK,EAAA,GAAK,GAAA,EAAK,KAAK,GAAG,CAAA;AAAA,MAChE,CAAA;AAEA,MAAA,MAAM,aAAA,GAAgB,CAAC,CAAA,KAAa;AAClC,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,WAAA,GAAc,IAAA;AACd,QAAA,oBAAA,CAAqB,OAAO,OAAO,CAAA;AAAA,MACrC,CAAA;AAEA,MAAA,MAAM,oBAAoB,MAAM;AAC9B,QAAA,WAAA,GAAc,KAAA;AACd,QAAA,MAAM,WAAA,GAAc,UAAU,EAAE,CAAA;AAChC,QAAA,IAAI,WAAA,EAAa;AACf,UAAA,QAAA,CAAS,QAAQ,WAAA,CAAY,KAAA;AAC7B,UAAA,QAAA,CAAS,cAAc,WAAA,CAAY,WAAA;AACnC,UAAA,QAAA,CAAS,WAAW,WAAA,CAAY,QAAA;AAChC,UAAA,QAAA,CAAS,WAAW,WAAA,CAAY,QAAA;AAChC,UAAA,QAAA,CAAS,OAAO,WAAA,CAAY,IAAA;AAC5B,UAAA,QAAA,CAAS,SAAS,WAAA,CAAY,MAAA;AAC9B,UAAA,QAAA,CAAS,UAAU,WAAA,CAAY,OAAA;AAC/B,UAAA,QAAA,CAAS,KAAK,WAAA,CAAY,EAAA;AAC1B,UAAA,QAAA,CAAS,KAAK,WAAA,CAAY,EAAA;AAC1B,UAAA,QAAA,CAAS,SAAS,WAAA,CAAY,MAAA;AAC9B,UAAA,MAAA,EAAO;AACP,UAAA,WAAA,EAAY;AACZ,UAAA,IAAI,CAAC,oBAAA;AACH,YAAA,MAAA,CAAO,OAAA,GAAU,sBAAsB,MAAM,CAAA;AAAA,QACjD;AAAA,MACF,CAAA;AAEA,MAAA,MAAA,CAAO,gBAAA,CAAiB,oBAAoB,aAAa,CAAA;AACzD,MAAA,MAAA,CAAO,gBAAA,CAAiB,wBAAwB,iBAAiB,CAAA;AAEjE,MAAA,MAAM,SAAS,MAAM;AACnB,QAAA,MAAM,EAAE,CAAA,EAAAA,EAAAA,EAAG,CAAA,EAAAC,EAAAA,KAAM,aAAA,EAAc;AAC/B,QAAA,IAAID,EAAAA,KAAM,CAAA,IAAKC,EAAAA,KAAM,CAAA,EAAG;AACxB,QAAA,MAAA,CAAO,KAAA,GAAQD,EAAAA;AACf,QAAA,MAAA,CAAO,MAAA,GAASC,EAAAA;AAChB,QAAA,EAAA,CAAG,QAAA,CAAS,CAAA,EAAG,CAAA,EAAGD,EAAAA,EAAGC,EAAC,CAAA;AACtB,QAAA,YAAA,CAAa,EAAA,EAAI,QAAA,CAAS,WAAA,EAAaD,EAAAA,EAAGC,EAAC,CAAA;AAAA,MAC7C,CAAA;AAEA,MAAA,MAAA,EAAO;AACP,MAAA,WAAA,EAAY;AAEZ,MAAA,EAAA,CAAG,UAAA,CAAW,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAExB,MAAA,MAAM,KAAA,GAAQ,YAAY,GAAA,EAAI;AAC9B,MAAA,IAAI,QAAA,GAAW,EAAA;AAEf,MAAA,MAAM,MAAA,GAAS,CAAC,GAAA,KAAgB;AAC9B,QAAA,IAAI,WAAA,EAAa;AAEjB,QAAA,IACE,CAAC,QAAA,CAAS,MAAA,IACV,UAAA,CAAW,OAAA,IACX,OAAO,KAAA,GAAQ,CAAA,IACf,MAAA,CAAO,MAAA,GAAS,CAAA,EAChB;AACA,UAAA,MAAM,IAAA,GAAA,CAAQ,MAAM,KAAA,IAAS,GAAA;AAG7B,UAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,GAAG,CAAA;AAClC,UAAA,IAAI,SAAS,QAAA,EAAU;AACrB,YAAA,QAAA,GAAW,IAAA;AACX,YAAA,EAAA,CAAG,KAAA,CAAM,GAAG,gBAAgB,CAAA;AAC5B,YAAA,YAAA,CAAa,EAAA,EAAI,QAAA,CAAS,KAAA,EAAO,IAAI,CAAA;AACrC,YAAA,EAAA,CAAG,UAAA,CAAW,EAAA,CAAG,cAAA,EAAgB,CAAA,EAAG,CAAC,CAAA;AAAA,UACvC;AAAA,QACF;AAEA,QAAA,MAAA,CAAO,OAAA,GAAU,sBAAsB,MAAM,CAAA;AAAA,MAC/C,CAAA;AAEA,MAAA,IAAI,oBAAA,EAAsB;AACxB,QAAA,YAAA,CAAa,EAAA,EAAI,QAAA,CAAS,KAAA,EAAO,CAAC,CAAA;AAClC,QAAA,EAAA,CAAG,KAAA,CAAM,GAAG,gBAAgB,CAAA;AAC5B,QAAA,EAAA,CAAG,UAAA,CAAW,EAAA,CAAG,cAAA,EAAgB,CAAA,EAAG,CAAC,CAAA;AAAA,MACvC,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,OAAA,GAAU,sBAAsB,MAAM,CAAA;AAAA,MAC/C;AAEA,MAAA,MAAMC,YAAW,MAAM;AACrB,QAAA,IAAI,cAAA,CAAe,OAAA,EAAS,YAAA,CAAa,cAAA,CAAe,OAAO,CAAA;AAC/D,QAAA,cAAA,CAAe,OAAA,GAAU,UAAA,CAAW,MAAA,EAAQ,GAAG,CAAA;AAAA,MACjD,CAAA;AAEA,MAAA,MAAA,CAAO,gBAAA,CAAiB,UAAUA,SAAQ,CAAA;AAE1C,MAAA,OAAO,MAAM;AACX,QAAA,oBAAA,CAAqB,OAAO,OAAO,CAAA;AACnC,QAAA,IAAI,cAAA,CAAe,OAAA,EAAS,YAAA,CAAa,cAAA,CAAe,OAAO,CAAA;AAC/D,QAAA,MAAA,CAAO,mBAAA,CAAoB,UAAUA,SAAQ,CAAA;AAC7C,QAAA,MAAA,CAAO,mBAAA,CAAoB,oBAAoB,aAAa,CAAA;AAC5D,QAAA,MAAA,CAAO,mBAAA,CAAoB,wBAAwB,iBAAiB,CAAA;AACpE,QAAA,eAAA,CAAgB,UAAA,EAAW;AAE3B,QAAA,EAAA,CAAG,YAAA,CAAa,SAAS,MAAM,CAAA;AAC/B,QAAA,EAAA,CAAG,YAAA,CAAa,SAAS,EAAE,CAAA;AAC3B,QAAA,EAAA,CAAG,YAAA,CAAa,SAAS,EAAE,CAAA;AAC3B,QAAA,EAAA,CAAG,aAAA,CAAc,SAAS,OAAO,CAAA;AAAA,MACnC,CAAA;AAAA,IACF;AAIA,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,eAAA,CAAgB,UAAA,EAAW;AAC3B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GAAY,GAAA;AAClB,IAAA,MAAM,MAAA,GAAS,CAACF,EAAAA,EAAWC,EAAAA,KACzB,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,CAAID,EAAAA,EAAGC,EAAC,CAAA,GAAI,SAAS,CAAA;AAEvC,IAAA,MAAM,QAAQ,MAAM;AAClB,MAAA,MAAM,EAAE,CAAA,EAAAD,EAAAA,EAAG,CAAA,EAAAC,EAAAA,KAAM,aAAA,EAAc;AAC/B,MAAA,IAAID,EAAAA,KAAM,CAAA,IAAKC,EAAAA,KAAM,CAAA,EAAG,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,GAAA,EAAK,CAAA,EAAE;AAEpD,MAAA,MAAME,IAAAA,GAAM,MAAA,CAAOH,EAAAA,EAAGC,EAAC,CAAA;AACvB,MAAA,MAAA,CAAO,KAAA,GAAQD,EAAAA;AACf,MAAA,MAAA,CAAO,MAAA,GAASC,EAAAA;AAEhB,MAAA,IACE,CAAC,eAAA,CAAgB,OAAA,IACjB,eAAA,CAAgB,OAAA,CAAQ,KAAA,GAAQD,EAAAA,GAAIG,IAAAA,IACpC,eAAA,CAAgB,OAAA,CAAQ,MAAA,GAASF,EAAAA,GAAIE,IAAAA,EACrC;AACA,QAAA,eAAA,CAAgB,OAAA,GAAU,oBAAA;AAAA,UACxBH,EAAAA,GAAIG,IAAAA;AAAA,UACJF,EAAAA,GAAIE,IAAAA;AAAA,UACJ,OAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,CAAA,EAAAH,EAAAA,EAAG,CAAA,EAAAC,EAAAA,EAAG,KAAAE,IAAAA,EAAI;AAAA,IACrB,CAAA;AAEA,IAAA,IAAI,EAAE,CAAA,EAAG,CAAA,EAAG,GAAA,KAAQ,KAAA,EAAM;AAG1B,IAAA,IAAI,OAAA,GAAU,CAAA;AACd,IAAA,IAAI,OAAA,GAAU,CAAA;AAEd,IAAA,MAAM,YAAY,MAAM;AACtB,MAAA,MAAM,QAAQ,eAAA,CAAgB,OAAA;AAC9B,MAAA,IAAI,CAAC,KAAA,IAAS,CAAA,KAAM,CAAA,IAAK,MAAM,CAAA,EAAG;AAElC,MAAA,MAAM,GAAA,GAAM,OAAO,gBAAA,IAAoB,CAAA;AAEvC,MAAA,GAAA,CAAI,SAAA,CAAU,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AACxB,MAAA,GAAA,CAAI,MAAA,GAAS,CAAA,KAAA,EAAQ,GAAA,GAAM,GAAG,CAAA,GAAA,CAAA;AAE9B,MAAA,OAAA,GAAA,CAAW,UAAU,GAAA,IAAO,GAAA;AAC5B,MAAA,OAAA,GAAA,CAAW,UAAU,GAAA,IAAO,GAAA;AAE5B,MAAA,GAAA,CAAI,SAAA,CAAU,OAAO,CAAC,OAAA,EAAS,CAAC,OAAA,EAAS,CAAA,GAAI,GAAA,EAAK,CAAA,GAAI,GAAG,CAAA;AACzD,MAAA,GAAA,CAAI,MAAA,GAAS,MAAA;AAAA,IACf,CAAA;AAEA,IAAA,IAAI,oBAAA,EAAsB;AACxB,MAAA,SAAA,EAAU;AACV,MAAA,eAAA,CAAgB,UAAA,EAAW;AAC3B,MAAA,eAAA,CAAgB,OAAA,GAAU,IAAA;AAC1B,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,SAAA,GAAY,YAAY,GAAA,EAAI;AAEhC,IAAA,MAAM,IAAA,GAAO,CAAC,GAAA,KAAgB;AAC5B,MAAA,IACE,CAAC,SAAS,MAAA,IACV,UAAA,CAAW,WACX,CAAA,GAAI,CAAA,IACJ,IAAI,CAAA,EACJ;AACA,QAAA,OAAO,GAAA,GAAM,aAAa,QAAA,EAAU;AAClC,UAAA,SAAA,IAAa,QAAA;AACb,UAAA,SAAA,EAAU;AAAA,QACZ;AAAA,MACF;AACA,MAAA,MAAA,CAAO,OAAA,GAAU,sBAAsB,IAAI,CAAA;AAAA,IAC7C,CAAA;AAEA,IAAA,MAAA,CAAO,OAAA,GAAU,sBAAsB,IAAI,CAAA;AAE3C,IAAA,MAAM,WAAW,MAAM;AACrB,MAAA,IAAI,cAAA,CAAe,OAAA,EAAS,YAAA,CAAa,cAAA,CAAe,OAAO,CAAA;AAC/D,MAAA,cAAA,CAAe,OAAA,GAAU,WAAW,MAAM;AACxC,QAAA,MAAM,IAAI,aAAA,EAAc;AACxB,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,CAAA,EAAG,EAAE,CAAC,CAAA;AAE9B,QAAA,IACE,eAAA,CAAgB,OAAA,IAChB,eAAA,CAAgB,OAAA,CAAQ,KAAA,IAAS,CAAA,CAAE,CAAA,GAAI,MAAA,IACvC,eAAA,CAAgB,OAAA,CAAQ,MAAA,IAAU,CAAA,CAAE,IAAI,MAAA,EACxC;AACA,UAAA,CAAA,GAAI,CAAA,CAAE,CAAA;AACN,UAAA,CAAA,GAAI,CAAA,CAAE,CAAA;AACN,UAAA,GAAA,GAAM,MAAA;AACN,UAAA,MAAA,CAAO,KAAA,GAAQ,CAAA;AACf,UAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAChB,UAAA;AAAA,QACF;AAEA,QAAA,CAAA,GAAI,CAAA,CAAE,CAAA;AACN,QAAA,CAAA,GAAI,CAAA,CAAE,CAAA;AACN,QAAA,GAAA,GAAM,MAAA;AACN,QAAA,MAAA,CAAO,KAAA,GAAQ,CAAA;AACf,QAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAChB,QAAA,eAAA,CAAgB,OAAA,GAAU,oBAAA;AAAA,UACxB,CAAA,GAAI,GAAA;AAAA,UACJ,CAAA,GAAI,GAAA;AAAA,UACJ,OAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF,GAAG,GAAG,CAAA;AAAA,IACR,CAAA;AAEA,IAAA,MAAA,CAAO,gBAAA,CAAiB,UAAU,QAAQ,CAAA;AAE1C,IAAA,OAAO,MAAM;AACX,MAAA,oBAAA,CAAqB,OAAO,OAAO,CAAA;AACnC,MAAA,IAAI,cAAA,CAAe,OAAA,EAAS,YAAA,CAAa,cAAA,CAAe,OAAO,CAAA;AAC/D,MAAA,MAAA,CAAO,mBAAA,CAAoB,UAAU,QAAQ,CAAA;AAC7C,MAAA,eAAA,CAAgB,UAAA,EAAW;AAC3B,MAAA,eAAA,CAAgB,OAAA,GAAU,IAAA;AAAA,IAC5B,CAAA;AAAA,EACF,GAAG,CAAC,OAAA,EAAS,SAAS,GAAA,EAAK,QAAA,EAAU,KAAK,CAAC,CAAA;AAE3C,EAAA,OAAO,SAAA;AACT;AC9aA,SAAS,SAAA,CAAU;AAAA,EACjB,OAAA,GAAU,GAAA;AAAA,EACV,OAAA,GAAU,IAAA;AAAA,EACV,SAAA,GAAY,SAAA;AAAA,EACZ,GAAA,GAAM,EAAA;AAAA,EACN,KAAA,GAAQ,SAAA;AAAA,EACR,SAAA;AAAA,EACA;AACF,CAAA,EAAmB;AACjB,EAAA,MAAM,YAAY,YAAA,CAAa,EAAE,SAAS,OAAA,EAAS,GAAA,EAAK,OAAO,CAAA;AAE/D,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,MAAA;AAAA,MACZ,SAAA,EAAW;AAAA,QACT,sEAAA;AAAA,QACA;AAAA,OACF,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,MACX,OAAO,EAAE,YAAA,EAAc,SAAA,EAAW,OAAA,EAAS,GAAG,KAAA,EAAM;AAAA,MAEpD,QAAA,kBAAA,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,SAAA;AAAA,UACL,SAAA,EAAU;AAAA;AAAA;AACZ;AAAA,GACF;AAEJ","file":"film-grain.js","sourcesContent":["export const vertexShader = `\nattribute vec2 position;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = position * 0.5 + 0.5;\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`\n\nexport const fragmentShader = `\nprecision highp float;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform float uDensity;\nuniform float uOpacity;\nuniform float uFps;\nuniform vec3 uColor;\n\nvarying vec2 vUv;\n\n// Stable hash\nfloat hash(vec2 p, float seed) {\n return fract(sin(dot(p + seed, vec2(127.1, 311.7))) * 43758.5453123);\n}\n\n// Film response curve (soft toe + shoulder rolloff)\nfloat filmCurve(float x) {\n return smoothstep(0.0, 0.2, x) * (1.0 - smoothstep(0.8, 1.0, x));\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy;\n vec2 p = floor(uv);\n\n // Temporal coherence: blend between current and next frame seed\n float frame = floor(uTime * uFps);\n float t = fract(uTime * uFps);\n float seed = frame * 0.1731;\n\n // Multi-scale grain with inter-frame blending on fine layer\n float fineA = hash(p, seed);\n float fineB = hash(p, seed + 0.1731);\n float fine = mix(fineA, fineB, t);\n\n float medium = hash(floor(uv * 0.5), seed + 3.1);\n float coarse = hash(floor(uv * 0.25), seed + 7.93);\n\n float grain = fine * 0.65 + medium * 0.25 + coarse * 0.10;\n\n // Emulsion clumping (organic structure)\n float cluster = hash(floor(uv * 0.18), seed + 9.2);\n grain *= mix(0.75, 1.35, cluster);\n\n // Density threshold\n grain = smoothstep(1.0 - uDensity, 1.0, grain);\n\n // Film response curve (replaces raw pow gamma)\n grain = filmCurve(grain);\n\n // Micro-blur: sample neighbors for optical diffusion\n float n1 = hash(p + vec2(1.0, 0.0), seed);\n float n2 = hash(p - vec2(1.0, 0.0), seed);\n float n3 = hash(p + vec2(0.0, 1.0), seed);\n float n4 = hash(p - vec2(0.0, 1.0), seed);\n float neighbors = (n1 + n2 + n3 + n4) * 0.25;\n grain = mix(grain, neighbors, 0.15);\n\n // Chromatic aberration (reuse neighbor hashes)\n float rShift = n1 * 0.015;\n float bShift = n2 * 0.015;\n\n vec3 color = uColor * vec3(\n grain + rShift,\n grain,\n grain + bShift\n );\n\n color = clamp(color, 0.0, 1.0);\n\n gl_FragColor = vec4(color, grain * uOpacity);\n}\n`\n","import { useEffect, useRef, useMemo } from \"react\"\nimport { vertexShader, fragmentShader } from \"./film-grain-shader\"\n\ninterface UseFilmGrainOptions {\n density: number\n opacity: number\n /** Target FPS for both WebGL and canvas fallback. Default 18 */\n fps?: number\n /** Hex color for canvas fallback grain. Default '#ffffff' */\n color?: string\n}\n\n/** Parse hex color safely */\nfunction parseHex(hex: string): [number, number, number, number] {\n if (!/^#([0-9a-f]{3,8})$/i.test(hex)) return [255, 255, 255, 255]\n let h = hex.replace(\"#\", \"\")\n if (h.length === 3) h = h.split(\"\").map((c) => c + c).join(\"\")\n if (h.length === 6) h += \"ff\"\n const n = parseInt(h, 16)\n return [(n >> 24) & 0xff, (n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff]\n}\n\n// ── WebGL renderer ──────────────────────────────────────────────────\n\ninterface WebGLUniforms {\n uTime: WebGLUniformLocation | null\n uResolution: WebGLUniformLocation | null\n uDensity: WebGLUniformLocation | null\n uOpacity: WebGLUniformLocation | null\n uFps: WebGLUniformLocation | null\n uColor: WebGLUniformLocation | null\n program: WebGLProgram\n vs: WebGLShader\n fs: WebGLShader\n buffer: WebGLBuffer | null\n}\n\nfunction initWebGL(gl: WebGLRenderingContext): WebGLUniforms | null {\n const createShader = (type: number, source: string) => {\n const shader = gl.createShader(type)\n if (!shader) return null\n gl.shaderSource(shader, source)\n gl.compileShader(shader)\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n gl.deleteShader(shader)\n return null\n }\n return shader\n }\n\n const vs = createShader(gl.VERTEX_SHADER, vertexShader)\n const fs = createShader(gl.FRAGMENT_SHADER, fragmentShader)\n if (!vs || !fs) return null\n\n const program = gl.createProgram()\n if (!program) return null\n\n gl.attachShader(program, vs)\n gl.attachShader(program, fs)\n gl.linkProgram(program)\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n gl.deleteProgram(program)\n return null\n }\n\n gl.useProgram(program)\n\n const buffer = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n gl.bufferData(\n gl.ARRAY_BUFFER,\n new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),\n gl.STATIC_DRAW\n )\n\n const position = gl.getAttribLocation(program, \"position\")\n gl.enableVertexAttribArray(position)\n gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0)\n\n return {\n uTime: gl.getUniformLocation(program, \"uTime\"),\n uResolution: gl.getUniformLocation(program, \"uResolution\"),\n uDensity: gl.getUniformLocation(program, \"uDensity\"),\n uOpacity: gl.getUniformLocation(program, \"uOpacity\"),\n uFps: gl.getUniformLocation(program, \"uFps\"),\n uColor: gl.getUniformLocation(program, \"uColor\"),\n program,\n vs,\n fs,\n buffer,\n }\n}\n\n/** Safe uniform setters */\nfunction setUniform1f(\n gl: WebGLRenderingContext,\n loc: WebGLUniformLocation | null,\n val: number\n) {\n if (loc) gl.uniform1f(loc, val)\n}\n\nfunction setUniform2f(\n gl: WebGLRenderingContext,\n loc: WebGLUniformLocation | null,\n x: number,\n y: number\n) {\n if (loc) gl.uniform2f(loc, x, y)\n}\n\nfunction setUniform3f(\n gl: WebGLRenderingContext,\n loc: WebGLUniformLocation | null,\n x: number,\n y: number,\n z: number\n) {\n if (loc) gl.uniform3f(loc, x, y, z)\n}\n\n// ── Canvas 2D fallback renderer ─────────────────────────────────────\n\nfunction generateGrainTexture(\n width: number,\n height: number,\n density: number,\n color: string\n): HTMLCanvasElement {\n const offscreen = document.createElement(\"canvas\")\n offscreen.width = width\n offscreen.height = height\n const ctx = offscreen.getContext(\"2d\")\n if (!ctx) return offscreen\n\n const [r, g, b, a] = parseHex(color)\n const imageData = ctx.createImageData(width, height)\n const pixels = new Uint32Array(imageData.data.buffer)\n\n for (let i = 0; i < pixels.length; i++) {\n if (Math.random() < density) {\n const variation = Math.round(a * (0.4 + Math.random() * 0.6))\n pixels[i] = ((variation << 24) | (b << 16) | (g << 8) | r) >>> 0\n }\n }\n\n ctx.putImageData(imageData, 0, 0)\n return offscreen\n}\n\n// ── Hook ────────────────────────────────────────────────────────────\n\nexport function useFilmGrain({\n density,\n opacity,\n fps = 18,\n color = \"#ffffff\",\n}: UseFilmGrainOptions) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null)\n const rafRef = useRef<number>(0)\n const visibleRef = useRef(true)\n const grainTextureRef = useRef<HTMLCanvasElement | null>(null)\n const resizeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const interval = useMemo(() => 1000 / fps, [fps])\n\n useEffect(() => {\n const canvas = canvasRef.current\n if (!canvas) return\n\n const container = canvas.parentElement\n if (!container) return\n\n const prefersReducedMotion = window.matchMedia(\n \"(prefers-reduced-motion: reduce)\"\n ).matches\n\n // Pause when offscreen\n const intersectionObs = new IntersectionObserver(\n (entries) => {\n const entry = entries[0]\n if (entry) visibleRef.current = entry.isIntersecting\n },\n { threshold: 0.01 }\n )\n intersectionObs.observe(container)\n\n const getDimensions = () => {\n const dpr = window.devicePixelRatio || 1\n return {\n w: Math.round(canvas.clientWidth * dpr),\n h: Math.round(canvas.clientHeight * dpr),\n dpr,\n }\n }\n\n // ── Try WebGL ──\n\n const gl =\n canvas.getContext(\"webgl\") ||\n (canvas.getContext(\"experimental-webgl\") as WebGLRenderingContext | null)\n const uniforms = gl ? initWebGL(gl) : null\n\n if (gl && uniforms) {\n let contextLost = false\n\n const [cr, cg, cb] = parseHex(color)\n const setUniforms = () => {\n setUniform1f(gl, uniforms.uDensity, density)\n setUniform1f(gl, uniforms.uOpacity, opacity)\n setUniform1f(gl, uniforms.uFps, fps)\n setUniform3f(gl, uniforms.uColor, cr / 255, cg / 255, cb / 255)\n }\n\n const onContextLost = (e: Event) => {\n e.preventDefault()\n contextLost = true\n cancelAnimationFrame(rafRef.current)\n }\n\n const onContextRestored = () => {\n contextLost = false\n const newUniforms = initWebGL(gl)\n if (newUniforms) {\n uniforms.uTime = newUniforms.uTime\n uniforms.uResolution = newUniforms.uResolution\n uniforms.uDensity = newUniforms.uDensity\n uniforms.uOpacity = newUniforms.uOpacity\n uniforms.uFps = newUniforms.uFps\n uniforms.uColor = newUniforms.uColor\n uniforms.program = newUniforms.program\n uniforms.vs = newUniforms.vs\n uniforms.fs = newUniforms.fs\n uniforms.buffer = newUniforms.buffer\n resize()\n setUniforms()\n if (!prefersReducedMotion)\n rafRef.current = requestAnimationFrame(render)\n }\n }\n\n canvas.addEventListener(\"webglcontextlost\", onContextLost)\n canvas.addEventListener(\"webglcontextrestored\", onContextRestored)\n\n const resize = () => {\n const { w, h } = getDimensions()\n if (w === 0 || h === 0) return\n canvas.width = w\n canvas.height = h\n gl.viewport(0, 0, w, h)\n setUniform2f(gl, uniforms.uResolution, w, h)\n }\n\n resize()\n setUniforms()\n\n gl.clearColor(0, 0, 0, 0)\n\n const start = performance.now()\n let lastSeed = -1\n\n const render = (now: number) => {\n if (contextLost) return\n\n if (\n !document.hidden &&\n visibleRef.current &&\n canvas.width > 0 &&\n canvas.height > 0\n ) {\n const time = (now - start) / 1000\n\n // Skip draw if grain seed hasn't changed\n const seed = Math.floor(time * fps)\n if (seed !== lastSeed) {\n lastSeed = seed\n gl.clear(gl.COLOR_BUFFER_BIT)\n setUniform1f(gl, uniforms.uTime, time)\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)\n }\n }\n\n rafRef.current = requestAnimationFrame(render)\n }\n\n if (prefersReducedMotion) {\n setUniform1f(gl, uniforms.uTime, 0)\n gl.clear(gl.COLOR_BUFFER_BIT)\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)\n } else {\n rafRef.current = requestAnimationFrame(render)\n }\n\n const onResize = () => {\n if (resizeTimerRef.current) clearTimeout(resizeTimerRef.current)\n resizeTimerRef.current = setTimeout(resize, 150)\n }\n\n window.addEventListener(\"resize\", onResize)\n\n return () => {\n cancelAnimationFrame(rafRef.current)\n if (resizeTimerRef.current) clearTimeout(resizeTimerRef.current)\n window.removeEventListener(\"resize\", onResize)\n canvas.removeEventListener(\"webglcontextlost\", onContextLost)\n canvas.removeEventListener(\"webglcontextrestored\", onContextRestored)\n intersectionObs.disconnect()\n\n gl.deleteBuffer(uniforms.buffer)\n gl.deleteShader(uniforms.vs)\n gl.deleteShader(uniforms.fs)\n gl.deleteProgram(uniforms.program)\n }\n }\n\n // ── Canvas 2D fallback ──\n\n const ctx = canvas.getContext(\"2d\")\n if (!ctx) {\n intersectionObs.disconnect()\n return\n }\n\n const padFactor = 0.3\n const getPad = (w: number, h: number) =>\n Math.round(Math.max(w, h) * padFactor)\n\n const setup = () => {\n const { w, h } = getDimensions()\n if (w === 0 || h === 0) return { w: 0, h: 0, pad: 0 }\n\n const pad = getPad(w, h)\n canvas.width = w\n canvas.height = h\n\n if (\n !grainTextureRef.current ||\n grainTextureRef.current.width < w + pad ||\n grainTextureRef.current.height < h + pad\n ) {\n grainTextureRef.current = generateGrainTexture(\n w + pad,\n h + pad,\n density,\n color\n )\n }\n\n return { w, h, pad }\n }\n\n let { w, h, pad } = setup()\n\n // Drifting offset for temporal coherence (not teleporting)\n let offsetX = 0\n let offsetY = 0\n\n const drawFrame = () => {\n const grain = grainTextureRef.current\n if (!grain || w === 0 || h === 0) return\n\n const dpr = window.devicePixelRatio || 1\n\n ctx.clearRect(0, 0, w, h)\n ctx.filter = `blur(${0.3 * dpr}px)`\n\n offsetX = (offsetX + 0.7) % pad\n offsetY = (offsetY + 0.5) % pad\n\n ctx.drawImage(grain, -offsetX, -offsetY, w + pad, h + pad)\n ctx.filter = \"none\"\n }\n\n if (prefersReducedMotion) {\n drawFrame()\n intersectionObs.disconnect()\n grainTextureRef.current = null\n return\n }\n\n let lastFrame = performance.now()\n\n const tick = (now: number) => {\n if (\n !document.hidden &&\n visibleRef.current &&\n w > 0 &&\n h > 0\n ) {\n while (now - lastFrame >= interval) {\n lastFrame += interval\n drawFrame()\n }\n }\n rafRef.current = requestAnimationFrame(tick)\n }\n\n rafRef.current = requestAnimationFrame(tick)\n\n const onResize = () => {\n if (resizeTimerRef.current) clearTimeout(resizeTimerRef.current)\n resizeTimerRef.current = setTimeout(() => {\n const m = getDimensions()\n const newPad = getPad(m.w, m.h)\n\n if (\n grainTextureRef.current &&\n grainTextureRef.current.width >= m.w + newPad &&\n grainTextureRef.current.height >= m.h + newPad\n ) {\n w = m.w\n h = m.h\n pad = newPad\n canvas.width = w\n canvas.height = h\n return\n }\n\n w = m.w\n h = m.h\n pad = newPad\n canvas.width = w\n canvas.height = h\n grainTextureRef.current = generateGrainTexture(\n w + pad,\n h + pad,\n density,\n color\n )\n }, 150)\n }\n\n window.addEventListener(\"resize\", onResize)\n\n return () => {\n cancelAnimationFrame(rafRef.current)\n if (resizeTimerRef.current) clearTimeout(resizeTimerRef.current)\n window.removeEventListener(\"resize\", onResize)\n intersectionObs.disconnect()\n grainTextureRef.current = null\n }\n }, [density, opacity, fps, interval, color])\n\n return canvasRef\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport { useFilmGrain } from \"./film-grain-webgl\"\n\ninterface FilmGrainProps {\n density?: number\n opacity?: number\n blendMode?: React.CSSProperties[\"mixBlendMode\"]\n fps?: number\n color?: string\n className?: string\n style?: React.CSSProperties\n}\n\nfunction FilmGrain({\n density = 0.6,\n opacity = 0.08,\n blendMode = \"overlay\",\n fps = 18,\n color = \"#ffffff\",\n className,\n style,\n}: FilmGrainProps) {\n const canvasRef = useFilmGrain({ density, opacity, fps, color })\n\n return (\n <div\n aria-hidden=\"true\"\n className={[\n \"absolute inset-0 z-0 pointer-events-none select-none overflow-hidden\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n style={{ mixBlendMode: blendMode, opacity, ...style }}\n >\n <canvas\n ref={canvasRef}\n className=\"w-full h-full will-change-transform\"\n />\n </div>\n )\n}\n\nexport { FilmGrain }\nexport type { FilmGrainProps }\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface GradientRevealTextProps {
|
|
4
|
+
/** The text to display */
|
|
5
|
+
text: string;
|
|
6
|
+
/** Spotlight follow speed in seconds. Default: 0 (instant) */
|
|
7
|
+
duration?: number;
|
|
8
|
+
/** Gradient colors for the reveal effect. Default: rainbow */
|
|
9
|
+
colors?: string[];
|
|
10
|
+
/** Base stroke opacity when not hovered. Default: 0.3 */
|
|
11
|
+
baseOpacity?: number;
|
|
12
|
+
/** Hovered stroke opacity. Default: 0.7 */
|
|
13
|
+
hoverOpacity?: number;
|
|
14
|
+
/** Font family for SVG text. Default: Helvetica Neue */
|
|
15
|
+
fontFamily?: string;
|
|
16
|
+
/** Spotlight radius multiplier relative to text height. Default: 0.6 */
|
|
17
|
+
spotlightSize?: number;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Large decorative text with a gradient spotlight that follows the cursor.
|
|
22
|
+
*
|
|
23
|
+
* Renders as an SVG that auto-sizes to fit the text with zero padding.
|
|
24
|
+
* The gradient reveal effect activates on hover — a circular spotlight
|
|
25
|
+
* follows the mouse, revealing rainbow-colored strokes beneath.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* <GradientRevealText text="HELLO" />
|
|
30
|
+
* <GradientRevealText text="BRAND" colors={["#ff0000", "#00ff00"]} />
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
declare function GradientRevealText({ text, duration, colors, baseOpacity, hoverOpacity, fontFamily, spotlightSize, className, }: GradientRevealTextProps): react_jsx_runtime.JSX.Element;
|
|
34
|
+
|
|
35
|
+
export { GradientRevealText, type GradientRevealTextProps };
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { cn } from './chunk-76UQO56T.js';
|
|
2
|
+
import { useId, useRef, useState, useCallback, useEffect } from 'react';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var DEFAULT_COLORS = [
|
|
6
|
+
"#eab308",
|
|
7
|
+
"#ef4444",
|
|
8
|
+
"#3b82f6",
|
|
9
|
+
"#06b6d4",
|
|
10
|
+
"#8b5cf6"
|
|
11
|
+
];
|
|
12
|
+
function GradientRevealText({
|
|
13
|
+
text,
|
|
14
|
+
duration = 0,
|
|
15
|
+
colors = DEFAULT_COLORS,
|
|
16
|
+
baseOpacity = 0.3,
|
|
17
|
+
hoverOpacity = 0.7,
|
|
18
|
+
fontFamily = "Helvetica Neue, Helvetica, Arial, sans-serif",
|
|
19
|
+
spotlightSize = 0.6,
|
|
20
|
+
className
|
|
21
|
+
}) {
|
|
22
|
+
const uid = useId();
|
|
23
|
+
const svgRef = useRef(null);
|
|
24
|
+
const textRef = useRef(null);
|
|
25
|
+
const gradientRef = useRef(null);
|
|
26
|
+
const [vb, setVb] = useState({ x: 0, y: 0, w: 100, h: 20 });
|
|
27
|
+
const [measured, setMeasured] = useState(false);
|
|
28
|
+
const [hovered, setHovered] = useState(false);
|
|
29
|
+
const targetPos = useRef({ cx: 0.5, cy: 0.5 });
|
|
30
|
+
const currentPos = useRef({ cx: 0.5, cy: 0.5 });
|
|
31
|
+
const rafId = useRef(0);
|
|
32
|
+
const measure = useCallback(() => {
|
|
33
|
+
const el = textRef.current;
|
|
34
|
+
if (!el) return;
|
|
35
|
+
const bbox = el.getBBox();
|
|
36
|
+
if (bbox.width === 0) return;
|
|
37
|
+
setVb({ x: bbox.x, y: bbox.y, w: bbox.width, h: bbox.height });
|
|
38
|
+
setMeasured(true);
|
|
39
|
+
}, []);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
measure();
|
|
42
|
+
document.fonts?.ready?.then(measure);
|
|
43
|
+
}, [text, measure]);
|
|
44
|
+
const applyGradientPos = useCallback((cx, cy) => {
|
|
45
|
+
const el = gradientRef.current;
|
|
46
|
+
if (!el) return;
|
|
47
|
+
const svgCx = vb.x + cx * vb.w;
|
|
48
|
+
const svgCy = vb.y + cy * vb.h;
|
|
49
|
+
el.setAttribute("cx", String(svgCx));
|
|
50
|
+
el.setAttribute("cy", String(svgCy));
|
|
51
|
+
}, [vb]);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (duration <= 0) return;
|
|
54
|
+
const speed = 1 - Math.pow(1e-3, 1 / (duration * 60));
|
|
55
|
+
const tick = () => {
|
|
56
|
+
const cur = currentPos.current;
|
|
57
|
+
const tgt = targetPos.current;
|
|
58
|
+
cur.cx += (tgt.cx - cur.cx) * speed;
|
|
59
|
+
cur.cy += (tgt.cy - cur.cy) * speed;
|
|
60
|
+
applyGradientPos(cur.cx, cur.cy);
|
|
61
|
+
rafId.current = requestAnimationFrame(tick);
|
|
62
|
+
};
|
|
63
|
+
rafId.current = requestAnimationFrame(tick);
|
|
64
|
+
return () => cancelAnimationFrame(rafId.current);
|
|
65
|
+
}, [duration, applyGradientPos]);
|
|
66
|
+
const updatePos = (e) => {
|
|
67
|
+
const svg = svgRef.current;
|
|
68
|
+
if (!svg) return;
|
|
69
|
+
const rect = svg.getBoundingClientRect();
|
|
70
|
+
const cx = (e.clientX - rect.left) / rect.width;
|
|
71
|
+
const cy = (e.clientY - rect.top) / rect.height;
|
|
72
|
+
targetPos.current = { cx, cy };
|
|
73
|
+
if (duration <= 0) {
|
|
74
|
+
currentPos.current = { cx, cy };
|
|
75
|
+
applyGradientPos(cx, cy);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const handleMouseEnter = (e) => {
|
|
79
|
+
const svg = svgRef.current;
|
|
80
|
+
if (svg) {
|
|
81
|
+
const rect = svg.getBoundingClientRect();
|
|
82
|
+
const cx = (e.clientX - rect.left) / rect.width;
|
|
83
|
+
const cy = (e.clientY - rect.top) / rect.height;
|
|
84
|
+
targetPos.current = { cx, cy };
|
|
85
|
+
currentPos.current = { cx, cy };
|
|
86
|
+
applyGradientPos(cx, cy);
|
|
87
|
+
}
|
|
88
|
+
setHovered(true);
|
|
89
|
+
};
|
|
90
|
+
const spotlightR = vb.h * spotlightSize;
|
|
91
|
+
const strokeW = vb.h * 0.015;
|
|
92
|
+
const initCx = vb.x + 0.5 * vb.w;
|
|
93
|
+
const initCy = vb.y + 0.5 * vb.h;
|
|
94
|
+
const gradientId = `grad-${uid}`;
|
|
95
|
+
const maskId = `mask-${uid}`;
|
|
96
|
+
const revealId = `reveal-${uid}`;
|
|
97
|
+
const stops = colors.map((color, i) => ({
|
|
98
|
+
offset: `${i / Math.max(colors.length - 1, 1) * 100}%`,
|
|
99
|
+
color
|
|
100
|
+
}));
|
|
101
|
+
const textStyle = {
|
|
102
|
+
fontSize: "1em",
|
|
103
|
+
fontFamily,
|
|
104
|
+
fill: "none",
|
|
105
|
+
strokeWidth: strokeW,
|
|
106
|
+
strokeLinejoin: "round",
|
|
107
|
+
strokeLinecap: "round",
|
|
108
|
+
paintOrder: "stroke fill"
|
|
109
|
+
};
|
|
110
|
+
return /* @__PURE__ */ jsxs(
|
|
111
|
+
"svg",
|
|
112
|
+
{
|
|
113
|
+
ref: svgRef,
|
|
114
|
+
"data-slot": "gradient-reveal-text",
|
|
115
|
+
width: "100%",
|
|
116
|
+
viewBox: `${vb.x} ${vb.y} ${vb.w} ${vb.h}`,
|
|
117
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
118
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
119
|
+
onMouseEnter: handleMouseEnter,
|
|
120
|
+
onMouseLeave: () => setHovered(false),
|
|
121
|
+
onMouseMove: updatePos,
|
|
122
|
+
className: cn("select-none", className),
|
|
123
|
+
style: { opacity: measured ? 1 : 0 },
|
|
124
|
+
"aria-hidden": true,
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ jsxs("defs", { children: [
|
|
127
|
+
/* @__PURE__ */ jsx("linearGradient", { id: gradientId, x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: hovered && stops.map((s) => /* @__PURE__ */ jsx("stop", { offset: s.offset, stopColor: s.color }, s.offset)) }),
|
|
128
|
+
/* @__PURE__ */ jsxs(
|
|
129
|
+
"radialGradient",
|
|
130
|
+
{
|
|
131
|
+
ref: gradientRef,
|
|
132
|
+
id: revealId,
|
|
133
|
+
gradientUnits: "userSpaceOnUse",
|
|
134
|
+
r: spotlightR,
|
|
135
|
+
cx: initCx,
|
|
136
|
+
cy: initCy,
|
|
137
|
+
children: [
|
|
138
|
+
/* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "white" }),
|
|
139
|
+
/* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "black" })
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
),
|
|
143
|
+
/* @__PURE__ */ jsx("mask", { id: maskId, children: /* @__PURE__ */ jsx(
|
|
144
|
+
"rect",
|
|
145
|
+
{
|
|
146
|
+
x: vb.x - vb.w,
|
|
147
|
+
y: vb.y - vb.h,
|
|
148
|
+
width: vb.w * 3,
|
|
149
|
+
height: vb.h * 3,
|
|
150
|
+
fill: `url(#${revealId})`
|
|
151
|
+
}
|
|
152
|
+
) })
|
|
153
|
+
] }),
|
|
154
|
+
/* @__PURE__ */ jsx(
|
|
155
|
+
"text",
|
|
156
|
+
{
|
|
157
|
+
ref: textRef,
|
|
158
|
+
x: "50%",
|
|
159
|
+
y: "50%",
|
|
160
|
+
textAnchor: "middle",
|
|
161
|
+
dominantBaseline: "central",
|
|
162
|
+
className: "font-bold",
|
|
163
|
+
style: { fontSize: "1em", fontFamily, visibility: "hidden" },
|
|
164
|
+
children: text
|
|
165
|
+
}
|
|
166
|
+
),
|
|
167
|
+
/* @__PURE__ */ jsx(
|
|
168
|
+
"text",
|
|
169
|
+
{
|
|
170
|
+
x: "50%",
|
|
171
|
+
y: "50%",
|
|
172
|
+
textAnchor: "middle",
|
|
173
|
+
dominantBaseline: "central",
|
|
174
|
+
className: "font-bold stroke-neutral-200 dark:stroke-neutral-800",
|
|
175
|
+
style: {
|
|
176
|
+
...textStyle,
|
|
177
|
+
opacity: hovered ? hoverOpacity : baseOpacity,
|
|
178
|
+
transition: "opacity 0.3s ease"
|
|
179
|
+
},
|
|
180
|
+
children: text
|
|
181
|
+
}
|
|
182
|
+
),
|
|
183
|
+
/* @__PURE__ */ jsx(
|
|
184
|
+
"text",
|
|
185
|
+
{
|
|
186
|
+
x: "50%",
|
|
187
|
+
y: "50%",
|
|
188
|
+
textAnchor: "middle",
|
|
189
|
+
dominantBaseline: "central",
|
|
190
|
+
mask: `url(#${maskId})`,
|
|
191
|
+
className: "font-bold",
|
|
192
|
+
style: {
|
|
193
|
+
...textStyle,
|
|
194
|
+
stroke: `url(#${gradientId})`
|
|
195
|
+
},
|
|
196
|
+
children: text
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export { GradientRevealText };
|
|
205
|
+
//# sourceMappingURL=gradient-reveal-text.js.map
|
|
206
|
+
//# sourceMappingURL=gradient-reveal-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/gradient-reveal-text.tsx"],"names":[],"mappings":"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","file":"gradient-reveal-text.js","sourcesContent":["\"use client\"\n\nimport { useRef, useEffect, useState, useId, useCallback } from \"react\"\nimport { cn } from \"./lib/utils\"\n\ninterface GradientRevealTextProps {\n /** The text to display */\n text: string\n /** Spotlight follow speed in seconds. Default: 0 (instant) */\n duration?: number\n /** Gradient colors for the reveal effect. Default: rainbow */\n colors?: string[]\n /** Base stroke opacity when not hovered. Default: 0.3 */\n baseOpacity?: number\n /** Hovered stroke opacity. Default: 0.7 */\n hoverOpacity?: number\n /** Font family for SVG text. Default: Helvetica Neue */\n fontFamily?: string\n /** Spotlight radius multiplier relative to text height. Default: 0.6 */\n spotlightSize?: number\n className?: string\n}\n\nconst DEFAULT_COLORS = [\n \"#eab308\",\n \"#ef4444\",\n \"#3b82f6\",\n \"#06b6d4\",\n \"#8b5cf6\",\n]\n\n/**\n * Large decorative text with a gradient spotlight that follows the cursor.\n *\n * Renders as an SVG that auto-sizes to fit the text with zero padding.\n * The gradient reveal effect activates on hover — a circular spotlight\n * follows the mouse, revealing rainbow-colored strokes beneath.\n *\n * @example\n * ```tsx\n * <GradientRevealText text=\"HELLO\" />\n * <GradientRevealText text=\"BRAND\" colors={[\"#ff0000\", \"#00ff00\"]} />\n * ```\n */\nfunction GradientRevealText({\n text,\n duration = 0,\n colors = DEFAULT_COLORS,\n baseOpacity = 0.3,\n hoverOpacity = 0.7,\n fontFamily = \"Helvetica Neue, Helvetica, Arial, sans-serif\",\n spotlightSize = 0.6,\n className,\n}: GradientRevealTextProps) {\n const uid = useId()\n const svgRef = useRef<SVGSVGElement>(null)\n const textRef = useRef<SVGTextElement>(null)\n const gradientRef = useRef<SVGRadialGradientElement>(null)\n\n const [vb, setVb] = useState({ x: 0, y: 0, w: 100, h: 20 })\n const [measured, setMeasured] = useState(false)\n const [hovered, setHovered] = useState(false)\n\n // Target position (where cursor is) and current animated position\n const targetPos = useRef({ cx: 0.5, cy: 0.5 })\n const currentPos = useRef({ cx: 0.5, cy: 0.5 })\n const rafId = useRef<number>(0)\n\n // Measure text bbox → set viewBox to fit exactly\n const measure = useCallback(() => {\n const el = textRef.current\n if (!el) return\n const bbox = el.getBBox()\n if (bbox.width === 0) return\n\n setVb({ x: bbox.x, y: bbox.y, w: bbox.width, h: bbox.height })\n setMeasured(true)\n }, [])\n\n useEffect(() => {\n measure()\n document.fonts?.ready?.then(measure)\n }, [text, measure])\n\n // Update the SVG gradient attributes directly (no React re-render)\n const applyGradientPos = useCallback((cx: number, cy: number) => {\n const el = gradientRef.current\n if (!el) return\n const svgCx = vb.x + cx * vb.w\n const svgCy = vb.y + cy * vb.h\n el.setAttribute(\"cx\", String(svgCx))\n el.setAttribute(\"cy\", String(svgCy))\n }, [vb])\n\n // RAF loop for smooth follow\n useEffect(() => {\n if (duration <= 0) return\n\n // Lerp factor: higher = faster catch-up. Derived from duration.\n const speed = 1 - Math.pow(0.001, 1 / (duration * 60))\n\n const tick = () => {\n const cur = currentPos.current\n const tgt = targetPos.current\n cur.cx += (tgt.cx - cur.cx) * speed\n cur.cy += (tgt.cy - cur.cy) * speed\n applyGradientPos(cur.cx, cur.cy)\n rafId.current = requestAnimationFrame(tick)\n }\n\n rafId.current = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(rafId.current)\n }, [duration, applyGradientPos])\n\n const updatePos = (e: React.MouseEvent<SVGSVGElement>) => {\n const svg = svgRef.current\n if (!svg) return\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n\n // If no smooth follow, apply instantly\n if (duration <= 0) {\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n }\n\n const handleMouseEnter = (e: React.MouseEvent<SVGSVGElement>) => {\n // Snap to entry point — no lerp on first frame\n const svg = svgRef.current\n if (svg) {\n const rect = svg.getBoundingClientRect()\n const cx = (e.clientX - rect.left) / rect.width\n const cy = (e.clientY - rect.top) / rect.height\n targetPos.current = { cx, cy }\n currentPos.current = { cx, cy }\n applyGradientPos(cx, cy)\n }\n setHovered(true)\n }\n\n // Derived values\n const spotlightR = vb.h * spotlightSize\n const strokeW = vb.h * 0.015\n const initCx = vb.x + 0.5 * vb.w\n const initCy = vb.y + 0.5 * vb.h\n\n // Unique SVG IDs\n const gradientId = `grad-${uid}`\n const maskId = `mask-${uid}`\n const revealId = `reveal-${uid}`\n\n // Evenly distribute color stops\n const stops = colors.map((color, i) => ({\n offset: `${(i / Math.max(colors.length - 1, 1)) * 100}%`,\n color,\n }))\n\n const textStyle = {\n fontSize: \"1em\",\n fontFamily,\n fill: \"none\",\n strokeWidth: strokeW,\n strokeLinejoin: \"round\" as const,\n strokeLinecap: \"round\" as const,\n paintOrder: \"stroke fill\" as const,\n }\n\n return (\n <svg\n ref={svgRef}\n data-slot=\"gradient-reveal-text\"\n width=\"100%\"\n viewBox={`${vb.x} ${vb.y} ${vb.w} ${vb.h}`}\n preserveAspectRatio=\"xMidYMid meet\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={() => setHovered(false)}\n onMouseMove={updatePos}\n className={cn(\"select-none\", className)}\n style={{ opacity: measured ? 1 : 0 }}\n aria-hidden\n >\n <defs>\n <linearGradient id={gradientId} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n {hovered &&\n stops.map((s) => (\n <stop key={s.offset} offset={s.offset} stopColor={s.color} />\n ))}\n </linearGradient>\n\n <radialGradient\n ref={gradientRef}\n id={revealId}\n gradientUnits=\"userSpaceOnUse\"\n r={spotlightR}\n cx={initCx}\n cy={initCy}\n >\n <stop offset=\"0%\" stopColor=\"white\" />\n <stop offset=\"100%\" stopColor=\"black\" />\n </radialGradient>\n\n <mask id={maskId}>\n <rect\n x={vb.x - vb.w}\n y={vb.y - vb.h}\n width={vb.w * 3}\n height={vb.h * 3}\n fill={`url(#${revealId})`}\n />\n </mask>\n </defs>\n\n {/* Hidden text for measurement */}\n <text\n ref={textRef}\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"font-bold\"\n style={{ fontSize: \"1em\", fontFamily, visibility: \"hidden\" }}\n >\n {text}\n </text>\n\n {/* Base stroke — subtle outline */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"font-bold stroke-neutral-200 dark:stroke-neutral-800\"\n style={{\n ...textStyle,\n opacity: hovered ? hoverOpacity : baseOpacity,\n transition: \"opacity 0.3s ease\",\n }}\n >\n {text}\n </text>\n\n {/* Gradient reveal on hover */}\n <text\n x=\"50%\"\n y=\"50%\"\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n mask={`url(#${maskId})`}\n className=\"font-bold\"\n style={{\n ...textStyle,\n stroke: `url(#${gradientId})`,\n }}\n >\n {text}\n </text>\n </svg>\n )\n}\n\nexport { GradientRevealText }\nexport type { GradientRevealTextProps }\n"]}
|
package/dist/input-group.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ type InputGroupInputProps = React.ComponentProps<"input">;
|
|
|
15
15
|
type InputGroupTextareaProps = React.ComponentProps<"textarea">;
|
|
16
16
|
declare function InputGroup({ className, ...props }: InputGroupProps): react_jsx_runtime.JSX.Element;
|
|
17
17
|
declare const inputGroupAddonVariants: (props?: ({
|
|
18
|
-
align?: "inline-end" | "inline-start" | "block-
|
|
18
|
+
align?: "inline-end" | "inline-start" | "block-end" | "block-start" | null | undefined;
|
|
19
19
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
20
20
|
declare function InputGroupAddon({ className, align, ...props }: InputGroupAddonProps): react_jsx_runtime.JSX.Element;
|
|
21
21
|
declare const inputGroupButtonVariants: (props?: ({
|
package/dist/pagination.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Button } from './chunk-OUFYQLVN.js';
|
|
2
1
|
import { ChevronLeftIcon, ChevronRightIcon, EllipsisIcon } from './chunk-DIGOLJIR.js';
|
|
2
|
+
import { Button } from './chunk-OUFYQLVN.js';
|
|
3
3
|
import { cn } from './chunk-76UQO56T.js';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
|
package/dist/sidebar.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { TooltipProvider, TooltipTrigger, Tooltip, TooltipContent } from './chunk-V4ZX4YCP.js';
|
|
2
1
|
import { useIsMobile } from './chunk-ZZZH3JGW.js';
|
|
2
|
+
import { TooltipProvider, TooltipTrigger, Tooltip, TooltipContent } from './chunk-V4ZX4YCP.js';
|
|
3
3
|
import { Skeleton } from './chunk-7F4MPMLJ.js';
|
|
4
|
-
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription } from './chunk-
|
|
4
|
+
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription } from './chunk-BKTJYX4M.js';
|
|
5
5
|
import { Separator } from './chunk-RPQHL6C5.js';
|
|
6
6
|
import { Input } from './chunk-QFSEK4M6.js';
|
|
7
|
-
import { Button } from './chunk-OUFYQLVN.js';
|
|
8
7
|
import { SidebarPanelIcon } from './chunk-DIGOLJIR.js';
|
|
8
|
+
import { Button } from './chunk-OUFYQLVN.js';
|
|
9
9
|
import { cn } from './chunk-76UQO56T.js';
|
|
10
10
|
import * as React from 'react';
|
|
11
11
|
import { Collapsible } from '@base-ui/react/collapsible';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
interface TextSegment {
|
|
5
|
+
text: string;
|
|
6
|
+
/** Optional className applied to this segment (e.g., bold, colored) */
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
interface TypewriterProps {
|
|
10
|
+
/** Simple string or styled segments for per-word/phrase styling */
|
|
11
|
+
text: string | TextSegment[];
|
|
12
|
+
/** Element to render into. Receives the animated text as children. */
|
|
13
|
+
children: ReactElement;
|
|
14
|
+
/** Time per character in seconds. Default: 0.04 */
|
|
15
|
+
speed?: number;
|
|
16
|
+
/** Delay before typing starts in seconds. Default: 0 */
|
|
17
|
+
delay?: number;
|
|
18
|
+
/** Show a blinking cursor during typing. Default: true */
|
|
19
|
+
cursor?: boolean;
|
|
20
|
+
/** Cursor character. Default: '|' */
|
|
21
|
+
cursorChar?: string;
|
|
22
|
+
/** Trigger when scrolled into view instead of on mount. Default: false */
|
|
23
|
+
onView?: boolean;
|
|
24
|
+
/** Trigger once. Default: true */
|
|
25
|
+
once?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Reveal mode. Default: 'typing'
|
|
28
|
+
* - 'typing': character-by-character like someone typing
|
|
29
|
+
* - 'smooth': sliding mask reveal (cinematic feel)
|
|
30
|
+
*/
|
|
31
|
+
variant?: "typing" | "smooth";
|
|
32
|
+
/** Duration of the smooth reveal in seconds. Default: 2 */
|
|
33
|
+
smoothDuration?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Text reveal animation with two modes:
|
|
37
|
+
*
|
|
38
|
+
* **typing** (default) — character-by-character like someone typing.
|
|
39
|
+
* **smooth** — cinematic sliding mask reveal.
|
|
40
|
+
*
|
|
41
|
+
* Supports plain strings or styled segments for per-word coloring.
|
|
42
|
+
* Zero wrapper divs — renders into the child element via cloneElement.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* // Simple string
|
|
47
|
+
* <Typewriter text="Welcome to the future.">
|
|
48
|
+
* <h1 className="text-4xl font-bold" />
|
|
49
|
+
* </Typewriter>
|
|
50
|
+
*
|
|
51
|
+
* // Per-word styling
|
|
52
|
+
* <Typewriter text={[
|
|
53
|
+
* { text: "Build on " },
|
|
54
|
+
* { text: "Intuition", className: "text-primary font-bold" },
|
|
55
|
+
* ]}>
|
|
56
|
+
* <h1 className="text-4xl" />
|
|
57
|
+
* </Typewriter>
|
|
58
|
+
*
|
|
59
|
+
* // Smooth reveal
|
|
60
|
+
* <Typewriter text="Cinematic reveal." variant="smooth" smoothDuration={1.5}>
|
|
61
|
+
* <h1 className="text-4xl font-bold" />
|
|
62
|
+
* </Typewriter>
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare function Typewriter({ text, children, speed, delay, cursor, cursorChar, onView, once, variant, smoothDuration, }: TypewriterProps): react_jsx_runtime.JSX.Element;
|
|
66
|
+
|
|
67
|
+
export { type TextSegment, Typewriter, type TypewriterProps };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { useRef, useId, useState, useEffect, isValidElement, cloneElement } from 'react';
|
|
2
|
+
import { useInView } from 'motion/react';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
function mergeRef(internalRef, externalRef) {
|
|
6
|
+
return (el) => {
|
|
7
|
+
internalRef.current = el;
|
|
8
|
+
if (typeof externalRef === "function") externalRef(el);
|
|
9
|
+
else if (externalRef && typeof externalRef === "object") {
|
|
10
|
+
externalRef.current = el;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function flattenText(text) {
|
|
15
|
+
if (typeof text === "string") return text;
|
|
16
|
+
return text.map((s) => s.text).join("");
|
|
17
|
+
}
|
|
18
|
+
function buildSegmentContent(segments, charIndex) {
|
|
19
|
+
const nodes = [];
|
|
20
|
+
let remaining = charIndex;
|
|
21
|
+
for (let i = 0; i < segments.length; i++) {
|
|
22
|
+
const seg = segments[i];
|
|
23
|
+
if (remaining <= 0) break;
|
|
24
|
+
const visibleChars = seg.text.slice(0, remaining);
|
|
25
|
+
remaining -= visibleChars.length;
|
|
26
|
+
if (seg.className) {
|
|
27
|
+
nodes.push(
|
|
28
|
+
/* @__PURE__ */ jsx("span", { className: seg.className, children: visibleChars }, i)
|
|
29
|
+
);
|
|
30
|
+
} else {
|
|
31
|
+
nodes.push(visibleChars);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return nodes;
|
|
35
|
+
}
|
|
36
|
+
function BlinkingCursor({ char, id }) {
|
|
37
|
+
const name = `tw-blink-${id}`;
|
|
38
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
"span",
|
|
41
|
+
{
|
|
42
|
+
"aria-hidden": true,
|
|
43
|
+
style: {
|
|
44
|
+
animation: `${name} 0.8s step-end infinite`,
|
|
45
|
+
fontWeight: "normal"
|
|
46
|
+
},
|
|
47
|
+
children: char
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ jsx("style", { children: `@keyframes ${name} { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }` })
|
|
51
|
+
] });
|
|
52
|
+
}
|
|
53
|
+
function Typewriter({
|
|
54
|
+
text,
|
|
55
|
+
children,
|
|
56
|
+
speed = 0.04,
|
|
57
|
+
delay = 0,
|
|
58
|
+
cursor = true,
|
|
59
|
+
cursorChar = "|",
|
|
60
|
+
onView = false,
|
|
61
|
+
once = true,
|
|
62
|
+
variant = "typing",
|
|
63
|
+
smoothDuration = 2
|
|
64
|
+
}) {
|
|
65
|
+
const ref = useRef(null);
|
|
66
|
+
const id = useId().replace(/:/g, "");
|
|
67
|
+
const isInView = useInView(ref, { once, margin: "-50px" });
|
|
68
|
+
const shouldAnimate = onView ? isInView : true;
|
|
69
|
+
if (variant === "smooth") {
|
|
70
|
+
return /* @__PURE__ */ jsx(
|
|
71
|
+
SmoothReveal,
|
|
72
|
+
{
|
|
73
|
+
text,
|
|
74
|
+
elementRef: ref,
|
|
75
|
+
id,
|
|
76
|
+
delay,
|
|
77
|
+
duration: smoothDuration,
|
|
78
|
+
cursor,
|
|
79
|
+
cursorChar,
|
|
80
|
+
shouldAnimate,
|
|
81
|
+
children
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
return /* @__PURE__ */ jsx(
|
|
86
|
+
TypingReveal,
|
|
87
|
+
{
|
|
88
|
+
text,
|
|
89
|
+
elementRef: ref,
|
|
90
|
+
id,
|
|
91
|
+
speed,
|
|
92
|
+
delay,
|
|
93
|
+
cursor,
|
|
94
|
+
cursorChar,
|
|
95
|
+
shouldAnimate,
|
|
96
|
+
children
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
function TypingReveal({
|
|
101
|
+
text,
|
|
102
|
+
children,
|
|
103
|
+
elementRef,
|
|
104
|
+
id,
|
|
105
|
+
speed,
|
|
106
|
+
delay,
|
|
107
|
+
cursor,
|
|
108
|
+
cursorChar,
|
|
109
|
+
shouldAnimate
|
|
110
|
+
}) {
|
|
111
|
+
const flat = flattenText(text);
|
|
112
|
+
const segments = typeof text === "string" ? [{ text }] : text;
|
|
113
|
+
const [charIndex, setCharIndex] = useState(0);
|
|
114
|
+
const [started, setStarted] = useState(false);
|
|
115
|
+
const [done, setDone] = useState(false);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!shouldAnimate || started) return;
|
|
118
|
+
const timer = setTimeout(() => setStarted(true), delay * 1e3);
|
|
119
|
+
return () => clearTimeout(timer);
|
|
120
|
+
}, [shouldAnimate, delay, started]);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (!started || done) return;
|
|
123
|
+
if (charIndex >= flat.length) {
|
|
124
|
+
setDone(true);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const timer = setTimeout(() => setCharIndex((prev) => prev + 1), speed * 1e3);
|
|
128
|
+
return () => clearTimeout(timer);
|
|
129
|
+
}, [started, charIndex, flat.length, speed, done]);
|
|
130
|
+
if (!isValidElement(children)) return children;
|
|
131
|
+
const childProps = children.props;
|
|
132
|
+
const existingRef = childProps.ref;
|
|
133
|
+
const content = started ? buildSegmentContent(segments, charIndex) : null;
|
|
134
|
+
const showCursor = cursor && started && !done;
|
|
135
|
+
return cloneElement(children, {
|
|
136
|
+
ref: mergeRef(elementRef, existingRef),
|
|
137
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138
|
+
content,
|
|
139
|
+
showCursor && /* @__PURE__ */ jsx(BlinkingCursor, { char: cursorChar, id })
|
|
140
|
+
] })
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function SmoothReveal({
|
|
144
|
+
text,
|
|
145
|
+
children,
|
|
146
|
+
elementRef,
|
|
147
|
+
id,
|
|
148
|
+
delay,
|
|
149
|
+
duration,
|
|
150
|
+
cursor,
|
|
151
|
+
cursorChar,
|
|
152
|
+
shouldAnimate
|
|
153
|
+
}) {
|
|
154
|
+
const segments = typeof text === "string" ? [{ text }] : text;
|
|
155
|
+
const [revealed, setRevealed] = useState(false);
|
|
156
|
+
const [done, setDone] = useState(false);
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
if (!shouldAnimate || revealed) return;
|
|
159
|
+
const timer = setTimeout(() => setRevealed(true), delay * 1e3);
|
|
160
|
+
return () => clearTimeout(timer);
|
|
161
|
+
}, [shouldAnimate, delay, revealed]);
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (!revealed) return;
|
|
164
|
+
const timer = setTimeout(() => setDone(true), duration * 1e3);
|
|
165
|
+
return () => clearTimeout(timer);
|
|
166
|
+
}, [revealed, duration]);
|
|
167
|
+
if (!isValidElement(children)) return children;
|
|
168
|
+
const childProps = children.props;
|
|
169
|
+
const existingRef = childProps.ref;
|
|
170
|
+
const existingStyle = childProps.style ?? {};
|
|
171
|
+
const animName = `tw-smooth-${id}`;
|
|
172
|
+
const showCursor = cursor && revealed && !done;
|
|
173
|
+
const fullContent = segments.map(
|
|
174
|
+
(seg, i) => seg.className ? /* @__PURE__ */ jsx("span", { className: seg.className, children: seg.text }, i) : seg.text
|
|
175
|
+
);
|
|
176
|
+
return cloneElement(children, {
|
|
177
|
+
ref: mergeRef(elementRef, existingRef),
|
|
178
|
+
style: {
|
|
179
|
+
...existingStyle,
|
|
180
|
+
whiteSpace: "nowrap",
|
|
181
|
+
overflow: "hidden",
|
|
182
|
+
...revealed ? {
|
|
183
|
+
animation: `${animName} ${duration}s linear forwards`
|
|
184
|
+
} : {
|
|
185
|
+
maxWidth: 0
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
189
|
+
/* @__PURE__ */ jsx("style", { children: `@keyframes ${animName} { from { max-width: 0; } to { max-width: 100%; } }` }),
|
|
190
|
+
fullContent,
|
|
191
|
+
showCursor && /* @__PURE__ */ jsx(BlinkingCursor, { char: cursorChar, id })
|
|
192
|
+
] })
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export { Typewriter };
|
|
197
|
+
//# sourceMappingURL=typewriter.js.map
|
|
198
|
+
//# sourceMappingURL=typewriter.js.map
|