umaki 0.10.1 โ†’ 0.13.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 (65) hide show
  1. package/README.md +77 -1
  2. package/dist/index.cjs.js +9 -3
  3. package/dist/index.es.js +10 -4
  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-rendered-line-height.cjs.js +57 -0
  38. package/dist/libs/get/get-rendered-line-height.d.ts +37 -0
  39. package/dist/libs/get/get-rendered-line-height.es.js +57 -0
  40. package/dist/libs/get/get-rendered-line-height.test.d.ts +1 -0
  41. package/dist/libs/get/get-scrollbar-width.cjs.js +1 -1
  42. package/dist/libs/get/get-scrollbar-width.d.ts +3 -0
  43. package/dist/libs/get/get-scrollbar-width.es.js +1 -1
  44. package/dist/libs/get/get-ua-data.cjs.js +4 -4
  45. package/dist/libs/get/get-ua-data.es.js +4 -4
  46. package/dist/libs/get/index.cjs.js +4 -2
  47. package/dist/libs/get/index.d.ts +2 -1
  48. package/dist/libs/get/index.es.js +3 -1
  49. package/dist/libs/is/is-after-date-time.cjs.js +3 -0
  50. package/dist/libs/is/is-after-date-time.d.ts +1 -0
  51. package/dist/libs/is/is-after-date-time.es.js +3 -0
  52. package/dist/libs/is/is-in-viewport.cjs.js +1 -1
  53. package/dist/libs/is/is-in-viewport.es.js +1 -1
  54. package/dist/libs/is/is-ipad.cjs.js +3 -0
  55. package/dist/libs/is/is-ipad.d.ts +1 -0
  56. package/dist/libs/is/is-ipad.es.js +3 -0
  57. package/dist/libs/security/html-sanitize.cjs.js +2 -0
  58. package/dist/libs/security/html-sanitize.d.ts +9 -0
  59. package/dist/libs/security/html-sanitize.es.js +3 -1
  60. package/dist/libs/security/index.cjs.js +1 -0
  61. package/dist/libs/security/index.es.js +3 -2
  62. package/dist/libs/transform/wrap-text-with-spans.cjs.js +4 -2
  63. package/dist/libs/transform/wrap-text-with-spans.d.ts +7 -2
  64. package/dist/libs/transform/wrap-text-with-spans.es.js +4 -2
  65. package/package.json +1 -1
