masoneffect 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/README.md +15 -2
  2. package/dist/core/index.d.ts +2 -0
  3. package/dist/core/index.d.ts.map +1 -1
  4. package/dist/core/typing/index.d.ts +52 -0
  5. package/dist/core/typing/index.d.ts.map +1 -0
  6. package/dist/count/core/index.d.ts +2 -0
  7. package/dist/count/core/index.d.ts.map +1 -1
  8. package/dist/count/core/typing/index.d.ts +52 -0
  9. package/dist/count/core/typing/index.d.ts.map +1 -0
  10. package/dist/count/index.d.ts +2 -0
  11. package/dist/count/index.d.ts.map +1 -1
  12. package/dist/count/react/index.d.ts +2 -0
  13. package/dist/count/react/index.d.ts.map +1 -1
  14. package/dist/count/react/typing/Typing.d.ts +18 -0
  15. package/dist/count/react/typing/Typing.d.ts.map +1 -0
  16. package/dist/count/react/typing/index.d.ts +4 -0
  17. package/dist/count/react/typing/index.d.ts.map +1 -0
  18. package/dist/count/svelte/index.d.ts +1 -0
  19. package/dist/count/svelte/index.d.ts.map +1 -1
  20. package/dist/count/svelte/typing/index.d.ts +3 -0
  21. package/dist/count/svelte/typing/index.d.ts.map +1 -0
  22. package/dist/count/vue/index.d.ts +1 -0
  23. package/dist/count/vue/index.d.ts.map +1 -1
  24. package/dist/count/vue/typing/index.d.ts +4 -0
  25. package/dist/count/vue/typing/index.d.ts.map +1 -0
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.mjs +1 -1
  30. package/dist/react/core/index.d.ts +2 -0
  31. package/dist/react/core/typing/index.d.ts +51 -0
  32. package/dist/react/count/core/index.d.ts +2 -0
  33. package/dist/react/count/core/index.d.ts.map +1 -1
  34. package/dist/react/count/core/typing/index.d.ts +52 -0
  35. package/dist/react/count/core/typing/index.d.ts.map +1 -0
  36. package/dist/react/count/index.d.ts +2 -0
  37. package/dist/react/count/index.d.ts.map +1 -1
  38. package/dist/react/count/react/index.d.ts +2 -0
  39. package/dist/react/count/react/index.d.ts.map +1 -1
  40. package/dist/react/count/react/typing/Typing.d.ts +18 -0
  41. package/dist/react/count/react/typing/Typing.d.ts.map +1 -0
  42. package/dist/react/count/react/typing/index.d.ts +4 -0
  43. package/dist/react/count/react/typing/index.d.ts.map +1 -0
  44. package/dist/react/count/svelte/index.d.ts +1 -0
  45. package/dist/react/count/svelte/index.d.ts.map +1 -1
  46. package/dist/react/count/svelte/typing/index.d.ts +3 -0
  47. package/dist/react/count/svelte/typing/index.d.ts.map +1 -0
  48. package/dist/react/count/vue/index.d.ts +1 -0
  49. package/dist/react/count/vue/index.d.ts.map +1 -1
  50. package/dist/react/count/vue/typing/index.d.ts +4 -0
  51. package/dist/react/count/vue/typing/index.d.ts.map +1 -0
  52. package/dist/react/index.cjs +2 -0
  53. package/dist/react/index.d.ts.map +1 -1
  54. package/dist/react/index.mjs +1 -0
  55. package/dist/react/react/index.d.ts +2 -0
  56. package/dist/react/react/typing/Typing.d.ts +17 -0
  57. package/dist/react/react/typing/index.d.ts +3 -0
  58. package/dist/react/svelte/index.d.ts +1 -0
  59. package/dist/react/svelte/typing/index.d.ts +2 -0
  60. package/dist/react/textToParticle/core/index.d.ts +2 -0
  61. package/dist/react/textToParticle/core/index.d.ts.map +1 -1
  62. package/dist/react/textToParticle/core/typing/index.d.ts +52 -0
  63. package/dist/react/textToParticle/core/typing/index.d.ts.map +1 -0
  64. package/dist/react/textToParticle/index.d.ts +2 -0
  65. package/dist/react/textToParticle/index.d.ts.map +1 -1
  66. package/dist/react/textToParticle/react/index.d.ts +2 -0
  67. package/dist/react/textToParticle/react/index.d.ts.map +1 -1
  68. package/dist/react/textToParticle/react/typing/Typing.d.ts +18 -0
  69. package/dist/react/textToParticle/react/typing/Typing.d.ts.map +1 -0
  70. package/dist/react/textToParticle/react/typing/index.d.ts +4 -0
  71. package/dist/react/textToParticle/react/typing/index.d.ts.map +1 -0
  72. package/dist/react/textToParticle/svelte/index.d.ts +1 -0
  73. package/dist/react/textToParticle/svelte/index.d.ts.map +1 -1
  74. package/dist/react/textToParticle/svelte/typing/index.d.ts +3 -0
  75. package/dist/react/textToParticle/svelte/typing/index.d.ts.map +1 -0
  76. package/dist/react/textToParticle/vue/index.d.ts +1 -0
  77. package/dist/react/textToParticle/vue/index.d.ts.map +1 -1
  78. package/dist/react/textToParticle/vue/typing/index.d.ts +4 -0
  79. package/dist/react/textToParticle/vue/typing/index.d.ts.map +1 -0
  80. package/dist/react/typing/Typing.d.ts +18 -0
  81. package/dist/react/typing/Typing.d.ts.map +1 -0
  82. package/dist/react/typing/core/count/index.d.ts +52 -0
  83. package/dist/react/typing/core/count/index.d.ts.map +1 -0
  84. package/dist/react/typing/core/index.d.ts +20 -0
  85. package/dist/react/typing/core/index.d.ts.map +1 -0
  86. package/dist/react/typing/core/textToParticle/index.d.ts +103 -0
  87. package/dist/react/typing/core/textToParticle/index.d.ts.map +1 -0
  88. package/dist/react/typing/core/typing/index.d.ts +52 -0
  89. package/dist/react/typing/core/typing/index.d.ts.map +1 -0
  90. package/dist/react/typing/index.cjs +1 -0
  91. package/dist/react/typing/index.d.ts +18 -0
  92. package/dist/react/typing/index.d.ts.map +1 -0
  93. package/dist/react/typing/index.mjs +1 -0
  94. package/dist/react/typing/index.umd.d.ts +7 -0
  95. package/dist/react/typing/index.umd.d.ts.map +1 -0
  96. package/dist/react/typing/react/MasonEffect.d.ts +32 -0
  97. package/dist/react/typing/react/MasonEffect.d.ts.map +1 -0
  98. package/dist/react/typing/react/count/Count.d.ts +19 -0
  99. package/dist/react/typing/react/count/Count.d.ts.map +1 -0
  100. package/dist/react/typing/react/count/index.d.ts +5 -0
  101. package/dist/react/typing/react/count/index.d.ts.map +1 -0
  102. package/dist/react/typing/react/index.d.ts +14 -0
  103. package/dist/react/typing/react/index.d.ts.map +1 -0
  104. package/dist/react/typing/react/textToParticle/TextToParticle.d.ts +15 -0
  105. package/dist/react/typing/react/textToParticle/TextToParticle.d.ts.map +1 -0
  106. package/dist/react/typing/react/textToParticle/index.d.ts +4 -0
  107. package/dist/react/typing/react/textToParticle/index.d.ts.map +1 -0
  108. package/dist/react/typing/react/typing/Typing.d.ts +18 -0
  109. package/dist/react/typing/react/typing/Typing.d.ts.map +1 -0
  110. package/dist/react/typing/react/typing/index.d.ts +4 -0
  111. package/dist/react/typing/react/typing/index.d.ts.map +1 -0
  112. package/dist/react/typing/svelte/count/index.d.ts +2 -0
  113. package/dist/react/typing/svelte/count/index.d.ts.map +1 -0
  114. package/dist/react/typing/svelte/index.d.ts +9 -0
  115. package/dist/react/typing/svelte/index.d.ts.map +1 -0
  116. package/dist/react/typing/svelte/textToParticle/index.d.ts +2 -0
  117. package/dist/react/typing/svelte/textToParticle/index.d.ts.map +1 -0
  118. package/dist/react/typing/svelte/typing/index.d.ts +3 -0
  119. package/dist/react/typing/svelte/typing/index.d.ts.map +1 -0
  120. package/dist/react/typing/vue/count/index.d.ts +2 -0
  121. package/dist/react/typing/vue/count/index.d.ts.map +1 -0
  122. package/dist/react/typing/vue/index.d.ts +9 -0
  123. package/dist/react/typing/vue/index.d.ts.map +1 -0
  124. package/dist/react/typing/vue/textToParticle/index.d.ts +2 -0
  125. package/dist/react/typing/vue/textToParticle/index.d.ts.map +1 -0
  126. package/dist/react/typing/vue/typing/index.d.ts +4 -0
  127. package/dist/react/typing/vue/typing/index.d.ts.map +1 -0
  128. package/dist/react/vue/index.d.ts +1 -0
  129. package/dist/react/vue/typing/index.d.ts +3 -0
  130. package/dist/svelte/count/index.d.ts +52 -0
  131. package/dist/svelte/index.cjs +1 -1
  132. package/dist/svelte/index.d.ts +52 -0
  133. package/dist/svelte/index.mjs +415 -48
  134. package/dist/svelte/textToParticle/index.d.ts +52 -0
  135. package/dist/svelte/typing/index.cjs +1 -0
  136. package/dist/svelte/typing/index.d.ts +215 -0
  137. package/dist/svelte/typing/index.mjs +634 -0
  138. package/dist/textToParticle/core/index.d.ts +2 -0
  139. package/dist/textToParticle/core/index.d.ts.map +1 -1
  140. package/dist/textToParticle/core/typing/index.d.ts +52 -0
  141. package/dist/textToParticle/core/typing/index.d.ts.map +1 -0
  142. package/dist/textToParticle/index.d.ts +2 -0
  143. package/dist/textToParticle/index.d.ts.map +1 -1
  144. package/dist/textToParticle/react/index.d.ts +2 -0
  145. package/dist/textToParticle/react/index.d.ts.map +1 -1
  146. package/dist/textToParticle/react/typing/Typing.d.ts +18 -0
  147. package/dist/textToParticle/react/typing/Typing.d.ts.map +1 -0
  148. package/dist/textToParticle/react/typing/index.d.ts +4 -0
  149. package/dist/textToParticle/react/typing/index.d.ts.map +1 -0
  150. package/dist/textToParticle/svelte/index.d.ts +1 -0
  151. package/dist/textToParticle/svelte/index.d.ts.map +1 -1
  152. package/dist/textToParticle/svelte/typing/index.d.ts +3 -0
  153. package/dist/textToParticle/svelte/typing/index.d.ts.map +1 -0
  154. package/dist/textToParticle/vue/index.d.ts +1 -0
  155. package/dist/textToParticle/vue/index.d.ts.map +1 -1
  156. package/dist/textToParticle/vue/typing/index.d.ts +4 -0
  157. package/dist/textToParticle/vue/typing/index.d.ts.map +1 -0
  158. package/dist/typing/core/count/index.d.ts +52 -0
  159. package/dist/typing/core/count/index.d.ts.map +1 -0
  160. package/dist/typing/core/index.d.ts +20 -0
  161. package/dist/typing/core/index.d.ts.map +1 -0
  162. package/dist/typing/core/textToParticle/index.d.ts +103 -0
  163. package/dist/typing/core/textToParticle/index.d.ts.map +1 -0
  164. package/dist/typing/core/typing/index.d.ts +52 -0
  165. package/dist/typing/core/typing/index.d.ts.map +1 -0
  166. package/dist/typing/index.cjs +1 -0
  167. package/dist/typing/index.d.ts +18 -0
  168. package/dist/typing/index.d.ts.map +1 -0
  169. package/dist/typing/index.mjs +1 -0
  170. package/dist/typing/index.umd.d.ts +7 -0
  171. package/dist/typing/index.umd.d.ts.map +1 -0
  172. package/dist/typing/react/MasonEffect.d.ts +32 -0
  173. package/dist/typing/react/MasonEffect.d.ts.map +1 -0
  174. package/dist/typing/react/count/Count.d.ts +19 -0
  175. package/dist/typing/react/count/Count.d.ts.map +1 -0
  176. package/dist/typing/react/count/index.d.ts +5 -0
  177. package/dist/typing/react/count/index.d.ts.map +1 -0
  178. package/dist/typing/react/index.d.ts +14 -0
  179. package/dist/typing/react/index.d.ts.map +1 -0
  180. package/dist/typing/react/textToParticle/TextToParticle.d.ts +15 -0
  181. package/dist/typing/react/textToParticle/TextToParticle.d.ts.map +1 -0
  182. package/dist/typing/react/textToParticle/index.d.ts +4 -0
  183. package/dist/typing/react/textToParticle/index.d.ts.map +1 -0
  184. package/dist/typing/react/typing/Typing.d.ts +18 -0
  185. package/dist/typing/react/typing/Typing.d.ts.map +1 -0
  186. package/dist/typing/react/typing/index.d.ts +4 -0
  187. package/dist/typing/react/typing/index.d.ts.map +1 -0
  188. package/dist/typing/svelte/count/index.d.ts +2 -0
  189. package/dist/typing/svelte/count/index.d.ts.map +1 -0
  190. package/dist/typing/svelte/index.d.ts +9 -0
  191. package/dist/typing/svelte/index.d.ts.map +1 -0
  192. package/dist/typing/svelte/textToParticle/index.d.ts +2 -0
  193. package/dist/typing/svelte/textToParticle/index.d.ts.map +1 -0
  194. package/dist/typing/svelte/typing/index.d.ts +3 -0
  195. package/dist/typing/svelte/typing/index.d.ts.map +1 -0
  196. package/dist/typing/vue/count/index.d.ts +2 -0
  197. package/dist/typing/vue/count/index.d.ts.map +1 -0
  198. package/dist/typing/vue/index.d.ts +9 -0
  199. package/dist/typing/vue/index.d.ts.map +1 -0
  200. package/dist/typing/vue/textToParticle/index.d.ts +2 -0
  201. package/dist/typing/vue/textToParticle/index.d.ts.map +1 -0
  202. package/dist/typing/vue/typing/index.d.ts +4 -0
  203. package/dist/typing/vue/typing/index.d.ts.map +1 -0
  204. package/dist/vue/count/index.d.ts +52 -0
  205. package/dist/vue/index.cjs +1 -1
  206. package/dist/vue/index.d.ts +52 -0
  207. package/dist/vue/index.mjs +312 -7
  208. package/dist/vue/textToParticle/index.d.ts +52 -0
  209. package/dist/vue/typing/index.cjs +1 -0
  210. package/dist/vue/typing/index.d.ts +215 -0
  211. package/dist/vue/typing/index.mjs +308 -0
  212. package/package.json +25 -2
