masoneffect 2.0.3 → 2.0.5

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 (101) hide show
  1. package/README.md +2 -2
  2. package/dist/core/count/index.d.ts +3 -2
  3. package/dist/core/count/index.d.ts.map +1 -1
  4. package/dist/core/textToParticle/index.d.ts +3 -3
  5. package/dist/core/textToParticle/index.d.ts.map +1 -1
  6. package/dist/core/typing/index.d.ts +8 -6
  7. package/dist/core/typing/index.d.ts.map +1 -1
  8. package/dist/core/utils/visibilityManager.d.ts +35 -0
  9. package/dist/core/utils/visibilityManager.d.ts.map +1 -0
  10. package/dist/count/core/count/index.d.ts +3 -2
  11. package/dist/count/core/count/index.d.ts.map +1 -1
  12. package/dist/count/core/textToParticle/index.d.ts +3 -3
  13. package/dist/count/core/textToParticle/index.d.ts.map +1 -1
  14. package/dist/count/core/typing/index.d.ts +8 -6
  15. package/dist/count/core/typing/index.d.ts.map +1 -1
  16. package/dist/count/core/utils/visibilityManager.d.ts +35 -0
  17. package/dist/count/core/utils/visibilityManager.d.ts.map +1 -0
  18. package/dist/count/index.cjs +1 -1
  19. package/dist/count/index.mjs +1 -1
  20. package/dist/index.cjs +1 -1
  21. package/dist/index.mjs +1 -1
  22. package/dist/index.umd.min.js +1 -1
  23. package/dist/react/core/count/index.d.ts +3 -2
  24. package/dist/react/core/textToParticle/index.d.ts +3 -3
  25. package/dist/react/core/typing/index.d.ts +8 -6
  26. package/dist/react/core/utils/visibilityManager.d.ts +34 -0
  27. package/dist/react/count/core/count/index.d.ts +3 -2
  28. package/dist/react/count/core/count/index.d.ts.map +1 -1
  29. package/dist/react/count/core/textToParticle/index.d.ts +3 -3
  30. package/dist/react/count/core/textToParticle/index.d.ts.map +1 -1
  31. package/dist/react/count/core/typing/index.d.ts +8 -6
  32. package/dist/react/count/core/typing/index.d.ts.map +1 -1
  33. package/dist/react/count/core/utils/visibilityManager.d.ts +35 -0
  34. package/dist/react/count/core/utils/visibilityManager.d.ts.map +1 -0
  35. package/dist/react/count/index.cjs +1 -1
  36. package/dist/react/count/index.mjs +1 -1
  37. package/dist/react/textToParticle/core/count/index.d.ts +3 -2
  38. package/dist/react/textToParticle/core/count/index.d.ts.map +1 -1
  39. package/dist/react/textToParticle/core/textToParticle/index.d.ts +3 -3
  40. package/dist/react/textToParticle/core/textToParticle/index.d.ts.map +1 -1
  41. package/dist/react/textToParticle/core/typing/index.d.ts +8 -6
  42. package/dist/react/textToParticle/core/typing/index.d.ts.map +1 -1
  43. package/dist/react/textToParticle/core/utils/visibilityManager.d.ts +35 -0
  44. package/dist/react/textToParticle/core/utils/visibilityManager.d.ts.map +1 -0
  45. package/dist/react/textToParticle/index.cjs +1 -1
  46. package/dist/react/textToParticle/index.mjs +1 -1
  47. package/dist/react/typing/core/count/index.d.ts +3 -2
  48. package/dist/react/typing/core/count/index.d.ts.map +1 -1
  49. package/dist/react/typing/core/textToParticle/index.d.ts +3 -3
  50. package/dist/react/typing/core/textToParticle/index.d.ts.map +1 -1
  51. package/dist/react/typing/core/typing/index.d.ts +8 -6
  52. package/dist/react/typing/core/typing/index.d.ts.map +1 -1
  53. package/dist/react/typing/core/utils/visibilityManager.d.ts +35 -0
  54. package/dist/react/typing/core/utils/visibilityManager.d.ts.map +1 -0
  55. package/dist/react/typing/index.cjs +1 -1
  56. package/dist/react/typing/index.mjs +1 -1
  57. package/dist/svelte/count/index.cjs +1 -1
  58. package/dist/svelte/count/index.d.ts +46 -32
  59. package/dist/svelte/count/index.mjs +120 -42
  60. package/dist/svelte/index.cjs +1 -1
  61. package/dist/svelte/index.d.ts +46 -32
  62. package/dist/svelte/index.mjs +211 -160
  63. package/dist/svelte/textToParticle/index.cjs +1 -1
  64. package/dist/svelte/textToParticle/index.d.ts +46 -32
  65. package/dist/svelte/textToParticle/index.mjs +119 -33
  66. package/dist/svelte/typing/index.cjs +1 -1
  67. package/dist/svelte/typing/index.d.ts +46 -32
  68. package/dist/svelte/typing/index.mjs +174 -85
  69. package/dist/textToParticle/core/count/index.d.ts +3 -2
  70. package/dist/textToParticle/core/count/index.d.ts.map +1 -1
  71. package/dist/textToParticle/core/textToParticle/index.d.ts +3 -3
  72. package/dist/textToParticle/core/textToParticle/index.d.ts.map +1 -1
  73. package/dist/textToParticle/core/typing/index.d.ts +8 -6
  74. package/dist/textToParticle/core/typing/index.d.ts.map +1 -1
  75. package/dist/textToParticle/core/utils/visibilityManager.d.ts +35 -0
  76. package/dist/textToParticle/core/utils/visibilityManager.d.ts.map +1 -0
  77. package/dist/textToParticle/index.cjs +1 -1
  78. package/dist/textToParticle/index.mjs +1 -1
  79. package/dist/typing/core/count/index.d.ts +3 -2
  80. package/dist/typing/core/count/index.d.ts.map +1 -1
  81. package/dist/typing/core/textToParticle/index.d.ts +3 -3
  82. package/dist/typing/core/textToParticle/index.d.ts.map +1 -1
  83. package/dist/typing/core/typing/index.d.ts +8 -6
  84. package/dist/typing/core/typing/index.d.ts.map +1 -1
  85. package/dist/typing/core/utils/visibilityManager.d.ts +35 -0
  86. package/dist/typing/core/utils/visibilityManager.d.ts.map +1 -0
  87. package/dist/typing/index.cjs +1 -1
  88. package/dist/typing/index.mjs +1 -1
  89. package/dist/vue/count/index.cjs +1 -1
  90. package/dist/vue/count/index.d.ts +46 -32
  91. package/dist/vue/count/index.mjs +119 -41
  92. package/dist/vue/index.cjs +1 -1
  93. package/dist/vue/index.d.ts +46 -32
  94. package/dist/vue/index.mjs +209 -158
  95. package/dist/vue/textToParticle/index.cjs +1 -1
  96. package/dist/vue/textToParticle/index.d.ts +46 -32
  97. package/dist/vue/textToParticle/index.mjs +119 -33
  98. package/dist/vue/typing/index.cjs +1 -1
  99. package/dist/vue/typing/index.d.ts +46 -32
  100. package/dist/vue/typing/index.mjs +173 -84
  101. package/package.json +1 -1
