umaki 0.10.0 โ†’ 0.12.0

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 (60) hide show
  1. package/README.md +165 -5
  2. package/dist/index.cjs.js +5 -1
  3. package/dist/index.es.js +7 -3
  4. package/dist/libs/config/_internal.cjs.js +5 -0
  5. package/dist/libs/config/_internal.d.ts +6 -0
  6. package/dist/libs/config/_internal.es.js +5 -0
  7. package/dist/libs/config/get-config.cjs.js +3 -5
  8. package/dist/libs/config/get-config.d.ts +0 -2
  9. package/dist/libs/config/get-config.es.js +1 -3
  10. package/dist/libs/config/index.cjs.js +0 -1
  11. package/dist/libs/config/index.es.js +1 -2
  12. package/dist/libs/config/set-config.cjs.js +3 -3
  13. package/dist/libs/config/set-config.es.js +1 -1
  14. package/dist/libs/convert/hex-to-rgb.cjs.js +22 -0
  15. package/dist/libs/convert/hex-to-rgb.d.ts +16 -0
  16. package/dist/libs/convert/hex-to-rgb.es.js +22 -0
  17. package/dist/libs/convert/hex-to-rgb.test.d.ts +1 -0
  18. package/dist/libs/convert/index.cjs.js +4 -0
  19. package/dist/libs/convert/index.d.ts +2 -0
  20. package/dist/libs/convert/index.es.js +5 -1
  21. package/dist/libs/convert/rgb-to-hex.cjs.js +9 -0
  22. package/dist/libs/convert/rgb-to-hex.d.ts +12 -0
  23. package/dist/libs/convert/rgb-to-hex.es.js +9 -0
  24. package/dist/libs/convert/rgb-to-hex.test.d.ts +1 -0
  25. package/dist/libs/eventControl/debounce.cjs.js +3 -0
  26. package/dist/libs/eventControl/debounce.d.ts +2 -1
  27. package/dist/libs/eventControl/debounce.es.js +3 -0
  28. package/dist/libs/eventControl/throttle.cjs.js +3 -0
  29. package/dist/libs/eventControl/throttle.d.ts +2 -1
  30. package/dist/libs/eventControl/throttle.es.js +3 -0
  31. package/dist/libs/get/get-aspect-ratio.cjs.js +3 -0
  32. package/dist/libs/get/get-aspect-ratio.d.ts +3 -2
  33. package/dist/libs/get/get-aspect-ratio.es.js +3 -0
  34. package/dist/libs/get/get-orientation.cjs.js +3 -0
  35. package/dist/libs/get/get-orientation.d.ts +1 -0
  36. package/dist/libs/get/get-orientation.es.js +3 -0
  37. package/dist/libs/get/get-scrollbar-width.cjs.js +1 -1
  38. package/dist/libs/get/get-scrollbar-width.d.ts +3 -0
  39. package/dist/libs/get/get-scrollbar-width.es.js +1 -1
  40. package/dist/libs/get/get-style-property-value-to-number.cjs.js +1 -1
  41. package/dist/libs/get/get-style-property-value-to-number.es.js +1 -1
  42. package/dist/libs/get/get-ua-data.cjs.js +4 -4
  43. package/dist/libs/get/get-ua-data.es.js +4 -4
  44. package/dist/libs/is/is-after-date-time.cjs.js +3 -0
  45. package/dist/libs/is/is-after-date-time.d.ts +1 -0
  46. package/dist/libs/is/is-after-date-time.es.js +3 -0
  47. package/dist/libs/is/is-in-viewport.cjs.js +1 -1
  48. package/dist/libs/is/is-in-viewport.es.js +1 -1
  49. package/dist/libs/is/is-ipad.cjs.js +3 -0
  50. package/dist/libs/is/is-ipad.d.ts +1 -0
  51. package/dist/libs/is/is-ipad.es.js +3 -0
  52. package/dist/libs/security/html-sanitize.cjs.js +2 -0
  53. package/dist/libs/security/html-sanitize.d.ts +9 -0
  54. package/dist/libs/security/html-sanitize.es.js +3 -1
  55. package/dist/libs/security/index.cjs.js +1 -0
  56. package/dist/libs/security/index.es.js +3 -2
  57. package/dist/libs/transform/wrap-text-with-spans.cjs.js +4 -2
  58. package/dist/libs/transform/wrap-text-with-spans.d.ts +7 -2
  59. package/dist/libs/transform/wrap-text-with-spans.es.js +4 -2
  60. package/package.json +1 -1
package/README.md CHANGED
@@ -78,15 +78,18 @@ console.log(breakpoint); // e.g. 768 (default) or custom value if set
78
78
 