package/README.md CHANGED
@@ -87,7 +87,9 @@ console.log(breakpoint); // e.g. 768 (default) or custom value if set
87
87
  - [videoPlayControl](#videoplaycontrol)
88
88
  - [Convert](#convert)
89
89
  - [changeDateStringToSpecificFormat](#changedatestringtospecificformat)
90
+ - [hexToRgb](#hextorgb)
90
91
  - [jsonStringToJsonObject](#jsonstringtojsonobject)
92
+ - [rgbToHex](#rgbtohex)
91
93
  - [EventControl](#eventcontrol)
92
94
  - [debounce](#debounce)
93
95
  - [throttle](#throttle)
@@ -104,6 +106,7 @@ console.log(breakpoint); // e.g. 768 (default) or custom value if set
104
106
  - [getRandomInt](#getrandomint)
105
107
  - [getRelativeTime](#getrelativetime)
106
108
  - [getRem](#getrem)
109
+ - [getRenderedLineHeight](#getrenderedlineheight)
107
110
  - [getScrollbarWidth](#getscrollbarwidth)
108
111
  - [getSessionStorage](#getsessionstorage)
109
112
  - [getStringLength](#getstringlength)
@@ -332,6 +335,21 @@ Note: This function focuses on timezone handling rather than locale-specific for
332
335
 
333
336
  [View file โ†’](src/libs/convert/change-date-string-to-specific-format.ts)
334
337
 
338
+ ### hexToRgb
339
+
340
+ 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.
341
+
342
+ ```ts
343
+ import { hexToRgb } from "umaki";
344
+
345
+ hexToRgb("#ff0000"); // { r: 255, g: 0, b: 0 }
346
+ hexToRgb("#fff"); // { r: 255, g: 255, b: 255 }
347
+ hexToRgb("abc"); // { r: 170, g: 187, b: 204 }
348
+ hexToRgb("#invalid"); // undefined
349
+ ```
350
+
351
+ [View file โ†’](src/libs/convert/hex-to-rgb.ts)
352
+
335
353
  ### jsonStringToJsonObject
336
354
 
337
355
  A function that converts a JSON string to a JSON object.
@@ -346,6 +364,22 @@ console.log(jsonObject); // { name: 'John', age: 30 }
346
364
 
347
365
  [View file โ†’](src/libs/convert/json-string-to-json-object.ts)
348
366
 
367
+ ### rgbToHex
368
+
369
+ 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`.
370
+
371
+ ```ts
372
+ import { rgbToHex } from "umaki";
373
+
374
+ rgbToHex(255, 0, 0); // '#ff0000'
375
+ rgbToHex(170, 187, 204); // '#aabbcc'
376
+ rgbToHex(1, 2, 3); // '#010203'
377
+ rgbToHex(300, -10, 128.5); // '#ff0081' (clamped & rounded)
378
+ rgbToHex(NaN, NaN, NaN); // '#000000'
379
+ ```
380
+
381
+ [View file โ†’](src/libs/convert/rgb-to-hex.ts)
382
+
349
383
  ## EventControl
350
384
 
351
385
  ### debounce
@@ -586,6 +620,48 @@ console.log(remValue); // '1rem'
586
620
 
587
621
  [View file โ†’](src/libs/get/get-rem.ts)
588
622
 
623
+ ### getRenderedLineHeight
624
+
625
+ Measures the line-height **as it is actually rendered** (in CSS pixels) for a target element by inserting a hidden probe element with the same font-related styles and dividing its multi-line height by the sample line count.
626
+
627
+ This works around an iOS Safari quirk ([WebKit Bug #225695](https://bugs.webkit.org/show_bug.cgi?id=225695)) where fractional `line-height` values are floored to integer pixels at paint time. Stacking-line UIs that rely on `1lh` (e.g. `mask-image: repeating-linear-gradient` rules) drift on iOS Safari but match `getRenderedLineHeight` output. Returns `NaN` in SSR environments or when the probe cannot be measured.
628
+
629
+ The caller is responsible for awaiting `document.fonts.ready` before measuring when font-loaded accuracy matters.
630
+
631
+ ```ts
632
+ import { getRenderedLineHeight } from "umaki";
633
+
634
+ const textEl = document.querySelector<HTMLElement>(".text");
635
+ if (!textEl) return;
636
+
637
+ await document.fonts.ready;
638
+
639
+ const lh = getRenderedLineHeight(textEl);
640
+ if (Number.isFinite(lh)) {
641
+ textEl.style.setProperty("--text-line-height", `${lh}px`);
642
+ }
643
+ ```
644
+
645
+ ```css
646
+ .text {
647
+ mask-image: repeating-linear-gradient(
648
+ to bottom,
649
+ transparent 0,
650
+ transparent calc(var(--text-line-height, 1lh) - 0.5px),
651
+ #000 calc(var(--text-line-height, 1lh) - 0.5px),
652
+ #000 var(--text-line-height, 1lh)
653
+ );
654
+ }
655
+ ```
656
+
657
+ You can adjust the sampling resolution via `sampleLines` (default `20`, minimum `2`):
658
+
659
+ ```ts
660
+ const lh = getRenderedLineHeight(textEl, { sampleLines: 40 });
661
+ ```
662
+
663
+ [View file โ†’](src/libs/get/get-rendered-line-height.ts)
664
+
589
665
  ### getScrollbarWidth
590
666
 
591
667
  A function that retrieves the width of the scrollbar.
@@ -1288,7 +1364,7 @@ import { getUaData, sanitizeHtml } from "umaki";
1288
1364
  | `umaki/callback` | Callback utilities (tap, tapAsync) |
1289
1365
  | `umaki/config` | Configuration (setConfig, getConfig) |
1290
1366
  | `umaki/control` | Scroll control, video playback, etc. |
1291
- | `umaki/convert` | Data conversion (dates, JSON) |
1367
+ | `umaki/convert` | Data conversion (dates, JSON, colors) |
1292
1368
  | `umaki/eventControl` | debounce, throttle |
1293
1369
  | `umaki/get` | Value retrieval (DOM, UA, etc.) |
1294
1370
  | `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");
@@ -23,9 +25,10 @@ const getGravatarUrl = require("./libs/get/get-gravatar-url.cjs.js");
23
25
  const getOrientation = require("./libs/get/get-orientation.cjs.js");
24
26
  const getParentList = require("./libs/get/get-parent-list.cjs.js");
25
27
  const getQueryParams = require("./libs/get/get-query-params.cjs.js");
26
- const getRelativeTime = require("./libs/get/get-relative-time.cjs.js");
27
28
  const getRandomInt = require("./libs/get/get-random-int.cjs.js");
29
+ const getRelativeTime = require("./libs/get/get-relative-time.cjs.js");
28
30
  const getRem = require("./libs/get/get-rem.cjs.js");
31
+ const getRenderedLineHeight = require("./libs/get/get-rendered-line-height.cjs.js");
29
32
  const getScrollbarWidth = require("./libs/get/get-scrollbar-width.cjs.js");
30
33
  const getSessionStorage = require("./libs/get/get-session-storage.cjs.js");
31
34
  const getStringLength = require("./libs/get/get-string-length.cjs.js");
@@ -62,7 +65,6 @@ const waitForAllMediaLoaded = require("./libs/wait/wait-for-all-media-loaded.cjs
62
65
  exports.tap = tap.tap;
63
66
  exports.tapAsync = tapAsync.tapAsync;
64
67
  exports.defaultConfig = defaultConfig.defaultConfig;
65
- exports.currentConfig = getConfig.currentConfig;
66
68
  exports.getConfig = getConfig.getConfig;
67
69
  exports.getConfigValue = getConfig.getConfigValue;
68
70
  exports.setConfig = setConfig.setConfig;
@@ -72,7 +74,9 @@ exports.pd = pd.pd;
72
74
  exports.scrollToHash = scrollToHash.scrollToHash;
73
75
  exports.videoPlayControl = videoPlayControl.videoPlayControl;
74
76
  exports.changeDateStringToSpecificFormat = changeDateStringToSpecificFormat.changeDateStringToSpecificFormat;
77
+ exports.hexToRgb = hexToRgb.hexToRgb;
75
78
  exports.jsonStringToJsonObject = jsonStringToJsonObject.jsonStringToJsonObject;
79
+ exports.rgbToHex = rgbToHex.rgbToHex;
76
80
  exports.debounce = debounce.debounce;
77
81
  exports.throttle = throttle.throttle;
78
82
  exports.getAspectRatio = getAspectRatio.getAspectRatio;
@@ -84,9 +88,10 @@ exports.getGravatarUrl = getGravatarUrl.getGravatarUrl;
84
88
  exports.getOrientation = getOrientation.getOrientation;
85
89
  exports.getParentList = getParentList.getParentList;
86
90
  exports.getQueryParams = getQueryParams.getQueryParams;
87
- exports.getRelativeTime = getRelativeTime.getRelativeTime;
88
91
  exports.getRandomInt = getRandomInt.getRandomInt;
92
+ exports.getRelativeTime = getRelativeTime.getRelativeTime;
89
93
  exports.getRem = getRem.getRem;
94
+ exports.getRenderedLineHeight = getRenderedLineHeight.getRenderedLineHeight;
90
95
  exports.getScrollbarWidth = getScrollbarWidth.getScrollbarWidth;
91
96
  exports.getSessionStorage = getSessionStorage.getSessionStorage;
92
97
  exports.getStringLength = getStringLength.getStringLength;
@@ -109,6 +114,7 @@ exports.removeAttribute = removeAttribute.removeAttribute;
109
114
  exports.removeSessionStorage = removeSessionStorage.removeSessionStorage;
110
115
  exports.removeStylePropertyValue = removeStylePropertyValue.removeStylePropertyValue;
111
116
  exports.htmlSanitize = htmlSanitize.htmlSanitize;
117
+ exports.sanitizeHtml = htmlSanitize.sanitizeHtml;
112
118
  exports.set100vh = set100vh.set100vh;
113
119
  exports.set100vw = set100vw.set100vw;
114
120
  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";
@@ -21,9 +23,10 @@ import { getGravatarUrl } from "./libs/get/get-gravatar-url.es.js";
21
23
  import { getOrientation } from "./libs/get/get-orientation.es.js";
22
24
  import { getParentList } from "./libs/get/get-parent-list.es.js";
23
25
  import { getQueryParams } from "./libs/get/get-query-params.es.js";
24
- import { getRelativeTime } from "./libs/get/get-relative-time.es.js";
25
26
  import { getRandomInt } from "./libs/get/get-random-int.es.js";
27
+ import { getRelativeTime } from "./libs/get/get-relative-time.es.js";
26
28
  import { getRem } from "./libs/get/get-rem.es.js";
29
+ import { getRenderedLineHeight } from "./libs/get/get-rendered-line-height.es.js";
27
30
  import { getScrollbarWidth } from "./libs/get/get-scrollbar-width.es.js";
28
31
  import { getSessionStorage } from "./libs/get/get-session-storage.es.js";
29
32
  import { getStringLength } from "./libs/get/get-string-length.es.js";
@@ -45,7 +48,7 @@ import { removeAllHtmlTags } from "./libs/remove/remove-all-html-tags.es.js";
45
48
  import { removeAttribute } from "./libs/remove/remove-attribute.es.js";
46
49
  import { removeSessionStorage } from "./libs/remove/remove-session-storage.es.js";
47
50
  import { removeStylePropertyValue } from "./libs/remove/remove-style-property-value.es.js";
48
- import { htmlSanitize } from "./libs/security/html-sanitize.es.js";
51
+ import { htmlSanitize, sanitizeHtml } from "./libs/security/html-sanitize.es.js";
49
52
  import { set100vh } from "./libs/set/set-100vh.es.js";
50
53
  import { set100vw } from "./libs/set/set-100vw.es.js";
51
54
  import { setAttribute } from "./libs/set/set-attribute.es.js";
@@ -62,7 +65,6 @@ export {
62
65
  changeDateStringToSpecificFormat,
63
66
  checkDeviceSize,
64
67
  copyToClipboard,
65
- currentConfig,
66
68
  debounce,
67
69
  defaultConfig,
68
70
  getAspectRatio,
@@ -79,12 +81,14 @@ export {
79
81
  getRandomInt,
80
82
  getRelativeTime,
81
83
  getRem,
84
+ getRenderedLineHeight,
82
85
  getScrollbarWidth,
83
86
  getSessionStorage,
84
87
  getStringLength,
85
88
  getStylePropertyValue,
86
89
  getStylePropertyValueToNumber,
87
90
  getUaData,
91
+ hexToRgb,
88
92
  htmlSanitize,
89
93
  isAfterDateTime,
90
94
  isBetweenDateTime,
@@ -102,6 +106,8 @@ export {
102
106
  removeAttribute,
103
107
  removeSessionStorage,
104
108
  removeStylePropertyValue,
109
+ rgbToHex,
110
+ sanitizeHtml,
105
111
  scrollToHash,
106
112
  set100vh,
107
113
  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
  };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const DEFAULT_SAMPLE_LINES = 20;
4
+ const MIN_SAMPLE_LINES = 2;
5
+ const MAX_SAMPLE_LINES = 100;
6
+ const normalizeSampleLines = (value) => {
7
+ const raw = value ?? DEFAULT_SAMPLE_LINES;
8
+ if (!Number.isFinite(raw)) return DEFAULT_SAMPLE_LINES;
9
+ return Math.min(MAX_SAMPLE_LINES, Math.max(MIN_SAMPLE_LINES, Math.floor(raw)));
10
+ };
11
+ const getRenderedLineHeight = (element, options) => {
12
+ if (typeof window === "undefined") return Number.NaN;
13
+ const sampleLines = normalizeSampleLines(options?.sampleLines);
14
+ const ownerDocument = element.ownerDocument;
15
+ const host = ownerDocument?.body;
16
+ const view = ownerDocument?.defaultView;
17
+ if (!host || !view) return Number.NaN;
18
+ const cs = view.getComputedStyle(element);
19
+ const probe = ownerDocument.createElement("div");
20
+ const style = probe.style;
21
+ style.position = "absolute";
22
+ style.left = "-9999px";
23
+ style.top = "0";
24
+ style.visibility = "hidden";
25
+ style.pointerEvents = "none";
26
+ style.margin = "0";
27
+ style.padding = "0";
28
+ style.border = "0";
29
+ style.whiteSpace = "pre";
30
+ style.fontFamily = cs.fontFamily;
31
+ style.fontSize = cs.fontSize;
32
+ style.fontWeight = cs.fontWeight;
33
+ style.fontStyle = cs.fontStyle;
34
+ style.lineHeight = cs.lineHeight;
35
+ style.letterSpacing = cs.letterSpacing;
36
+ style.fontFeatureSettings = cs.fontFeatureSettings;
37
+ if (cs.fontVariationSettings) {
38
+ style.fontVariationSettings = cs.fontVariationSettings;
39
+ }
40
+ for (let i = 0; i < sampleLines; i++) {
41
+ if (i > 0) probe.appendChild(ownerDocument.createElement("br"));
42
+ probe.appendChild(ownerDocument.createTextNode("X"));
43
+ }
44
+ host.appendChild(probe);
45
+ try {
46
+ const probeHeight = probe.getBoundingClientRect().height;
47
+ if (probeHeight <= 0) return Number.NaN;
48
+ return probeHeight / sampleLines;
49
+ } catch {
50
+ return Number.NaN;
51
+ } finally {
52
+ if (probe.parentNode === host) {
53
+ host.removeChild(probe);
54
+ }
55
+ }
56
+ };
57
+ exports.getRenderedLineHeight = getRenderedLineHeight;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Options for {@link getRenderedLineHeight}.
3
+ */
4
+ export type GetRenderedLineHeightOptions = {
5
+ /**
6
+ * Number of lines used to measure the rendered line-height. Higher values
7
+ * yield a more precise per-line average. Clamped to the range [2, 100];
8
+ * non-finite values fall back to the default.
9
+ *
10
+ * @default 20
11
+ */
12
+ sampleLines?: number;
13
+ };
14
+ /**
15
+ * Measures the line-height as it is actually rendered (in CSS pixels) for the
16
+ * given element.
17
+ *
18
+ * On iOS Safari, fractional `line-height` values are floored to integer pixels
19
+ * at paint time, which makes `getComputedStyle(...).lineHeight` and the
20
+ * `1lh` unit drift from the visual baseline. This function inserts a hidden
21
+ * probe element with the same font/line-height related styles, measures the
22
+ * total height across multiple lines, and divides by the line count to obtain
23
+ * the actually rendered per-line height.
24
+ *
25
+ * Returns `NaN` in non-DOM environments (SSR), or when the probe cannot be
26
+ * measured (no body, no defaultView, zero/negative height, or measurement
27
+ * exception).
28
+ *
29
+ * The caller is responsible for waiting on `document.fonts.ready` before
30
+ * calling this function when accurate font-loaded measurements matter.
31
+ *
32
+ * @param element - The element whose rendered line-height should be measured.
33
+ * @param options - Measurement options.
34
+ * @returns The rendered line-height in CSS pixels, or `NaN` when measurement
35
+ * is not possible.
36
+ */
37
+ export declare const getRenderedLineHeight: (element: HTMLElement, options?: GetRenderedLineHeightOptions) => number;
@@ -0,0 +1,57 @@
1
+ const DEFAULT_SAMPLE_LINES = 20;
2
+ const MIN_SAMPLE_LINES = 2;
3
+ const MAX_SAMPLE_LINES = 100;
4
+ const normalizeSampleLines = (value) => {
5
+ const raw = value ?? DEFAULT_SAMPLE_LINES;
6
+ if (!Number.isFinite(raw)) return DEFAULT_SAMPLE_LINES;
7
+ return Math.min(MAX_SAMPLE_LINES, Math.max(MIN_SAMPLE_LINES, Math.floor(raw)));
8
+ };
9
+ const getRenderedLineHeight = (element, options) => {
10
+ if (typeof window === "undefined") return Number.NaN;
11
+ const sampleLines = normalizeSampleLines(options?.sampleLines);
12
+ const ownerDocument = element.ownerDocument;
13
+ const host = ownerDocument?.body;
14
+ const view = ownerDocument?.defaultView;
15
+ if (!host || !view) return Number.NaN;
16
+ const cs = view.getComputedStyle(element);
17
+ const probe = ownerDocument.createElement("div");
18
+ const style = probe.style;
19
+ style.position = "absolute";
20
+ style.left = "-9999px";
21
+ style.top = "0";
22
+ style.visibility = "hidden";
23
+ style.pointerEvents = "none";
24
+ style.margin = "0";
25
+ style.padding = "0";
26
+ style.border = "0";
27
+ style.whiteSpace = "pre";
28
+ style.fontFamily = cs.fontFamily;
29
+ style.fontSize = cs.fontSize;
30
+ style.fontWeight = cs.fontWeight;
31
+ style.fontStyle = cs.fontStyle;
32
+ style.lineHeight = cs.lineHeight;
33
+ style.letterSpacing = cs.letterSpacing;
34
+ style.fontFeatureSettings = cs.fontFeatureSettings;
35
+ if (cs.fontVariationSettings) {
36
+ style.fontVariationSettings = cs.fontVariationSettings;
37
+ }
38
+ for (let i = 0; i < sampleLines; i++) {
39
+ if (i > 0) probe.appendChild(ownerDocument.createElement("br"));
40
+ probe.appendChild(ownerDocument.createTextNode("X"));
41
+ }
42
+ host.appendChild(probe);
43
+ try {
44
+ const probeHeight = probe.getBoundingClientRect().height;
45
+ if (probeHeight <= 0) return Number.NaN;
46
+ return probeHeight / sampleLines;
47
+ } catch {
48
+ return Number.NaN;
49
+ } finally {
50
+ if (probe.parentNode === host) {
51
+ host.removeChild(probe);
52
+ }
53
+ }
54
+ };
55
+ export {
56
+ getRenderedLineHeight
57
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -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
  };
@@ -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;
@@ -9,9 +9,10 @@ const getGravatarUrl = require("./get-gravatar-url.cjs.js");
9
9
  const getOrientation = require("./get-orientation.cjs.js");
10
10
  const getParentList = require("./get-parent-list.cjs.js");
11
11
  const getQueryParams = require("./get-query-params.cjs.js");
12
- const getRelativeTime = require("./get-relative-time.cjs.js");
13
12
  const getRandomInt = require("./get-random-int.cjs.js");
13
+ const getRelativeTime = require("./get-relative-time.cjs.js");
14
14
  const getRem = require("./get-rem.cjs.js");
15
+ const getRenderedLineHeight = require("./get-rendered-line-height.cjs.js");
15
16
  const getScrollbarWidth = require("./get-scrollbar-width.cjs.js");
16
17
  const getSessionStorage = require("./get-session-storage.cjs.js");
17
18
  const getStringLength = require("./get-string-length.cjs.js");
@@ -27,9 +28,10 @@ exports.getGravatarUrl = getGravatarUrl.getGravatarUrl;
27
28
  exports.getOrientation = getOrientation.getOrientation;
28
29
  exports.getParentList = getParentList.getParentList;
29
30
  exports.getQueryParams = getQueryParams.getQueryParams;
30
- exports.getRelativeTime = getRelativeTime.getRelativeTime;
31
31
  exports.getRandomInt = getRandomInt.getRandomInt;
32
+ exports.getRelativeTime = getRelativeTime.getRelativeTime;
32
33
  exports.getRem = getRem.getRem;
34
+ exports.getRenderedLineHeight = getRenderedLineHeight.getRenderedLineHeight;
33
35
  exports.getScrollbarWidth = getScrollbarWidth.getScrollbarWidth;
34
36
  exports.getSessionStorage = getSessionStorage.getSessionStorage;
35
37
  exports.getStringLength = getStringLength.getStringLength;
@@ -10,9 +10,10 @@ export * from './get-gravatar-url';
10
10
  export * from './get-orientation';
11
11
  export * from './get-parent-list';
12
12
  export * from './get-query-params';
13
- export * from './get-relative-time';
14
13
  export * from './get-random-int';
14
+ export * from './get-relative-time';
15
15
  export * from './get-rem';
16
+ export * from './get-rendered-line-height';
16
17
  export * from './get-scrollbar-width';
17
18
  export * from './get-session-storage';
18
19
  export * from './get-string-length';
@@ -7,9 +7,10 @@ import { getGravatarUrl } from "./get-gravatar-url.es.js";
7
7
  import { getOrientation } from "./get-orientation.es.js";
8
8
  import { getParentList } from "./get-parent-list.es.js";
9
9
  import { getQueryParams } from "./get-query-params.es.js";
10
- import { getRelativeTime } from "./get-relative-time.es.js";
11
10
  import { getRandomInt } from "./get-random-int.es.js";
11
+ import { getRelativeTime } from "./get-relative-time.es.js";
12
12
  import { getRem } from "./get-rem.es.js";
13
+ import { getRenderedLineHeight } from "./get-rendered-line-height.es.js";
13
14
  import { getScrollbarWidth } from "./get-scrollbar-width.es.js";
14
15
  import { getSessionStorage } from "./get-session-storage.es.js";
15
16
  import { getStringLength } from "./get-string-length.es.js";
@@ -29,6 +30,7 @@ export {
29
30
  getRandomInt,
30
31
  getRelativeTime,
31
32
  getRem,
33
+ getRenderedLineHeight,
32
34
  getScrollbarWidth,
33
35
  getSessionStorage,
34
36
  getStringLength,
@@ -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.1",
3
+ "version": "0.13.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",