@@ -1,4 +1,105 @@
1
1
  import { defineComponent, ref, onMounted, onUnmounted, watch, createElementBlock, openBlock, normalizeStyle, normalizeClass } from "vue";
2
+ class VisibilityManager {
3
+ constructor(container, options = {}) {
4
+ this.container = container;
5
+ this.options = {
6
+ threshold: options.threshold ?? 0.1,
7
+ rootMargin: options.rootMargin ?? "0px",
8
+ onVisible: options.onVisible,
9
+ onHidden: options.onHidden
10
+ };
11
+ this.intersectionObserver = null;
12
+ this.visibilityChangeHandler = null;
13
+ this.isVisible = false;
14
+ this.isPageVisible = typeof document !== "undefined" ? !document.hidden : true;
15
+ this.setupIntersectionObserver();
16
+ this.setupPageVisibility();
17
+ }
18
+ setupIntersectionObserver() {
19
+ if (typeof window === "undefined" || typeof window.IntersectionObserver === "undefined") {
20
+ this.isVisible = true;
21
+ if (this.isPageVisible && this.options.onVisible) {
22
+ this.options.onVisible();
23
+ }
24
+ return;
25
+ }
26
+ this.intersectionObserver = new IntersectionObserver(
27
+ (entries) => {
28
+ for (const entry of entries) {
29
+ if (entry.target !== this.container) continue;
30
+ if (entry.isIntersecting) {
31
+ this.isVisible = true;
32
+ if (this.isPageVisible && this.options.onVisible) {
33
+ this.options.onVisible();
34
+ }
35
+ } else {
36
+ this.isVisible = false;
37
+ if (this.options.onHidden) {
38
+ this.options.onHidden();
39
+ }
40
+ }
41
+ }
42
+ },
43
+ {
44
+ threshold: this.options.threshold,
45
+ rootMargin: this.options.rootMargin
46
+ }
47
+ );
48
+ this.intersectionObserver.observe(this.container);
49
+ }
50
+ setupPageVisibility() {
51
+ if (typeof document === "undefined") return;
52
+ this.visibilityChangeHandler = () => {
53
+ const wasVisible = this.isPageVisible;
54
+ this.isPageVisible = !document.hidden;
55
+ if (document.hidden) {
56
+ if (this.options.onHidden) {
57
+ this.options.onHidden();
58
+ }
59
+ } else if (wasVisible !== this.isPageVisible) {
60
+ if (this.isVisible && this.options.onVisible) {
61
+ this.options.onVisible();
62
+ }
63
+ }
64
+ };
65
+ document.addEventListener("visibilitychange", this.visibilityChangeHandler);
66
+ if (document.hidden && this.isVisible) {
67
+ if (this.options.onHidden) {
68
+ this.options.onHidden();
69
+ }
70
+ }
71
+ }
72
+ /**
73
+ * 현재 요소가 화면에 보이는지 확인
74
+ */
75
+ getIsVisible() {
76
+ return this.isVisible && this.isPageVisible;
77
+ }
78
+ /**
79
+ * 옵션 업데이트
80
+ */
81
+ updateOptions(newOptions) {
82
+ this.options = { ...this.options, ...newOptions };
83
+ if (this.intersectionObserver) {
84
+ this.intersectionObserver.disconnect();
85
+ this.intersectionObserver = null;
86
+ }
87
+ this.setupIntersectionObserver();
88
+ }
89
+ /**
90
+ * 리소스 정리
91
+ */
92
+ destroy() {
93
+ if (this.intersectionObserver) {
94
+ this.intersectionObserver.disconnect();
95
+ this.intersectionObserver = null;
96
+ }
97
+ if (this.visibilityChangeHandler && typeof document !== "undefined") {
98
+ document.removeEventListener("visibilitychange", this.visibilityChangeHandler);
99
+ this.visibilityChangeHandler = null;
100
+ }
101
+ }
102
+ }
2
103
  function decomposeHangul(char) {
3
104
  const code = char.charCodeAt(0);
4
105
  if (code < 44032 || code > 55203) {
@@ -19,25 +120,48 @@ function decomposeHangul(char) {
19
120
  }
20
121
  return result;
21
122
  }
123
+ function composeHangul(initial, medial, final) {
124
+ const initialChars = ["ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
125
+ const medialChars = ["ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ", "ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅘ", "ㅙ", "ㅚ", "ㅛ", "ㅜ", "ㅝ", "ㅞ", "ㅟ", "ㅠ", "ㅡ", "ㅢ", "ㅣ"];
126
+ const finalChars = ["", "ㄱ", "ㄲ", "ㄳ", "ㄴ", "ㄵ", "ㄶ", "ㄷ", "ㄹ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅁ", "ㅂ", "ㅄ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
127
+ const initialIndex = initialChars.indexOf(initial);
128
+ const medialIndex = medialChars.indexOf(medial);
129
+ const finalIndex = final ? finalChars.indexOf(final) : 0;
130
+ if (initialIndex === -1 || medialIndex === -1) {
131
+ return initial + (medial || "") + (final || "");
132
+ }
133
+ const code = 44032 + initialIndex * 21 * 28 + medialIndex * 28 + finalIndex;
134
+ return String.fromCharCode(code);
135
+ }
22
136
  function decomposeText(text) {
23
137
  const units = [];
138
+ const charUnitRanges = [];
24
139
  for (let i = 0; i < text.length; i++) {
25
140
  const char = text[i];
26
141
  const code = char.charCodeAt(0);
142
+ const startIndex = units.length;
27
143
  if (code >= 44032 && code <= 55203) {
28
144
  const decomposed = decomposeHangul(char);
29
145
  units.push(...decomposed);
146
+ charUnitRanges.push({
147
+ start: startIndex,
148
+ end: units.length,
149
+ isHangul: true
150
+ });
30
151
  } else {
31
152
  units.push(char);
153
+ charUnitRanges.push({
154
+ start: startIndex,
155
+ end: units.length,
156
+ isHangul: false
157
+ });
32
158
  }
33
159
  }
34
- return units;
160
+ return { units, charUnitRanges };
35
161
  }
36
162
  class Typing {
37
163
  // 원본 텍스트
38
164
  constructor(container, options) {
39
- this.originalChars = [];
40
- this.charUnitMap = [];
41
165
  this.container = typeof container === "string" ? document.querySelector(container) : container;
42
166
  if (!this.container) {
43
167
  throw new Error("Container element not found");
@@ -56,100 +180,65 @@ class Typing {
56
180
  onUpdate: options.onUpdate || null,
57
181
  onComplete: options.onComplete || null
58
182
  };
59
- this.textUnits = decomposeText(this.config.text);
60
- this.originalChars = [];
61
- this.charUnitMap = [];
62
- this.initializeTextStructure();
183
+ const decomposed = decomposeText(this.config.text);
184
+ this.textUnits = decomposed.units;
185
+ this.charUnitRanges = decomposed.charUnitRanges;
63
186
  this.currentIndex = 0;
64
187
  this.displayedText = "";
65
188
  this.timeoutId = null;
66
- this.intersectionObserver = null;
189
+ this.visibilityManager = null;
67
190
  this.isRunning = false;
68
191
  this.hasTriggered = false;
69
192
  this.init();
70
193
  }
71
194
  init() {
72
195
  this.updateDisplay("");
73
- this.setupIntersectionObserver();
196
+ this.setupVisibilityManager();
74
197
  }
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
- }
198
+ setupVisibilityManager() {
199
+ this.visibilityManager = new VisibilityManager(this.container, {
200
+ threshold: this.config.threshold,
201
+ rootMargin: this.config.rootMargin,
202
+ onVisible: () => {
203
+ if (!this.hasTriggered && this.config.enabled) {
204
+ this.hasTriggered = true;
205
+ setTimeout(() => this.start(), this.config.delay);
96
206
  }
97
207
  },
98
- {
99
- threshold: this.config.threshold,
100
- rootMargin: this.config.rootMargin
208
+ onHidden: () => {
101
209
  }
102
- );
103
- this.intersectionObserver.observe(this.container);
210
+ });
104
211
  }
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);
212
+ // 단위들을 다시 합쳐서 실제 표시할 텍스트 생성
213
+ // 한글의 경우 자음/모음이 하나씩 보이도록 합성
214
+ buildTextFromUnits(unitCount) {
215
+ if (unitCount === 0) return "";
216
+ let result = "";
217
+ for (let charIndex = 0; charIndex < this.charUnitRanges.length; charIndex++) {
218
+ const range = this.charUnitRanges[charIndex];
219
+ if (range.start >= unitCount) {
220
+ break;
118
221
  }
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;
222
+ const unitsEntered = Math.min(unitCount - range.start, range.end - range.start);
223
+ if (unitsEntered <= 0) {
224
+ break;
225
+ }
226
+ if (range.isHangul) {
227
+ const charUnits = this.textUnits.slice(range.start, range.start + unitsEntered);
228
+ if (charUnits.length === 1) {
229
+ result += charUnits[0];
230
+ } else if (charUnits.length === 2) {
231
+ result += composeHangul(charUnits[0], charUnits[1]);
232
+ } else if (charUnits.length >= 3) {
233
+ result += composeHangul(charUnits[0], charUnits[1], charUnits[2]);
234
+ }
133
235
  } else {
134
- const unitsEntered = unitIndex - (currentUnits - unitsForChar);
135
236
  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
- }
237
+ result += this.textUnits[range.start];
142
238
  }
143
- break;
144
239
  }
145
240
  }
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);
241
+ return result;
153
242
  }