@@ -0,0 +1 @@
1
+ "use strict";const t=require("vue");function e(t){const e=t.charCodeAt(0);if(e<44032||e>55203)return[t];const i=e-44032,s=Math.floor(i/588),n=Math.floor(i%588/28),r=i%28,o=["","ㄱ","ㄲ","ㄳ","ㄴ","ㄵ","ㄶ","ㄷ","ㄹ","ㄺ","ㄻ","ㄼ","ㄽ","ㄾ","ㄿ","ㅀ","ㅁ","ㅂ","ㅄ","ㅅ","ㅆ","ㅇ","ㅈ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"],h=[];return h.push(["ㄱ","ㄲ","ㄴ","ㄷ","ㄸ","ㄹ","ㅁ","ㅂ","ㅃ","ㅅ","ㅆ","ㅇ","ㅈ","ㅉ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"][s]),h.push(["ㅏ","ㅐ","ㅑ","ㅒ","ㅓ","ㅔ","ㅕ","ㅖ","ㅗ","ㅘ","ㅙ","ㅚ","ㅛ","ㅜ","ㅝ","ㅞ","ㅟ","ㅠ","ㅡ","ㅢ","ㅣ"][n]),r>0&&h.push(o[r]),h}function i(t){const i=[];for(let s=0;s<t.length;s++){const n=t[s],r=n.charCodeAt(0);if(r>=44032&&r<=55203){const t=e(n);i.push(...t)}else i.push(n)}return i}class s{constructor(t,e){if(this.originalChars=[],this.charUnitMap=[],this.container="string"==typeof t?document.querySelector(t):t,!this.container)throw new Error("Container element not found");this.originalText=e.text,this.config={text:e.text,speed:e.speed??50,delay:e.delay??0,enabled:e.enabled??!0,threshold:e.threshold??.2,rootMargin:e.rootMargin??"0px 0px -100px 0px",triggerOnce:e.triggerOnce??!1,showCursor:e.showCursor??!0,cursorChar:e.cursorChar??"|",onUpdate:e.onUpdate||null,onComplete:e.onComplete||null},this.textUnits=i(this.config.text),this.originalChars=[],this.charUnitMap=[],this.initializeTextStructure(),this.currentIndex=0,this.displayedText="",this.timeoutId=null,this.intersectionObserver=null,this.isRunning=!1,this.hasTriggered=!1,this.init()}init(){this.updateDisplay(""),this.setupIntersectionObserver()}setupIntersectionObserver(){"undefined"!=typeof window&&void 0!==window.IntersectionObserver?(this.intersectionObserver=new IntersectionObserver(t=>{var e;for(const i of t)i.target===this.container&&i.isIntersecting&&!this.hasTriggered&&(this.config.enabled&&setTimeout(()=>this.start(),this.config.delay),this.hasTriggered=!0,this.config.triggerOnce&&(null==(e=this.intersectionObserver)||e.disconnect()))},{threshold:this.config.threshold,rootMargin:this.config.rootMargin}),this.intersectionObserver.observe(this.container)):this.config.enabled&&setTimeout(()=>this.start(),this.config.delay)}initializeTextStructure(){this.originalChars=[],this.charUnitMap=[];for(let t=0;t<this.originalText.length;t++){const i=this.originalText[t],s=i.charCodeAt(0);if(this.originalChars.push(i),s>=44032&&s<=55203){const t=e(i);this.charUnitMap.push(t.length)}else this.charUnitMap.push(1)}}getCharIndexFromUnitIndex(t){if(0===t)return 0;let e=0,i=0;for(let s=0;s<this.charUnitMap.length;s++){const n=this.charUnitMap[s];if(i+=n,!(t>=i)){const r=t-(i-n);if(r>0){const t=this.originalChars[s]&&this.originalChars[s].charCodeAt(0)>=44032&&this.originalChars[s].charCodeAt(0)<=55203;(t&&r>=2||!t&&r>=1)&&(e=s+1)}break}e=s+1}return e}buildTextFromUnits(t){if(0===t.length)return"";const e=this.getCharIndexFromUnitIndex(t.length);return this.originalText.substring(0,e)}start(){this.isRunning||(this.isRunning=!0,this.currentIndex=0,this.displayedText="",this.typeNext())}typeNext(){if(this.currentIndex>=this.textUnits.length)return this.isRunning=!1,this.config.showCursor&&this.updateDisplay(this.originalText),void(this.config.onComplete&&this.config.onComplete());const t=this.textUnits.slice(0,this.currentIndex+1);this.displayedText=this.buildTextFromUnits(t);let e=this.displayedText;this.config.showCursor&&(e+=this.config.cursorChar),this.updateDisplay(e),this.config.onUpdate&&this.config.onUpdate(this.displayedText),this.currentIndex++,this.timeoutId=setTimeout(()=>{this.typeNext()},this.config.speed)}stop(){this.isRunning=!1,this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=null)}reset(){this.stop(),this.currentIndex=0,this.displayedText="",this.hasTriggered=!1,this.updateDisplay("")}updateDisplay(t){this.container.textContent=t}setText(t){this.originalText=t,this.config.text=t,this.textUnits=i(t),this.initializeTextStructure(),this.reset(),this.config.enabled&&setTimeout(()=>this.start(),this.config.delay)}destroy(){this.stop(),this.intersectionObserver&&(this.intersectionObserver.disconnect(),this.intersectionObserver=null)}}const n=t.defineComponent({__name:"Typing",props:{className:{},style:{},onUpdate:{},onComplete:{},text:{},speed:{default:50},delay:{default:0},enabled:{type:Boolean,default:!0},threshold:{default:.2},rootMargin:{default:"0px 0px -100px 0px"},triggerOnce:{type:Boolean,default:!1},showCursor:{type:Boolean,default:!0},cursorChar:{default:"|"}},setup(e,{expose:i}){const n=e,r=t.ref(null),o=t.ref(null);return t.onMounted(()=>{if(!r.value)return;const t={text:n.text,speed:n.speed,delay:n.delay,enabled:n.enabled,threshold:n.threshold,rootMargin:n.rootMargin,triggerOnce:n.triggerOnce,showCursor:n.showCursor,cursorChar:n.cursorChar,onUpdate:n.onUpdate,onComplete:n.onComplete};o.value=new s(r.value,t)}),t.onUnmounted(()=>{o.value&&(o.value.destroy(),o.value=null)}),t.watch(()=>n.text,t=>{o.value&&t!==o.value.originalText&&o.value.setText(t)}),i({start:()=>{var t;return null==(t=o.value)?void 0:t.start()},stop:()=>{var t;return null==(t=o.value)?void 0:t.stop()},reset:()=>{var t;return null==(t=o.value)?void 0:t.reset()},setText:t=>{var e;return null==(e=o.value)?void 0:e.setText(t)},destroy:()=>{o.value&&(o.value.destroy(),o.value=null)}}),(i,s)=>(t.openBlock(),t.createElementBlock("div",{ref_key:"containerRef",ref:r,class:t.normalizeClass(e.className),style:t.normalizeStyle(e.style)},null,6))}});module.exports=n;
@@ -0,0 +1,215 @@
1
+ export declare class Count {
2
+ container: HTMLElement;
3
+ config: Required<Omit<CountOptions, 'onUpdate' | 'onComplete'>> & {
4
+ onUpdate: CountOptions['onUpdate'];
5
+ onComplete: CountOptions['onComplete'];
6
+ };
7
+ currentValue: number;
8
+ startTime: number | null;
9
+ animationFrameId: number | null;
10
+ intersectionObserver: IntersectionObserver | null;
11
+ isRunning: boolean;
12
+ hasTriggered: boolean;
13
+ constructor(container: HTMLElement | string, options: CountOptions);
14
+ init(): void;
15
+ setupIntersectionObserver(): void;
16
+ start(): void;
17
+ stop(): void;
18
+ reset(): void;
19
+ updateDisplay(value: number): void;
20
+ formatNumber(value: number): string;
21
+ updateConfig(newConfig: Partial<CountOptions>): void;
22
+ getValue(): number;
23
+ destroy(): void;
24
+ }
25
+
26
+ /**
27
+ * Count - 숫자 카운팅 애니메이션 효과
28
+ * 바닐라 JS 코어 클래스
29
+ *
30
+ * 사용법:
31
+ * import { Count } from 'masoneffect/count';
32
+ */
33
+ export declare interface CountOptions {
34
+ targetValue: number;
35
+ duration?: number;
36
+ startValue?: number;
37
+ enabled?: boolean;
38
+ easing?: (t: number) => number;
39
+ threshold?: number;
40
+ rootMargin?: string;
41
+ triggerOnce?: boolean;
42
+ onUpdate?: (value: number) => void;
43
+ onComplete?: () => void;
44
+ }
45
+
46
+ export declare const easingFunctions: {
47
+ linear: (t: number) => number;
48
+ easeInQuad: (t: number) => number;
49
+ easeOutQuad: (t: number) => number;
50
+ easeInOutQuad: (t: number) => number;
51
+ easeOutCubic: (t: number) => number;
52
+ };
53
+
54
+ export declare interface Particle {
55
+ x: number;
56
+ y: number;
57
+ vx: number;
58
+ vy: number;
59
+ tx: number;
60
+ ty: number;
61
+ initialX?: number;
62
+ initialY?: number;
63
+ j: number;
64
+ }
65
+
66
+ declare class TextToParticle {
67
+ container: HTMLElement;
68
+ config: Required<Omit<TextToParticleOptions, 'onReady' | 'onUpdate' | 'debounceDelay'>> & {
69
+ onReady: TextToParticleOptions['onReady'];
70
+ onUpdate: TextToParticleOptions['onUpdate'];
71
+ };
72
+ canvas: HTMLCanvasElement;
73
+ ctx: CanvasRenderingContext2D;
74
+ offCanvas: HTMLCanvasElement;
75
+ offCtx: CanvasRenderingContext2D;
76
+ W: number;
77
+ H: number;
78
+ DPR: number;
79
+ particles: Particle[];
80
+ mouse: {
81
+ x: number;
82
+ y: number;
83
+ down: boolean;
84
+ };
85
+ animationId: number | null;
86
+ isRunning: boolean;
87
+ isVisible: boolean;
88
+ intersectionObserver: IntersectionObserver | null;
89
+ debounceDelay: number;
90
+ _debouncedMorph: (textOrOptions?: string | Partial<TextToParticleOptions> | null) => void;
91
+ _debouncedUpdateConfig: (newConfig: Partial<TextToParticleOptions>) => void;
92
+ constructor(container: HTMLElement | string, options?: TextToParticleOptions);
93
+ init(): void;
94
+ setupIntersectionObserver(): void;
95
+ resize(): void;
96
+ /**
97
+ * 텍스트가 영역 안에 들어가는지 확인하는 헬퍼 함수 (줄바꿈 지원)
98
+ * @param fontSize 확인할 폰트 크기
99
+ * @param text 텍스트 (\n으로 줄바꿈 구분)
100
+ * @param maxWidth 최대 너비
101
+ * @param maxHeight 최대 높이
102
+ * @returns { width: number, height: number, fits: boolean }
103
+ */
104
+ private measureTextFit;
105
+ /**
106
+ * 이진 검색을 사용하여 적절한 폰트 크기를 찾는 최적화된 함수
107
+ * 반복 횟수를 O(log n)으로 줄여 성능 개선 (최대 15회 반복, 기존 최대 100회에서 대폭 감소)
108
+ */
109
+ private findOptimalFontSize;
110
+ buildTargets(): void;
111
+ makeParticle(): Particle;
112
+ initParticles(): void;
113
+ scatter(): void;
114
+ morph(textOrOptions?: string | Partial<TextToParticleOptions> | null): void;
115
+ _morphInternal(textOrOptions?: string | Partial<TextToParticleOptions> | null): void;
116
+ update(): void;
117
+ animate(): void;
118
+ start(): void;
119
+ stop(): void;
120
+ setupEventListeners(): void;
121
+ removeEventListeners(): void;
122
+ handleResize(): void;
123
+ handleMouseMove(e: MouseEvent): void;
124
+ handleMouseLeave(): void;
125
+ handleMouseDown(): void;
126
+ handleMouseUp(): void;
127
+ updateConfig(newConfig: Partial<TextToParticleOptions>): void;
128
+ _updateConfigInternal(newConfig: Partial<TextToParticleOptions>): void;
129
+ destroy(): void;
130
+ }
131
+ export { TextToParticle as MasonEffect }
132
+ export { TextToParticle }
133
+ export default TextToParticle;
134
+
135
+ /**
136
+ * TextToParticle - 텍스트를 파티클로 변환하는 효과
137
+ * 바닐라 JS 코어 클래스
138
+ *
139
+ * 사용법:
140
+ * import { TextToParticle } from 'masoneffect/textToParticle';
141
+ */
142
+ declare interface TextToParticleOptions {
143
+ text?: string;
144
+ densityStep?: number;
145
+ maxParticles?: number;
146
+ pointSize?: number;
147
+ ease?: number;
148
+ repelRadius?: number;
149
+ repelStrength?: number;
150
+ particleColor?: string;
151
+ fontFamily?: string;
152
+ fontSize?: number | null;
153
+ width?: number | null;
154
+ height?: number | null;
155
+ devicePixelRatio?: number | null;
156
+ debounceDelay?: number;
157
+ onReady?: (instance: TextToParticle) => void;
158
+ onUpdate?: (instance: TextToParticle) => void;
159
+ }
160
+ export { TextToParticleOptions as MasonEffectOptions }
161
+ export { TextToParticleOptions }
162
+
163
+ export declare class Typing {
164
+ container: HTMLElement;
165
+ config: Required<Omit<TypingOptions, 'onUpdate' | 'onComplete'>> & {
166
+ onUpdate: TypingOptions['onUpdate'];
167
+ onComplete: TypingOptions['onComplete'];
168
+ };
169
+ textUnits: string[];
170
+ currentIndex: number;
171
+ displayedText: string;
172
+ timeoutId: ReturnType<typeof setTimeout> | null;
173
+ intersectionObserver: IntersectionObserver | null;
174
+ isRunning: boolean;
175
+ hasTriggered: boolean;
176
+ originalText: string;
177
+ constructor(container: HTMLElement | string, options: TypingOptions);
178
+ init(): void;
179
+ setupIntersectionObserver(): void;
180
+ private originalChars;
181
+ private charUnitMap;
182
+ private initializeTextStructure;
183
+ private getCharIndexFromUnitIndex;
184
+ private buildTextFromUnits;
185
+ start(): void;
186
+ typeNext(): void;
187
+ stop(): void;
188
+ reset(): void;
189
+ updateDisplay(text: string): void;
190
+ setText(newText: string): void;
191
+ destroy(): void;
192
+ }
193
+
194
+ /**
195
+ * Typing - 타이핑 애니메이션 효과
196
+ * 바닐라 JS 코어 클래스
197
+ *
198
+ * 사용법:
199
+ * import { Typing } from 'masoneffect/typing';
200
+ */
201
+ export declare interface TypingOptions {
202
+ text: string;
203
+ speed?: number;
204
+ delay?: number;
205
+ enabled?: boolean;
206
+ threshold?: number;
207
+ rootMargin?: string;
208
+ triggerOnce?: boolean;
209
+ showCursor?: boolean;
210
+ cursorChar?: string;
211
+ onUpdate?: (text: string) => void;
212
+ onComplete?: () => void;
213
+ }
214
+
215
+ export { }
@@ -0,0 +1,308 @@
1
+ import { defineComponent, ref, onMounted, onUnmounted, watch, createElementBlock, openBlock, normalizeStyle, normalizeClass } from "vue";
2
+ function decomposeHangul(char) {
3
+ const code = char.charCodeAt(0);
4
+ if (code < 44032 || code > 55203) {
5
+ return [char];
6
+ }
7
+ const base = code - 44032;
8
+ const initial = Math.floor(base / (21 * 28));
9
+ const medial = Math.floor(base % (21 * 28) / 28);
10
+ const final = base % 28;
11
+ const initialChars = ["ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
12
+ const medialChars = ["ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ", "ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅘ", "ㅙ", "ㅚ", "ㅛ", "ㅜ", "ㅝ", "ㅞ", "ㅟ", "ㅠ", "ㅡ", "ㅢ", "ㅣ"];
13
+ const finalChars = ["", "ㄱ", "ㄲ", "ㄳ", "ㄴ", "ㄵ", "ㄶ", "ㄷ", "ㄹ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅁ", "ㅂ", "ㅄ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
14
+ const result = [];
15
+ result.push(initialChars[initial]);
16
+ result.push(medialChars[medial]);
17
+ if (final > 0) {
18
+ result.push(finalChars[final]);
19
+ }
20
+ return result;
21
+ }
22
+ function decomposeText(text) {
23
+ const units = [];
24
+ for (let i = 0; i < text.length; i++) {
25
+ const char = text[i];
26
+ const code = char.charCodeAt(0);
27
+ if (code >= 44032 && code <= 55203) {
28
+ const decomposed = decomposeHangul(char);
29
+ units.push(...decomposed);
30
+ } else {
31
+ units.push(char);
32
+ }
33
+ }
34
+ return units;
35
+ }
36
+ class Typing {
37
+ // 원본 텍스트
38
+ constructor(container, options) {
39
+ this.originalChars = [];
40
+ this.charUnitMap = [];
41
+ this.container = typeof container === "string" ? document.querySelector(container) : container;
42
+ if (!this.container) {
43
+ throw new Error("Container element not found");
44
+ }
45
+ this.originalText = options.text;
46
+ this.config = {
47
+ text: options.text,
48
+ speed: options.speed ?? 50,
49
+ delay: options.delay ?? 0,
50
+ enabled: options.enabled ?? true,
51
+ threshold: options.threshold ?? 0.2,
52
+ rootMargin: options.rootMargin ?? "0px 0px -100px 0px",
53
+ triggerOnce: options.triggerOnce ?? false,
54
+ showCursor: options.showCursor ?? true,
55
+ cursorChar: options.cursorChar ?? "|",
56
+ onUpdate: options.onUpdate || null,
57
+ onComplete: options.onComplete || null
58
+ };
59
+ this.textUnits = decomposeText(this.config.text);
60
+ this.originalChars = [];
61
+ this.charUnitMap = [];
62
+ this.initializeTextStructure();
63
+ this.currentIndex = 0;
64
+ this.displayedText = "";
65
+ this.timeoutId = null;
66
+ this.intersectionObserver = null;
67
+ this.isRunning = false;
68
+ this.hasTriggered = false;
69
+ this.init();
70
+ }
71
+ init() {
72
+ this.updateDisplay("");
73
+ this.setupIntersectionObserver();
74
+ }
75
+ setupIntersectionObserver() {
76
+ if (typeof window === "undefined" || typeof window.IntersectionObserver === "undefined") {
77
+ if (this.config.enabled) {
78
+ setTimeout(() => this.start(), this.config.delay);
79
+ }
80
+ return;
81
+ }
82
+ this.intersectionObserver = new IntersectionObserver(
83
+ (entries) => {
84
+ var _a;
85
+ for (const entry of entries) {
86
+ if (entry.target !== this.container) continue;
87
+ if (entry.isIntersecting && !this.hasTriggered) {
88
+ if (this.config.enabled) {
89
+ setTimeout(() => this.start(), this.config.delay);
90
+ }
91
+ this.hasTriggered = true;
92
+ if (this.config.triggerOnce) {
93
+ (_a = this.intersectionObserver) == null ? void 0 : _a.disconnect();
94
+ }
95
+ }
96
+ }
97
+ },
98
+ {
99
+ threshold: this.config.threshold,
100
+ rootMargin: this.config.rootMargin
101
+ }
102
+ );
103
+ this.intersectionObserver.observe(this.container);
104
+ }
105
+ // 각 글자에 해당하는 단위 개수
106
+ initializeTextStructure() {
107
+ this.originalChars = [];
108
+ this.charUnitMap = [];
109
+ for (let i = 0; i < this.originalText.length; i++) {
110
+ const char = this.originalText[i];
111
+ const code = char.charCodeAt(0);
112
+ this.originalChars.push(char);
113
+ if (code >= 44032 && code <= 55203) {
114
+ const decomposed = decomposeHangul(char);
115
+ this.charUnitMap.push(decomposed.length);
116
+ } else {
117
+ this.charUnitMap.push(1);
118
+ }
119
+ }
120
+ }
121
+ // 단위 인덱스를 원본 텍스트의 글자 인덱스로 변환
122
+ // unitIndex: 현재까지 입력된 단위 개수 (0부터 시작)
123
+ // 반환: 표시할 글자 개수 (0부터 시작, exclusive)
124
+ getCharIndexFromUnitIndex(unitIndex) {
125
+ if (unitIndex === 0) return 0;
126
+ let charIndex = 0;
127
+ let currentUnits = 0;
128
+ for (let i = 0; i < this.charUnitMap.length; i++) {
129
+ const unitsForChar = this.charUnitMap[i];
130
+ currentUnits += unitsForChar;
131
+ if (unitIndex >= currentUnits) {
132
+ charIndex = i + 1;
133
+ } else {
134
+ const unitsEntered = unitIndex - (currentUnits - unitsForChar);
135
+ if (unitsEntered > 0) {
136
+ const isHangul = this.originalChars[i] && this.originalChars[i].charCodeAt(0) >= 44032 && this.originalChars[i].charCodeAt(0) <= 55203;
137
+ if (isHangul && unitsEntered >= 2) {
138
+ charIndex = i + 1;
139
+ } else if (!isHangul && unitsEntered >= 1) {
140
+ charIndex = i + 1;
141
+ }
142
+ }
143
+ break;
144
+ }
145
+ }
146
+ return charIndex;
147
+ }
148
+ // 단위들을 다시 합쳐서 실제 표시할 텍스트 생성
149
+ buildTextFromUnits(units) {
150
+ if (units.length === 0) return "";
151
+ const charIndex = this.getCharIndexFromUnitIndex(units.length);
152
+ return this.originalText.substring(0, charIndex);
153
+ }
154
+ start() {
155
+ if (this.isRunning) return;
156
+ this.isRunning = true;
157
+ this.currentIndex = 0;
158
+ this.displayedText = "";
159
+ this.typeNext();
160
+ }
161
+ typeNext() {
162
+ if (this.currentIndex >= this.textUnits.length) {
163
+ this.isRunning = false;
164
+ if (this.config.showCursor) {
165
+ this.updateDisplay(this.originalText);
166
+ }
167
+ if (this.config.onComplete) {
168
+ this.config.onComplete();
169
+ }
170
+ return;
171
+ }
172
+ const unitsToShow = this.textUnits.slice(0, this.currentIndex + 1);
173
+ this.displayedText = this.buildTextFromUnits(unitsToShow);
174
+ let displayText = this.displayedText;
175
+ if (this.config.showCursor) {
176
+ displayText += this.config.cursorChar;
177
+ }
178
+ this.updateDisplay(displayText);
179
+ if (this.config.onUpdate) {
180
+ this.config.onUpdate(this.displayedText);
181
+ }
182
+ this.currentIndex++;
183
+ this.timeoutId = setTimeout(() => {
184
+ this.typeNext();
185
+ }, this.config.speed);
186
+ }
187
+ stop() {
188
+ this.isRunning = false;
189
+ if (this.timeoutId) {
190
+ clearTimeout(this.timeoutId);
191
+ this.timeoutId = null;
192
+ }
193
+ }
194
+ reset() {
195
+ this.stop();
196
+ this.currentIndex = 0;
197
+ this.displayedText = "";
198
+ this.hasTriggered = false;
199
+ this.updateDisplay("");
200
+ }
201
+ updateDisplay(text) {
202
+ this.container.textContent = text;
203
+ }
204
+ // 텍스트 변경
205
+ setText(newText) {
206
+ this.originalText = newText;
207
+ this.config.text = newText;
208
+ this.textUnits = decomposeText(newText);
209
+ this.initializeTextStructure();
210
+ this.reset();
211
+ if (this.config.enabled) {
212
+ setTimeout(() => this.start(), this.config.delay);
213
+ }
214
+ }
215
+ destroy() {
216
+ this.stop();
217
+ if (this.intersectionObserver) {
218
+ this.intersectionObserver.disconnect();
219
+ this.intersectionObserver = null;
220
+ }
221
+ }
222
+ }
223
+ const _sfc_main = /* @__PURE__ */ defineComponent({
224
+ __name: "Typing",
225
+ props: {
226
+ className: {},
227
+ style: {},
228
+ onUpdate: {},
229
+ onComplete: {},
230
+ text: {},
231
+ speed: { default: 50 },
232
+ delay: { default: 0 },
233
+ enabled: { type: Boolean, default: true },
234
+ threshold: { default: 0.2 },
235
+ rootMargin: { default: "0px 0px -100px 0px" },
236
+ triggerOnce: { type: Boolean, default: false },
237
+ showCursor: { type: Boolean, default: true },
238
+ cursorChar: { default: "|" }
239
+ },
240
+ setup(__props, { expose: __expose }) {
241
+ const props = __props;
242
+ const containerRef = ref(null);
243
+ const instanceRef = ref(null);
244
+ onMounted(() => {
245
+ if (!containerRef.value) return;
246
+ const options = {
247
+ text: props.text,
248
+ speed: props.speed,
249
+ delay: props.delay,
250
+ enabled: props.enabled,
251
+ threshold: props.threshold,
252
+ rootMargin: props.rootMargin,
253
+ triggerOnce: props.triggerOnce,
254
+ showCursor: props.showCursor,
255
+ cursorChar: props.cursorChar,
256
+ onUpdate: props.onUpdate,
257
+ onComplete: props.onComplete
258
+ };
259
+ instanceRef.value = new Typing(containerRef.value, options);
260
+ });
261
+ onUnmounted(() => {
262
+ if (instanceRef.value) {
263
+ instanceRef.value.destroy();
264
+ instanceRef.value = null;
265
+ }
266
+ });
267
+ watch(() => props.text, (newText) => {
268
+ if (instanceRef.value && newText !== instanceRef.value["originalText"]) {
269
+ instanceRef.value.setText(newText);
270
+ }
271
+ });
272
+ __expose({
273
+ start: () => {
274
+ var _a;
275
+ return (_a = instanceRef.value) == null ? void 0 : _a.start();
276
+ },
277
+ stop: () => {
278
+ var _a;
279
+ return (_a = instanceRef.value) == null ? void 0 : _a.stop();
280
+ },
281
+ reset: () => {
282
+ var _a;
283
+ return (_a = instanceRef.value) == null ? void 0 : _a.reset();
284
+ },
285
+ setText: (text) => {
286
+ var _a;
287
+ return (_a = instanceRef.value) == null ? void 0 : _a.setText(text);
288
+ },
289
+ destroy: () => {
290
+ if (instanceRef.value) {
291
+ instanceRef.value.destroy();
292
+ instanceRef.value = null;
293
+ }
294
+ }
295
+ });
296
+ return (_ctx, _cache) => {
297
+ return openBlock(), createElementBlock("div", {
298
+ ref_key: "containerRef",
299
+ ref: containerRef,
300
+ class: normalizeClass(__props.className),
301
+ style: normalizeStyle(__props.style)
302
+ }, null, 6);
303
+ };
304
+ }
305
+ });
306
+ export {
307
+ _sfc_main as default
308
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "masoneffect",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "A collection of animation effects library. Supports React, Vue, Svelte, and vanilla JavaScript with Tree-shaking support.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -21,6 +21,11 @@
21
21
  "require": "./dist/count/index.cjs",
22
22
  "types": "./dist/count/index.d.ts"
23
23
  },
24
+ "./typing": {
25
+ "import": "./dist/typing/index.mjs",
26
+ "require": "./dist/typing/index.cjs",
27
+ "types": "./dist/typing/index.d.ts"
28
+ },
24
29
  "./react": {
25
30
  "import": "./dist/react/index.mjs",
26
31
  "require": "./dist/react/index.cjs",
@@ -36,6 +41,11 @@
36
41
  "require": "./dist/react/count/index.cjs",
37
42
  "types": "./dist/react/count/index.d.ts"
38
43
  },
44
+ "./react/typing": {
45
+ "import": "./dist/react/typing/index.mjs",
46
+ "require": "./dist/react/typing/index.cjs",
47
+ "types": "./dist/react/typing/index.d.ts"
48
+ },
39
49
  "./vue": {
40
50
  "import": "./dist/vue/index.mjs",
41
51
  "require": "./dist/vue/index.cjs",
@@ -51,6 +61,11 @@
51
61
  "require": "./dist/vue/count/index.cjs",
52
62
  "types": "./dist/vue/count/index.d.ts"
53
63
  },
64
+ "./vue/typing": {
65
+ "import": "./dist/vue/typing/index.mjs",
66
+ "require": "./dist/vue/typing/index.cjs",
67
+ "types": "./dist/vue/typing/index.d.ts"
68
+ },
54
69
  "./svelte": {
55
70
  "import": "./dist/svelte/index.mjs",
56
71
  "require": "./dist/svelte/index.cjs",
@@ -65,19 +80,26 @@
65
80
  "import": "./dist/svelte/count/index.mjs",
66
81
  "require": "./dist/svelte/count/index.cjs",
67
82
  "types": "./dist/svelte/count/index.d.ts"
83
+ },
84
+ "./svelte/typing": {
85
+ "import": "./dist/svelte/typing/index.mjs",
86
+ "require": "./dist/svelte/typing/index.cjs",
87
+ "types": "./dist/svelte/typing/index.d.ts"
68
88
  }
69
89
  },
70
90
  "files": [
71
91
  "dist"
72
92
  ],
73
93
  "scripts": {
74
- "build": "rollup -c rollup.config.mjs && npm run build:vue && npm run build:vue:textToParticle && npm run build:vue:count && npm run build:svelte && npm run build:svelte:textToParticle && npm run build:svelte:count && node scripts/generate-react-types.js",
94
+ "build": "rollup -c rollup.config.mjs && npm run build:vue && npm run build:vue:textToParticle && npm run build:vue:count && npm run build:vue:typing && npm run build:svelte && npm run build:svelte:textToParticle && npm run build:svelte:count && npm run build:svelte:typing && node scripts/generate-react-types.js",
75
95
  "build:vue": "vite build --config vite.config.vue.mjs",
76
96
  "build:vue:textToParticle": "vite build --config vite.config.vue.textToParticle.mjs",
77
97
  "build:vue:count": "vite build --config vite.config.vue.count.mjs",
98
+ "build:vue:typing": "vite build --config vite.config.vue.typing.mjs",
78
99
  "build:svelte": "vite build --config vite.config.svelte.mjs",
79
100
  "build:svelte:textToParticle": "vite build --config vite.config.svelte.textToParticle.mjs",
80
101
  "build:svelte:count": "vite build --config vite.config.svelte.count.mjs",
102
+ "build:svelte:typing": "vite build --config vite.config.svelte.typing.mjs",
81
103
  "dev": "rollup -c rollup.config.mjs -w",
82
104
  "serve": "npx http-server . -p 8080 -o --cors",
83
105
  "dev:example": "npm run serve",
@@ -108,6 +130,7 @@
108
130
  "bugs": {
109
131
  "url": "https://github.com/fe-hyunsu/masoneffect/issues"
110
132
  },
133
+ "aiAgentGuide": "./llms.txt",
111
134
  "devDependencies": {
112
135
  "@rollup/plugin-commonjs": "^25.0.7",
113
136
  "@rollup/plugin-node-resolve": "^15.2.3",