umaki 0.12.0 → 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.
- package/README.md +43 -0
- package/dist/index.cjs.js +4 -2
- package/dist/index.es.js +3 -1
- package/dist/libs/get/get-rendered-line-height.cjs.js +57 -0
- package/dist/libs/get/get-rendered-line-height.d.ts +37 -0
- package/dist/libs/get/get-rendered-line-height.es.js +57 -0
- package/dist/libs/get/get-rendered-line-height.test.d.ts +1 -0
- package/dist/libs/get/index.cjs.js +4 -2
- package/dist/libs/get/index.d.ts +2 -1
- package/dist/libs/get/index.es.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,6 +106,7 @@ console.log(breakpoint); // e.g. 768 (default) or custom value if set
|
|
|
106
106
|
- [getRandomInt](#getrandomint)
|
|
107
107
|
- [getRelativeTime](#getrelativetime)
|
|
108
108
|
- [getRem](#getrem)
|
|
109
|
+
- [getRenderedLineHeight](#getrenderedlineheight)
|
|
109
110
|
- [getScrollbarWidth](#getscrollbarwidth)
|
|
110
111
|
- [getSessionStorage](#getsessionstorage)
|
|
111
112
|
- [getStringLength](#getstringlength)
|
|
@@ -619,6 +620,48 @@ console.log(remValue); // '1rem'
|
|
|
619
620
|
|
|
620
621
|
[View file →](src/libs/get/get-rem.ts)
|
|
621
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
|
+
|
|
622
665
|
### getScrollbarWidth
|
|
623
666
|
|
|
624
667
|
A function that retrieves the width of the scrollbar.
|
package/dist/index.cjs.js
CHANGED
|
@@ -25,9 +25,10 @@ const getGravatarUrl = require("./libs/get/get-gravatar-url.cjs.js");
|
|
|
25
25
|
const getOrientation = require("./libs/get/get-orientation.cjs.js");
|
|
26
26
|
const getParentList = require("./libs/get/get-parent-list.cjs.js");
|
|
27
27
|
const getQueryParams = require("./libs/get/get-query-params.cjs.js");
|
|
28
|
-
const getRelativeTime = require("./libs/get/get-relative-time.cjs.js");
|
|
29
28
|
const getRandomInt = require("./libs/get/get-random-int.cjs.js");
|
|
29
|
+
const getRelativeTime = require("./libs/get/get-relative-time.cjs.js");
|
|
30
30
|
const getRem = require("./libs/get/get-rem.cjs.js");
|
|
31
|
+
const getRenderedLineHeight = require("./libs/get/get-rendered-line-height.cjs.js");
|
|
31
32
|
const getScrollbarWidth = require("./libs/get/get-scrollbar-width.cjs.js");
|
|
32
33
|
const getSessionStorage = require("./libs/get/get-session-storage.cjs.js");
|
|
33
34
|
const getStringLength = require("./libs/get/get-string-length.cjs.js");
|
|
@@ -87,9 +88,10 @@ exports.getGravatarUrl = getGravatarUrl.getGravatarUrl;
|
|
|
87
88
|
exports.getOrientation = getOrientation.getOrientation;
|
|
88
89
|
exports.getParentList = getParentList.getParentList;
|
|
89
90
|
exports.getQueryParams = getQueryParams.getQueryParams;
|
|
90
|
-
exports.getRelativeTime = getRelativeTime.getRelativeTime;
|
|
91
91
|
exports.getRandomInt = getRandomInt.getRandomInt;
|
|
92
|
+
exports.getRelativeTime = getRelativeTime.getRelativeTime;
|
|
92
93
|
exports.getRem = getRem.getRem;
|
|
94
|
+
exports.getRenderedLineHeight = getRenderedLineHeight.getRenderedLineHeight;
|
|
93
95
|
exports.getScrollbarWidth = getScrollbarWidth.getScrollbarWidth;
|
|
94
96
|
exports.getSessionStorage = getSessionStorage.getSessionStorage;
|
|
95
97
|
exports.getStringLength = getStringLength.getStringLength;
|
package/dist/index.es.js
CHANGED
|
@@ -23,9 +23,10 @@ import { getGravatarUrl } from "./libs/get/get-gravatar-url.es.js";
|
|
|
23
23
|
import { getOrientation } from "./libs/get/get-orientation.es.js";
|
|
24
24
|
import { getParentList } from "./libs/get/get-parent-list.es.js";
|
|
25
25
|
import { getQueryParams } from "./libs/get/get-query-params.es.js";
|
|
26
|
-
import { getRelativeTime } from "./libs/get/get-relative-time.es.js";
|
|
27
26
|
import { getRandomInt } from "./libs/get/get-random-int.es.js";
|
|
27
|
+
import { getRelativeTime } from "./libs/get/get-relative-time.es.js";
|
|
28
28
|
import { getRem } from "./libs/get/get-rem.es.js";
|
|
29
|
+
import { getRenderedLineHeight } from "./libs/get/get-rendered-line-height.es.js";
|
|
29
30
|
import { getScrollbarWidth } from "./libs/get/get-scrollbar-width.es.js";
|
|
30
31
|
import { getSessionStorage } from "./libs/get/get-session-storage.es.js";
|
|
31
32
|
import { getStringLength } from "./libs/get/get-string-length.es.js";
|
|
@@ -80,6 +81,7 @@ export {
|
|
|
80
81
|
getRandomInt,
|
|
81
82
|
getRelativeTime,
|
|
82
83
|
getRem,
|
|
84
|
+
getRenderedLineHeight,
|
|
83
85
|
getScrollbarWidth,
|
|
84
86
|
getSessionStorage,
|
|
85
87
|
getStringLength,
|
|
@@ -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 {};
|
|
@@ -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;
|
package/dist/libs/get/index.d.ts
CHANGED
|
@@ -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,
|