154
243
  start() {
155
244
  if (this.isRunning) return;
@@ -169,8 +258,7 @@ class Typing {
169
258
  }
170
259
  return;
171
260
  }
172
- const unitsToShow = this.textUnits.slice(0, this.currentIndex + 1);
173
- this.displayedText = this.buildTextFromUnits(unitsToShow);
261
+ this.displayedText = this.buildTextFromUnits(this.currentIndex + 1);
174
262
  let displayText = this.displayedText;
175
263
  if (this.config.showCursor) {
176
264
  displayText += this.config.cursorChar;
@@ -205,8 +293,9 @@ class Typing {
205
293
  setText(newText) {
206
294
  this.originalText = newText;
207
295
  this.config.text = newText;
208
- this.textUnits = decomposeText(newText);
209
- this.initializeTextStructure();
296
+ const decomposed = decomposeText(newText);
297
+ this.textUnits = decomposed.units;
298
+ this.charUnitRanges = decomposed.charUnitRanges;
210
299
  this.reset();
211
300
  if (this.config.enabled) {
212
301
  setTimeout(() => this.start(), this.config.delay);
@@ -214,9 +303,9 @@ class Typing {
214
303
  }
215
304
  destroy() {
216
305
  this.stop();
217
- if (this.intersectionObserver) {
218
- this.intersectionObserver.disconnect();
219
- this.intersectionObserver = null;
306
+ if (this.visibilityManager) {
307
+ this.visibilityManager.destroy();
308
+ this.visibilityManager = null;
220
309
  }
221
310
  }
222
311
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "masoneffect",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
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",