79
79
  - [Callback](#callback)
80
80
  - [tap](#tap)
81
- - [tapAsync](#tapasync)
81
+ - [tapAsync](#tapasync-promise)
82
82
  - [Control](#control)
83
83
  - [bgScrollStop](#bgscrollstop)
84
+ - [copyToClipboard](#copytoclipboard-promise)
84
85
  - [pd](#pd)
85
- - [scrollToHash](#scrolltohash)
86
+ - [scrollToHash](#scrolltohash-promise)
86
87
  - [videoPlayControl](#videoplaycontrol)
87
88
  - [Convert](#convert)
88
89
  - [changeDateStringToSpecificFormat](#changedatestringtospecificformat)
90
+ - [hexToRgb](#hextorgb)
89
91
  - [jsonStringToJsonObject](#jsonstringtojsonobject)
92
+ - [rgbToHex](#rgbtohex)
90
93
  - [EventControl](#eventcontrol)
91
94
  - [debounce](#debounce)
92
95
  - [throttle](#throttle)
@@ -100,6 +103,8 @@ console.log(breakpoint); // e.g. 768 (default) or custom value if set
100
103
  - [getOrientation](#getorientation)
101
104
  - [getParentList](#getparentlist)
102
105
  - [getQueryParams](#getqueryparams)
106
+ - [getRandomInt](#getrandomint)
107
+ - [getRelativeTime](#getrelativetime)
103
108
  - [getRem](#getrem)
104
109
  - [getScrollbarWidth](#getscrollbarwidth)
105
110
  - [getSessionStorage](#getsessionstorage)
@@ -111,8 +116,10 @@ console.log(breakpoint); // e.g. 768 (default) or custom value if set
111
116
  - [isAfterDateTime](#isafterdatetime)
112
117
  - [isBetweenDateTime](#isbetweendatetime)
113
118
  - [isExistAllElements](#isexistallelements)
119
+ - [isInViewport](#isinviewport)
114
120
  - [isIpad](#isipad)
115
121
  - [isKeyExists](#iskeyexists)
122
+ - [isOnline](#isonline)
116
123
  - [isSafari](#issafari)
117
124
  - [isScrollable](#isscrollable)
118
125
  - [isTouchSupport](#istouchsupport)
@@ -135,8 +142,8 @@ console.log(breakpoint); // e.g. 768 (default) or custom value if set
135
142
  - [Transform](#transform)
136
143
  - [wrapTextWithSpans](#wraptextwithspans)
137
144
  - [Wait](#wait)
138
- - [sleep](#sleep)
139
- - [waitForAllMediaLoaded](#waitforallmedialoaded)
145
+ - [sleep](#sleep-promise)
146
+ - [waitForAllMediaLoaded](#waitforallmedialoaded-promise)
140
147
  - [Security](#security)
141
148
  - [sanitizeHtml](#sanitizehtml)
142
149
  - [Advanced Usage](#advanced-usage)
@@ -218,6 +225,30 @@ bgScrollStop(false); // scroll start
218
225
 
219
226
  [View file โ†’](src/libs/control/bg-scroll-stop.ts)
220
227
 
228
+ ### copyToClipboard (Promise)
229
+
230
+ A function that copies text to the clipboard using the modern Clipboard API.
231
+
232
+ ```ts
233
+ import { copyToClipboard } from "umaki";
234
+
235
+ // Basic usage
236
+ const success = await copyToClipboard("Hello, World!");
237
+ if (success) {
238
+ console.log("Copied to clipboard!");
239
+ } else {
240
+ console.log("Failed to copy");
241
+ }
242
+
243
+ // Use in click handler
244
+ button.addEventListener("click", async () => {
245
+ const copied = await copyToClipboard(textToCopy);
246
+ showToast(copied ? "Copied!" : "Copy failed");
247
+ });
248
+ ```
249
+
250
+ [View file โ†’](src/libs/control/copy-to-clipboard.ts)
251
+
221
252
  ### pd
222
253
 
223
254
  A function that prevents the default event behavior.
@@ -303,6 +334,21 @@ Note: This function focuses on timezone handling rather than locale-specific for
303
334
 
304
335
  [View file โ†’](src/libs/convert/change-date-string-to-specific-format.ts)
305
336
 
337
+ ### hexToRgb
338
+
339
+ A function that converts a hex color string to an RGB color object. Supports `#RGB` / `#RRGGBB` and the same forms without the leading `#`. Returns `undefined` for invalid input.
340
+
341
+ ```ts
342
+ import { hexToRgb } from "umaki";
343
+
344
+ hexToRgb("#ff0000"); // { r: 255, g: 0, b: 0 }
345
+ hexToRgb("#fff"); // { r: 255, g: 255, b: 255 }
346
+ hexToRgb("abc"); // { r: 170, g: 187, b: 204 }
347
+ hexToRgb("#invalid"); // undefined
348
+ ```
349
+
350
+ [View file โ†’](src/libs/convert/hex-to-rgb.ts)
351
+
306
352
  ### jsonStringToJsonObject
307
353
 
308
354
  A function that converts a JSON string to a JSON object.
@@ -317,6 +363,22 @@ console.log(jsonObject); // { name: 'John', age: 30 }
317
363
 
318
364
  [View file โ†’](src/libs/convert/json-string-to-json-object.ts)
319
365
 
366
+ ### rgbToHex
367
+
368
+ A function that converts RGB color components to a 6-digit hex color string with leading `#`. Each component is rounded to the nearest integer and clamped to `[0, 255]`. Non-finite values (`NaN`, `Infinity`, `-Infinity`) are treated as `0`.
369
+
370
+ ```ts
371
+ import { rgbToHex } from "umaki";
372
+
373
+ rgbToHex(255, 0, 0); // '#ff0000'
374
+ rgbToHex(170, 187, 204); // '#aabbcc'
375
+ rgbToHex(1, 2, 3); // '#010203'
376
+ rgbToHex(300, -10, 128.5); // '#ff0081' (clamped & rounded)
377
+ rgbToHex(NaN, NaN, NaN); // '#000000'
378
+ ```
379
+
380
+ [View file โ†’](src/libs/convert/rgb-to-hex.ts)
381
+
320
382
  ## EventControl
321
383
 
322
384
  ### debounce
@@ -497,6 +559,53 @@ const customParamWithOptions = getQueryParams("id", {
497
559
 
498
560
  [View file โ†’](src/libs/get/get-query-params.ts)
499
561
 
562
+ ### getRandomInt
563
+
564
+ A function that returns a random integer between min (inclusive) and max (inclusive).
565
+
566
+ ```ts
567
+ import { getRandomInt } from "umaki";
568
+
569
+ // Basic usage
570
+ const random = getRandomInt(1, 10);
571
+ console.log(random); // Random integer from 1 to 10
572
+
573
+ // Use for array index
574
+ const items = ["apple", "banana", "orange"];
575
+ const randomItem = items[getRandomInt(0, items.length - 1)];
576
+
577
+ // Generate random delay
578
+ const delay = getRandomInt(100, 500);
579
+ await sleep(delay / 1000);
580
+ ```
581
+
582
+ [View file โ†’](src/libs/get/get-random-int.ts)
583
+
584
+ ### getRelativeTime
585
+
586
+ A function that returns a human-readable relative time string (e.g., "3 minutes ago", "2 days ago") using the Intl.RelativeTimeFormat API.
587
+
588
+ ```ts
589
+ import { getRelativeTime } from "umaki";
590
+
591
+ // Basic usage (Japanese locale by default)
592
+ const pastDate = new Date(Date.now() - 5 * 60 * 1000);
593
+ console.log(getRelativeTime(pastDate)); // "5 ๅˆ†ๅ‰"
594
+
595
+ // English locale
596
+ console.log(getRelativeTime(pastDate, "en")); // "5 minutes ago"
597
+
598
+ // Future dates
599
+ const futureDate = new Date(Date.now() + 2 * 24 * 60 * 60 * 1000);
600
+ console.log(getRelativeTime(futureDate)); // "2 ๆ—ฅๅพŒ"
601
+
602
+ // With timestamp or ISO string
603
+ console.log(getRelativeTime(1702800000000, "en")); // relative to now
604
+ console.log(getRelativeTime("2024-01-15T12:00:00Z", "en"));
605
+ ```
606
+
607
+ [View file โ†’](src/libs/get/get-relative-time.ts)
608
+
500
609
  ### getRem
501
610
 
502
611
  A function that converts a pixel value to rem units.
@@ -650,6 +759,31 @@ console.log(result); // true or false
650
759
 
651
760
  [View file โ†’](src/libs/is/is-exist-all-elements.ts)
652
761
 
762
+ ### isInViewport
763
+
764
+ A function that checks if an element is currently visible within the viewport.
765
+
766
+ ```ts
767
+ import { isInViewport } from "umaki";
768
+
769
+ const element = document.getElementById("target");
770
+
771
+ // Check if any part of the element is visible
772
+ const isVisible = isInViewport(element);
773
+ console.log(isVisible); // true or false
774
+
775
+ // Check if the entire element is visible
776
+ const isFullyVisible = isInViewport(element, { threshold: 1 });
777
+
778
+ // Check if at least 50% of the element is visible
779
+ const isHalfVisible = isInViewport(element, { threshold: 0.5 });
780
+
781
+ // With expanded viewport bounds (trigger 100px before element enters viewport)
782
+ const isNearViewport = isInViewport(element, { rootMargin: "100px" });
783
+ ```
784
+
785
+ [View file โ†’](src/libs/is/is-in-viewport.ts)
786
+
653
787
  ### isIpad
654
788
 
655
789
  A function that checks if the device is an iPad.
@@ -677,6 +811,32 @@ console.log(result); // true or false
677
811
 
678
812
  [View file โ†’](src/libs/is/is-key-exists.ts)
679
813
 
814
+ ### isOnline
815
+
816
+ A function that checks if the browser is currently online using the Navigator.onLine API.
817
+
818
+ ```ts
819
+ import { isOnline } from "umaki";
820
+
821
+ // Basic usage
822
+ if (isOnline()) {
823
+ // Perform network request
824
+ fetchData();
825
+ } else {
826
+ // Show offline message
827
+ showOfflineMessage();
828
+ }
829
+
830
+ // Use with event listeners for online/offline detection
831
+ window.addEventListener("online", () => {
832
+ if (isOnline()) {
833
+ console.log("Back online!");
834
+ }
835
+ });
836
+ ```
837
+
838
+ [View file โ†’](src/libs/is/is-online.ts)
839
+
680
840
  ### isSafari
681
841
 
682
842
  A function that checks if the browser is Safari.
@@ -1161,7 +1321,7 @@ import { getUaData, sanitizeHtml } from "umaki";
1161
1321
  | `umaki/callback` | Callback utilities (tap, tapAsync) |
1162
1322
  | `umaki/config` | Configuration (setConfig, getConfig) |
1163
1323
  | `umaki/control` | Scroll control, video playback, etc. |
1164
- | `umaki/convert` | Data conversion (dates, JSON) |
1324
+ | `umaki/convert` | Data conversion (dates, JSON, colors) |
1165
1325
  | `umaki/eventControl` | debounce, throttle |
1166
1326
  | `umaki/get` | Value retrieval (DOM, UA, etc.) |
1167
1327
  | `umaki/is` | Boolean checks (device detection, etc.) |
package/dist/index.cjs.js CHANGED
@@ -11,7 +11,9 @@ const pd = require("./libs/control/pd.cjs.js");
11
11
  const scrollToHash = require("./libs/control/scroll-to-hash.cjs.js");
12
12
  const videoPlayControl = require("./libs/control/video-play-control.cjs.js");
13
13
  const changeDateStringToSpecificFormat = require("./libs/convert/change-date-string-to-specific-format.cjs.js");
14
+ const hexToRgb = require("./libs/convert/hex-to-rgb.cjs.js");
14
15
  const jsonStringToJsonObject = require("./libs/convert/json-string-to-json-object.cjs.js");
16
+ const rgbToHex = require("./libs/convert/rgb-to-hex.cjs.js");
15
17
  const debounce = require("./libs/eventControl/debounce.cjs.js");
16
18
  const throttle = require("./libs/eventControl/throttle.cjs.js");
17
19
  const getAspectRatio = require("./libs/get/get-aspect-ratio.cjs.js");
@@ -62,7 +64,6 @@ const waitForAllMediaLoaded = require("./libs/wait/wait-for-all-media-loaded.cjs
62
64
  exports.tap = tap.tap;
63
65
  exports.tapAsync = tapAsync.tapAsync;
64
66
  exports.defaultConfig = defaultConfig.defaultConfig;
65
- exports.currentConfig = getConfig.currentConfig;
66
67
  exports.getConfig = getConfig.getConfig;
67
68
  exports.getConfigValue = getConfig.getConfigValue;
68
69
  exports.setConfig = setConfig.setConfig;
@@ -72,7 +73,9 @@ exports.pd = pd.pd;
72
73
  exports.scrollToHash = scrollToHash.scrollToHash;
73
74
  exports.videoPlayControl = videoPlayControl.videoPlayControl;
74
75
  exports.changeDateStringToSpecificFormat = changeDateStringToSpecificFormat.changeDateStringToSpecificFormat;
76
+ exports.hexToRgb = hexToRgb.hexToRgb;
75
77
  exports.jsonStringToJsonObject = jsonStringToJsonObject.jsonStringToJsonObject;
78
+ exports.rgbToHex = rgbToHex.rgbToHex;
76
79
  exports.debounce = debounce.debounce;
77
80
  exports.throttle = throttle.throttle;
78
81
  exports.getAspectRatio = getAspectRatio.getAspectRatio;
@@ -109,6 +112,7 @@ exports.removeAttribute = removeAttribute.removeAttribute;
109
112
  exports.removeSessionStorage = removeSessionStorage.removeSessionStorage;
110
113
  exports.removeStylePropertyValue = removeStylePropertyValue.removeStylePropertyValue;
111
114
  exports.htmlSanitize = htmlSanitize.htmlSanitize;
115
+ exports.sanitizeHtml = htmlSanitize.sanitizeHtml;
112
116
  exports.set100vh = set100vh.set100vh;
113
117
  exports.set100vw = set100vw.set100vw;
114
118
  exports.setAttribute = setAttribute.setAttribute;
package/dist/index.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { tap } from "./libs/callback/tap.es.js";
2
2
  import { tapAsync } from "./libs/callback/tap-async.es.js";
3
3
  import { defaultConfig } from "./libs/config/default-config.es.js";
4
- import { currentConfig, getConfig, getConfigValue } from "./libs/config/get-config.es.js";
4
+ import { getConfig, getConfigValue } from "./libs/config/get-config.es.js";
5
5
  import { setConfig } from "./libs/config/set-config.es.js";
6
6
  import { bgScrollStop } from "./libs/control/bg-scroll-stop.es.js";
7
7
  import { copyToClipboard } from "./libs/control/copy-to-clipboard.es.js";
@@ -9,7 +9,9 @@ import { pd } from "./libs/control/pd.es.js";
9
9
  import { scrollToHash } from "./libs/control/scroll-to-hash.es.js";
10
10
  import { videoPlayControl } from "./libs/control/video-play-control.es.js";
11
11
  import { changeDateStringToSpecificFormat } from "./libs/convert/change-date-string-to-specific-format.es.js";
12
+ import { hexToRgb } from "./libs/convert/hex-to-rgb.es.js";
12
13
  import { jsonStringToJsonObject } from "./libs/convert/json-string-to-json-object.es.js";
14
+ import { rgbToHex } from "./libs/convert/rgb-to-hex.es.js";
13
15
  import { debounce } from "./libs/eventControl/debounce.es.js";
14
16
  import { throttle } from "./libs/eventControl/throttle.es.js";
15
17
  import { getAspectRatio } from "./libs/get/get-aspect-ratio.es.js";
@@ -45,7 +47,7 @@ import { removeAllHtmlTags } from "./libs/remove/remove-all-html-tags.es.js";
45
47
  import { removeAttribute } from "./libs/remove/remove-attribute.es.js";
46
48
  import { removeSessionStorage } from "./libs/remove/remove-session-storage.es.js";
47
49
  import { removeStylePropertyValue } from "./libs/remove/remove-style-property-value.es.js";
48
- import { htmlSanitize } from "./libs/security/html-sanitize.es.js";
50
+ import { htmlSanitize, sanitizeHtml } from "./libs/security/html-sanitize.es.js";
49
51
  import { set100vh } from "./libs/set/set-100vh.es.js";
50
52
  import { set100vw } from "./libs/set/set-100vw.es.js";
51
53
  import { setAttribute } from "./libs/set/set-attribute.es.js";
@@ -62,7 +64,6 @@ export {
62
64
  changeDateStringToSpecificFormat,
63
65
  checkDeviceSize,
64
66
  copyToClipboard,
65
- currentConfig,
66
67
  debounce,
67
68
  defaultConfig,
68
69
  getAspectRatio,
@@ -85,6 +86,7 @@ export {
85
86
  getStylePropertyValue,
86
87
  getStylePropertyValueToNumber,
87
88
  getUaData,
89
+ hexToRgb,
88
90
  htmlSanitize,
89
91
  isAfterDateTime,
90
92
  isBetweenDateTime,
@@ -102,6 +104,8 @@ export {
102
104
  removeAttribute,
103
105
  removeSessionStorage,
104
106
  removeStylePropertyValue,
107
+ rgbToHex,
108
+ sanitizeHtml,
105
109
  scrollToHash,
106
110
  set100vh,
107
111
  set100vw,
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const defaultConfig = require("./default-config.cjs.js");
4
+ const currentConfig = { ...defaultConfig.defaultConfig };
5
+ exports.currentConfig = currentConfig;
@@ -0,0 +1,6 @@
1
+ import { UmakiConfig } from './types';
2
+ /**
3
+ * Internal module for shared configuration state.
4
+ * This module should NOT be exported publicly.
5
+ */
6
+ export declare const currentConfig: UmakiConfig;
@@ -0,0 +1,5 @@
1
+ import { defaultConfig } from "./default-config.es.js";
2
+ const currentConfig = { ...defaultConfig };
3
+ export {
4
+ currentConfig
5
+ };
@@ -1,13 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const defaultConfig = require("./default-config.cjs.js");
4
- const currentConfig = { ...defaultConfig.defaultConfig };
3
+ const _internal = require("./_internal.cjs.js");
5
4
  const getConfig = () => {
6
- return { ...currentConfig };
5
+ return { ..._internal.currentConfig };
7
6
  };
8
7
  const getConfigValue = (key) => {
9
- return currentConfig[key];
8
+ return _internal.currentConfig[key];
10
9
  };
11
- exports.currentConfig = currentConfig;
12
10
  exports.getConfig = getConfig;
13
11
  exports.getConfigValue = getConfigValue;
@@ -1,5 +1,4 @@
1
1
  import { UmakiConfig } from './types';
2
- declare const currentConfig: UmakiConfig;
3
2
  /**
4
3
  * Get the current configuration
5
4
  * @returns The current configuration object
@@ -11,4 +10,3 @@ export declare const getConfig: () => UmakiConfig;
11
10
  * @returns The value for the specified key, or undefined if the key doesn't exist
12
11
  */
13
12
  export declare const getConfigValue: <K extends keyof UmakiConfig>(key: K) => UmakiConfig[K];
14
- export { currentConfig };
@@ -1,5 +1,4 @@
1
- import { defaultConfig } from "./default-config.es.js";
2
- const currentConfig = { ...defaultConfig };
1
+ import { currentConfig } from "./_internal.es.js";
3
2
  const getConfig = () => {
4
3
  return { ...currentConfig };
5
4
  };
@@ -7,7 +6,6 @@ const getConfigValue = (key) => {
7
6
  return currentConfig[key];
8
7
  };
9
8
  export {
10
- currentConfig,
11
9
  getConfig,
12
10
  getConfigValue
13
11
  };
@@ -4,7 +4,6 @@ const defaultConfig = require("./default-config.cjs.js");
4
4
  const getConfig = require("./get-config.cjs.js");
5
5
  const setConfig = require("./set-config.cjs.js");
6
6
  exports.defaultConfig = defaultConfig.defaultConfig;
7
- exports.currentConfig = getConfig.currentConfig;
8
7
  exports.getConfig = getConfig.getConfig;
9
8
  exports.getConfigValue = getConfig.getConfigValue;
10
9
  exports.setConfig = setConfig.setConfig;
@@ -1,8 +1,7 @@
1
1
  import { defaultConfig } from "./default-config.es.js";
2
- import { currentConfig, getConfig, getConfigValue } from "./get-config.es.js";
2
+ import { getConfig, getConfigValue } from "./get-config.es.js";
3
3
  import { setConfig } from "./set-config.es.js";
4
4
  export {
5
- currentConfig,
6
5
  defaultConfig,
7
6
  getConfig,
8
7
  getConfigValue,
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const getConfig = require("./get-config.cjs.js");
3
+ const _internal = require("./_internal.cjs.js");
4
4
  const setConfig = (config) => {
5
- Object.assign(getConfig.currentConfig, config);
6
- return { ...getConfig.currentConfig };
5
+ Object.assign(_internal.currentConfig, config);
6
+ return { ..._internal.currentConfig };
7
7
  };
8
8
  exports.setConfig = setConfig;
@@ -1,4 +1,4 @@
1
- import { currentConfig } from "./get-config.es.js";
1
+ import { currentConfig } from "./_internal.es.js";
2
2
  const setConfig = (config) => {
3
3
  Object.assign(currentConfig, config);
4
4
  return { ...currentConfig };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const HEX_PATTERN = /^[0-9a-fA-F]+$/;
4
+ const hexToRgb = (hex) => {
5
+ const trimmed = hex.trim();
6
+ const normalized = trimmed.startsWith("#") ? trimmed.slice(1) : trimmed;
7
+ if (!HEX_PATTERN.test(normalized)) return void 0;
8
+ let expanded;
9
+ if (normalized.length === 3) {
10
+ expanded = `${normalized[0]}${normalized[0]}${normalized[1]}${normalized[1]}${normalized[2]}${normalized[2]}`;
11
+ } else if (normalized.length === 6) {
12
+ expanded = normalized;
13
+ } else {
14
+ return void 0;
15
+ }
16
+ return {
17
+ r: Number.parseInt(expanded.slice(0, 2), 16),
18
+ g: Number.parseInt(expanded.slice(2, 4), 16),
19
+ b: Number.parseInt(expanded.slice(4, 6), 16)
20
+ };
21
+ };
22
+ exports.hexToRgb = hexToRgb;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * RGB color components in 0-255 range.
3
+ */
4
+ export interface RgbColor {
5
+ r: number;
6
+ g: number;
7
+ b: number;
8
+ }
9
+ /**
10
+ * Converts a hex color string to an RGB color object.
11
+ * Supports `#RGB`, `#RRGGBB` and the same forms without the leading `#`.
12
+ *
13
+ * @param hex - Hex color string (e.g. `#fff`, `#ff0000`, `ff0000`)
14
+ * @returns RGB color object, or `undefined` if the input is not a valid hex color string.
15
+ */
16
+ export declare const hexToRgb: (hex: string) => RgbColor | undefined;
@@ -0,0 +1,22 @@
1
+ const HEX_PATTERN = /^[0-9a-fA-F]+$/;
2
+ const hexToRgb = (hex) => {
3
+ const trimmed = hex.trim();
4
+ const normalized = trimmed.startsWith("#") ? trimmed.slice(1) : trimmed;
5
+ if (!HEX_PATTERN.test(normalized)) return void 0;
6
+ let expanded;
7
+ if (normalized.length === 3) {
8
+ expanded = `${normalized[0]}${normalized[0]}${normalized[1]}${normalized[1]}${normalized[2]}${normalized[2]}`;
9
+ } else if (normalized.length === 6) {
10
+ expanded = normalized;
11
+ } else {
12
+ return void 0;
13
+ }
14
+ return {
15
+ r: Number.parseInt(expanded.slice(0, 2), 16),
16
+ g: Number.parseInt(expanded.slice(2, 4), 16),
17
+ b: Number.parseInt(expanded.slice(4, 6), 16)
18
+ };
19
+ };
20
+ export {
21
+ hexToRgb
22
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const changeDateStringToSpecificFormat = require("./change-date-string-to-specific-format.cjs.js");
4
+ const hexToRgb = require("./hex-to-rgb.cjs.js");
4
5
  const jsonStringToJsonObject = require("./json-string-to-json-object.cjs.js");
6
+ const rgbToHex = require("./rgb-to-hex.cjs.js");
5
7
  exports.changeDateStringToSpecificFormat = changeDateStringToSpecificFormat.changeDateStringToSpecificFormat;
8
+ exports.hexToRgb = hexToRgb.hexToRgb;
6
9
  exports.jsonStringToJsonObject = jsonStringToJsonObject.jsonStringToJsonObject;
10
+ exports.rgbToHex = rgbToHex.rgbToHex;
@@ -2,4 +2,6 @@
2
2
  * Convert functions
3
3
  */
4
4
  export * from './change-date-string-to-specific-format';
5
+ export * from './hex-to-rgb';
5
6
  export * from './json-string-to-json-object';
7
+ export * from './rgb-to-hex';
@@ -1,6 +1,10 @@
1
1
  import { changeDateStringToSpecificFormat } from "./change-date-string-to-specific-format.es.js";
2
+ import { hexToRgb } from "./hex-to-rgb.es.js";
2
3
  import { jsonStringToJsonObject } from "./json-string-to-json-object.es.js";
4
+ import { rgbToHex } from "./rgb-to-hex.es.js";
3
5
  export {
4
6
  changeDateStringToSpecificFormat,
5
- jsonStringToJsonObject
7
+ hexToRgb,
8
+ jsonStringToJsonObject,
9
+ rgbToHex
6
10
  };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const sanitizeComponent = (value) => {
4
+ if (!Number.isFinite(value)) return 0;
5
+ return Math.max(0, Math.min(255, Math.round(value)));
6
+ };
7
+ const toHexPair = (value) => sanitizeComponent(value).toString(16).padStart(2, "0");
8
+ const rgbToHex = (r, g, b) => `#${toHexPair(r)}${toHexPair(g)}${toHexPair(b)}`;
9
+ exports.rgbToHex = rgbToHex;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Converts RGB color components to a 6-digit hex color string with leading `#`.
3
+ *
4
+ * Each component is rounded to the nearest integer and clamped to `[0, 255]`.
5
+ * Non-finite values (`NaN`, `Infinity`, `-Infinity`) are treated as `0`.
6
+ *
7
+ * @param r - Red component (0-255)
8
+ * @param g - Green component (0-255)
9
+ * @param b - Blue component (0-255)
10
+ * @returns Lowercase hex color string (e.g. `#ff0000`)
11
+ */
12
+ export declare const rgbToHex: (r: number, g: number, b: number) => string;
@@ -0,0 +1,9 @@
1
+ const sanitizeComponent = (value) => {
2
+ if (!Number.isFinite(value)) return 0;
3
+ return Math.max(0, Math.min(255, Math.round(value)));
4
+ };
5
+ const toHexPair = (value) => sanitizeComponent(value).toString(16).padStart(2, "0");
6
+ const rgbToHex = (r, g, b) => `#${toHexPair(r)}${toHexPair(g)}${toHexPair(b)}`;
7
+ export {
8
+ rgbToHex
9
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const debounce = (fn, delay) => {
4
+ if (delay < 0 || !Number.isFinite(delay)) {
5
+ throw new Error("delay must be a non-negative finite number");
6
+ }
4
7
  let timeoutId = null;
5
8
  return (...args) => {
6
9
  timeoutId && clearTimeout(timeoutId);
@@ -4,8 +4,9 @@ type DebounceProcedure = (...args: unknown[]) => void;
4
4
  *
5
5
  * @template F - The type of the function to debounce.
6
6
  * @param {F} fn - The function to debounce.
7
- * @param {number} delay - The number of milliseconds to delay.
7
+ * @param {number} delay - The number of milliseconds to delay. Must be a non-negative finite number.
8
8
  * @returns {(...args: Parameters<F>) => void} - A debounced version of the provided function.
9
+ * @throws {Error} If delay is negative or not finite.
9
10
  */
10
11
  export declare const debounce: <F extends DebounceProcedure>(fn: F, delay: number) => ((...args: Parameters<F>) => void);
11
12
  export {};
@@ -1,4 +1,7 @@
1
1
  const debounce = (fn, delay) => {
2
+ if (delay < 0 || !Number.isFinite(delay)) {
3
+ throw new Error("delay must be a non-negative finite number");
4
+ }
2
5
  let timeoutId = null;
3
6
  return (...args) => {
4
7
  timeoutId && clearTimeout(timeoutId);
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const throttle = (fn, wait) => {
4
+ if (wait < 0 || !Number.isFinite(wait)) {
5
+ throw new Error("wait must be a non-negative finite number");
6
+ }
4
7
  let lastCallTime = 0;
5
8
  return (...args) => {
6
9
  const currentTime = Date.now();
@@ -5,8 +5,9 @@ type ThrottleFunction = (...args: unknown[]) => void;
5
5
  *
6
6
  * @template F - The type of the function to be throttled.
7
7
  * @param fn - The function to throttle.
8
- * @param wait - The number of milliseconds to wait before allowing the next execution.
8
+ * @param wait - The number of milliseconds to wait before allowing the next execution. Must be a non-negative finite number.
9
9
  * @returns A throttled version of the provided function.
10
+ * @throws {Error} If wait is negative or not finite.
10
11
  */
11
12
  export declare const throttle: <F extends ThrottleFunction>(fn: F, wait: number) => ((...args: Parameters<F>) => void);
12
13
  export {};
@@ -1,4 +1,7 @@
1
1
  const throttle = (fn, wait) => {
2
+ if (wait < 0 || !Number.isFinite(wait)) {
3
+ throw new Error("wait must be a non-negative finite number");
4
+ }
2
5
  let lastCallTime = 0;
3
6
  return (...args) => {
4
7
  const currentTime = Date.now();
@@ -2,6 +2,9 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const getGcd = require("./get-gcd.cjs.js");
4
4
  const getAspectRatio = (w, h) => {
5
+ if (w <= 0 || h <= 0 || !Number.isFinite(w) || !Number.isFinite(h)) {
6
+ throw new Error("Width and height must be positive finite numbers");
7
+ }
5
8
  const gcd = getGcd.getGcd(w, h);
6
9
  return { w: w / gcd, h: h / gcd };
7
10
  };
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Returns the aspect ratio of the given width and height.
3
3
  *
4
- * @param w - The width value.
5
- * @param h - The height value.
4
+ * @param w - The width value. Must be a positive number.
5
+ * @param h - The height value. Must be a positive number.
6
6
  * @returns An object containing the width and height of the aspect ratio.
7
+ * @throws {Error} If width or height is not a positive number.
7
8
  */
8
9
  export declare const getAspectRatio: (w: number, h: number) => {
9
10
  w: number;
@@ -1,5 +1,8 @@
1
1
  import { getGcd } from "./get-gcd.es.js";
2
2
  const getAspectRatio = (w, h) => {
3
+ if (w <= 0 || h <= 0 || !Number.isFinite(w) || !Number.isFinite(h)) {
4
+ throw new Error("Width and height must be positive finite numbers");
5
+ }
3
6
  const gcd = getGcd(w, h);
4
7
  return { w: w / gcd, h: h / gcd };
5
8
  };
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const getOrientation = () => {
4
+ if (typeof window === "undefined") {
5
+ return "portrait";
6
+ }
4
7
  const isLandscape = window.matchMedia("(orientation: landscape)").matches;
5
8
  return isLandscape ? "landscape" : "portrait";
6
9
  };
@@ -2,5 +2,6 @@
2
2
  * Retrieves the current orientation of the device.
3
3
  *
4
4
  * @returns {'landscape' | 'portrait'} The current orientation, either 'landscape' or 'portrait'.
5
+ * Returns 'portrait' as default in SSR environments where window is undefined.
5
6
  */
6
7
  export declare const getOrientation: () => "landscape" | "portrait";
@@ -1,4 +1,7 @@
1
1
  const getOrientation = () => {
2
+ if (typeof window === "undefined") {
3
+ return "portrait";
4
+ }
2
5
  const isLandscape = window.matchMedia("(orientation: landscape)").matches;
3
6
  return isLandscape ? "landscape" : "portrait";
4
7
  };
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const getScrollbarWidth = () => window.innerWidth - document.body.clientWidth;
3
+ const getScrollbarWidth = () => window.innerWidth - document.documentElement.clientWidth;
4
4
  exports.getScrollbarWidth = getScrollbarWidth;
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Retrieves the width of the scrollbar.
3
3
  *
4
+ * Uses document.documentElement.clientWidth instead of document.body.clientWidth
5
+ * to ensure accurate measurement regardless of body element styling (e.g., max-width, margin).
6
+ *
4
7
  * @returns {number} The width of the scrollbar in pixels.
5
8
  */
6
9
  export declare const getScrollbarWidth: () => number;
@@ -1,4 +1,4 @@
1
- const getScrollbarWidth = () => window.innerWidth - document.body.clientWidth;
1
+ const getScrollbarWidth = () => window.innerWidth - document.documentElement.clientWidth;
2
2
  export {
3
3
  getScrollbarWidth
4
4
  };
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const getStylePropertyValue = require("./get-style-property-value.cjs.js");
4
- const getStylePropertyValueToNumber = (key) => Number.parseInt(getStylePropertyValue.getStylePropertyValue(key), 10) || 0;
4
+ const getStylePropertyValueToNumber = (key) => Number.parseFloat(getStylePropertyValue.getStylePropertyValue(key)) || 0;
5
5
  exports.getStylePropertyValueToNumber = getStylePropertyValueToNumber;
@@ -1,5 +1,5 @@
1
1
  import { getStylePropertyValue } from "./get-style-property-value.es.js";
2
- const getStylePropertyValueToNumber = (key) => Number.parseInt(getStylePropertyValue(key), 10) || 0;
2
+ const getStylePropertyValueToNumber = (key) => Number.parseFloat(getStylePropertyValue(key)) || 0;
3
3
  export {
4
4
  getStylePropertyValueToNumber
5
5
  };
@@ -11,11 +11,11 @@ const getUaData = () => {
11
11
  const osName = result.os.name;
12
12
  const type = result.device.type;
13
13
  const uaString = {
14
- browserName: browserName ? browserName.toLowerCase().replace(" ", "-") : "",
14
+ browserName: browserName ? browserName.toLowerCase().replace(/ /g, "-") : "",
15
15
  browserVersion: browserVersion ? browserVersion : "",
16
- browserEngine: browserEngine ? browserEngine.toLowerCase().replace(" ", "-") : "",
17
- osName: osName ? osName.toLowerCase().replace(" ", "-") : "",
18
- type: typeof type !== "undefined" ? type.toLowerCase().replace(" ", "-") : "laptop",
16
+ browserEngine: browserEngine ? browserEngine.toLowerCase().replace(/ /g, "-") : "",
17
+ osName: osName ? osName.toLowerCase().replace(/ /g, "-") : "",
18
+ type: typeof type !== "undefined" ? type.toLowerCase().replace(/ /g, "-") : "laptop",
19
19
  touchSupport: isTouchSupport.isTouchSupport()
20
20
  };
21
21
  return uaString;
@@ -9,11 +9,11 @@ const getUaData = () => {
9
9
  const osName = result.os.name;
10
10
  const type = result.device.type;
11
11
  const uaString = {
12
- browserName: browserName ? browserName.toLowerCase().replace(" ", "-") : "",
12
+ browserName: browserName ? browserName.toLowerCase().replace(/ /g, "-") : "",
13
13
  browserVersion: browserVersion ? browserVersion : "",
14
- browserEngine: browserEngine ? browserEngine.toLowerCase().replace(" ", "-") : "",
15
- osName: osName ? osName.toLowerCase().replace(" ", "-") : "",
16
- type: typeof type !== "undefined" ? type.toLowerCase().replace(" ", "-") : "laptop",
14
+ browserEngine: browserEngine ? browserEngine.toLowerCase().replace(/ /g, "-") : "",
15
+ osName: osName ? osName.toLowerCase().replace(/ /g, "-") : "",
16
+ type: typeof type !== "undefined" ? type.toLowerCase().replace(/ /g, "-") : "laptop",
17
17
  touchSupport: isTouchSupport()
18
18
  };
19
19
  return uaString;
@@ -2,6 +2,9 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const dayjs = require("dayjs");
4
4
  const isAfterDateTime = (dateA, now = dayjs()) => {
5
+ if (!dayjs(dateA).isValid()) {
6
+ throw new Error("dateA is not a valid date");
7
+ }
5
8
  return now.isAfter(dayjs(dateA), "millisecond");
6
9
  };
7
10
  exports.isAfterDateTime = isAfterDateTime;
@@ -6,5 +6,6 @@ import { default as dayjs } from 'dayjs';
6
6
  * @param dateA - A date/time string to compare, parsed with dayjs.
7
7
  * @param now - Optional reference time as a Dayjs object; defaults to current time.
8
8
  * @returns `true` if `now` is strictly after the parsed `dateA` at millisecond precision; otherwise `false`.
9
+ * @throws Will throw an error if dateA is not a valid date.
9
10
  */
10
11
  export declare const isAfterDateTime: (dateA: string, now?: dayjs.Dayjs) => boolean;
@@ -1,5 +1,8 @@
1
1
  import dayjs from "dayjs";
2
2
  const isAfterDateTime = (dateA, now = dayjs()) => {
3
+ if (!dayjs(dateA).isValid()) {
4
+ throw new Error("dateA is not a valid date");
5
+ }
3
6
  return now.isAfter(dayjs(dateA), "millisecond");
4
7
  };
5
8
  export {
@@ -5,7 +5,7 @@ const parseRootMargin = (rootMargin) => {
5
5
  const parseValue = (value) => {
6
6
  if (value.endsWith("%")) {
7
7
  const percent = Number.parseFloat(value) / 100;
8
- return window.innerHeight * percent;
8
+ return window.innerWidth * percent;
9
9
  }
10
10
  return Number.parseFloat(value) || 0;
11
11
  };
@@ -3,7 +3,7 @@ const parseRootMargin = (rootMargin) => {
3
3
  const parseValue = (value) => {
4
4
  if (value.endsWith("%")) {
5
5
  const percent = Number.parseFloat(value) / 100;
6
- return window.innerHeight * percent;
6
+ return window.innerWidth * percent;
7
7
  }
8
8
  return Number.parseFloat(value) || 0;
9
9
  };
@@ -3,6 +3,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const getOrientation = require("../get/get-orientation.cjs.js");
4
4
  const getUaData = require("../get/get-ua-data.cjs.js");
5
5
  const isIpad = (orientation = "portrait") => {
6
+ if (typeof window === "undefined" || typeof navigator === "undefined") {
7
+ return false;
8
+ }
6
9
  const clientData = getUaData.getUaData();
7
10
  if (!clientData.touchSupport) return false;
8
11
  return clientData.type === "laptop" && clientData.osName === "mac-os" && clientData.browserName === "safari" && getOrientation.getOrientation() === orientation;
@@ -4,6 +4,7 @@ type Orientation = 'portrait' | 'landscape';
4
4
  *
5
5
  * @param orientation - The desired screen orientation ('portrait' or 'landscape'). Defaults to 'portrait'.
6
6
  * @returns `true` if the device is an iPad with the specified orientation, otherwise `false`.
7
+ * Returns `false` in SSR environments where window/navigator is undefined.
7
8
  */
8
9
  export declare const isIpad: (orientation?: Orientation) => boolean;
9
10
  export {};
@@ -1,6 +1,9 @@
1
1
  import { getOrientation } from "../get/get-orientation.es.js";
2
2
  import { getUaData } from "../get/get-ua-data.es.js";
3
3
  const isIpad = (orientation = "portrait") => {
4
+ if (typeof window === "undefined" || typeof navigator === "undefined") {
5
+ return false;
6
+ }
4
7
  const clientData = getUaData();
5
8
  if (!clientData.touchSupport) return false;
6
9
  return clientData.type === "laptop" && clientData.osName === "mac-os" && clientData.browserName === "safari" && getOrientation() === orientation;
@@ -4,4 +4,6 @@ const DOMPurify = require("isomorphic-dompurify");
4
4
  const htmlSanitize = (html, config = {}) => {
5
5
  return DOMPurify.sanitize(html, config);
6
6
  };
7
+ const sanitizeHtml = htmlSanitize;
7
8
  exports.htmlSanitize = htmlSanitize;
9
+ exports.sanitizeHtml = sanitizeHtml;
@@ -7,3 +7,12 @@ import { default as DOMPurify } from 'isomorphic-dompurify';
7
7
  * @returns The sanitized HTML string.
8
8
  */
9
9
  export declare const htmlSanitize: (html: string, config?: Parameters<typeof DOMPurify.sanitize>[1]) => string;
10
+ /**
11
+ * Alias for htmlSanitize.
12
+ * Sanitizes the given HTML string to prevent XSS attacks.
13
+ *
14
+ * @param html - The HTML string to sanitize.
15
+ * @param config - Optional configuration for DOMPurify.
16
+ * @returns The sanitized HTML string.
17
+ */
18
+ export declare const sanitizeHtml: (html: string, config?: Parameters<typeof DOMPurify.sanitize>[1]) => string;
@@ -2,6 +2,8 @@ import DOMPurify from "isomorphic-dompurify";
2
2
  const htmlSanitize = (html, config = {}) => {
3
3
  return DOMPurify.sanitize(html, config);
4
4
  };
5
+ const sanitizeHtml = htmlSanitize;
5
6
  export {
6
- htmlSanitize
7
+ htmlSanitize,
8
+ sanitizeHtml
7
9
  };
@@ -2,3 +2,4 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const htmlSanitize = require("./html-sanitize.cjs.js");
4
4
  exports.htmlSanitize = htmlSanitize.htmlSanitize;
5
+ exports.sanitizeHtml = htmlSanitize.sanitizeHtml;
@@ -1,4 +1,5 @@
1
- import { htmlSanitize } from "./html-sanitize.es.js";
1
+ import { htmlSanitize, sanitizeHtml } from "./html-sanitize.es.js";
2
2
  export {
3
- htmlSanitize
3
+ htmlSanitize,
4
+ sanitizeHtml
4
5
  };
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const runes2 = require("runes2");
3
4
  const wrapTextWithSpans = (element) => {
4
5
  if (!element) return;
5
6
  if (element.nodeType === Node.TEXT_NODE) {
6
7
  const textContent = (element.textContent || "").trim();
7
8
  const fragment = document.createDocumentFragment();
8
- for (const char of textContent) {
9
+ const graphemes = runes2.runes(textContent);
10
+ for (const grapheme of graphemes) {
9
11
  const span = document.createElement("span");
10
- span.textContent = char;
12
+ span.textContent = grapheme;
11
13
  fragment.appendChild(span);
12
14
  }
13
15
  element.replaceWith(fragment);
@@ -1,10 +1,15 @@
1
1
  /**
2
- * Wraps each character of the text content of an HTML element with individual <span> elements.
2
+ * Wraps each grapheme cluster (visual character) of the text content of an HTML element with individual <span> elements.
3
3
  *
4
4
  * @param element - The HTML element whose text content will be wrapped with <span> elements.
5
5
  *
6
6
  * This function recursively processes the given element and its child nodes. If the node is a text node,
7
- * it replaces the text content with a series of <span> elements, each containing a single character from the text.
7
+ * it replaces the text content with a series of <span> elements, each containing a single grapheme cluster from the text.
8
8
  * If the node is an element node, it recursively processes its child nodes.
9
+ *
10
+ * This function correctly handles:
11
+ * - Composite emojis (e.g., ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ, ๐Ÿ‘๐Ÿป)
12
+ * - Flag emojis (e.g., ๐Ÿ‡ฏ๐Ÿ‡ต)
13
+ * - Combined characters
9
14
  */
10
15
  export declare const wrapTextWithSpans: (element: HTMLElement) => void;
@@ -1,11 +1,13 @@
1
+ import { runes } from "runes2";
1
2
  const wrapTextWithSpans = (element) => {
2
3
  if (!element) return;
3
4
  if (element.nodeType === Node.TEXT_NODE) {
4
5
  const textContent = (element.textContent || "").trim();
5
6
  const fragment = document.createDocumentFragment();
6
- for (const char of textContent) {
7
+ const graphemes = runes(textContent);
8
+ for (const grapheme of graphemes) {
7
9
  const span = document.createElement("span");
8
- span.textContent = char;
10
+ span.textContent = grapheme;
9
11
  fragment.appendChild(span);
10
12
  }
11
13
  element.replaceWith(fragment);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umaki",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "A utility that is often used in web production.",
5
5
  "author": "TsubasaHiga",
6
6
  "homepage": "https://github.com/TsubasaHiga/umaki",