@hypen-space/web 0.4.946 → 0.4.948

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 (40) hide show
  1. package/dist/canvas/paint.js +23 -33
  2. package/dist/canvas/paint.js.map +1 -1
  3. package/dist/canvas/utils.js +6 -1
  4. package/dist/canvas/utils.js.map +1 -1
  5. package/dist/dom/applicators/advanced-layout.js +9 -8
  6. package/dist/dom/applicators/advanced-layout.js.map +1 -1
  7. package/dist/dom/applicators/border.js +10 -17
  8. package/dist/dom/applicators/border.js.map +1 -1
  9. package/dist/dom/applicators/effects.js +9 -8
  10. package/dist/dom/applicators/effects.js.map +1 -1
  11. package/dist/dom/applicators/font.js +2 -1
  12. package/dist/dom/applicators/font.js.map +1 -1
  13. package/dist/dom/applicators/layout.js +2 -1
  14. package/dist/dom/applicators/layout.js.map +1 -1
  15. package/dist/dom/applicators/margin.js +6 -7
  16. package/dist/dom/applicators/margin.js.map +1 -1
  17. package/dist/dom/applicators/padding.js +9 -10
  18. package/dist/dom/applicators/padding.js.map +1 -1
  19. package/dist/dom/applicators/size.d.ts +19 -0
  20. package/dist/dom/applicators/size.js +35 -9
  21. package/dist/dom/applicators/size.js.map +1 -1
  22. package/dist/dom/applicators/transform.js +5 -4
  23. package/dist/dom/applicators/transform.js.map +1 -1
  24. package/dist/dom/applicators/typography.js +14 -5
  25. package/dist/dom/applicators/typography.js.map +1 -1
  26. package/package.json +2 -2
  27. package/src/canvas/QUICKSTART.md +0 -2
  28. package/src/canvas/paint.ts +21 -32
  29. package/src/canvas/utils.ts +6 -1
  30. package/src/dom/applicators/advanced-layout.ts +9 -8
  31. package/src/dom/applicators/border.ts +10 -17
  32. package/src/dom/applicators/effects.ts +9 -8
  33. package/src/dom/applicators/font.ts +2 -1
  34. package/src/dom/applicators/layout.ts +2 -1
  35. package/src/dom/applicators/margin.ts +6 -6
  36. package/src/dom/applicators/padding.ts +9 -9
  37. package/src/dom/applicators/size.ts +34 -9
  38. package/src/dom/applicators/transform.ts +5 -4
  39. package/src/dom/applicators/typography.ts +13 -5
  40. package/src/canvas/PARITY.md +0 -254
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type { ApplicatorHandler } from "./index.js";
6
6
  import { mapAlignmentValue } from "./layout.js";
7
+ import { toCssLength } from "./size.js";
7
8
 
8
9
  export const advancedLayoutHandlers: Record<string, ApplicatorHandler> = {
9
10
  // Flexbox properties
@@ -12,7 +13,7 @@ export const advancedLayoutHandlers: Record<string, ApplicatorHandler> = {
12
13
  },
13
14
 
14
15
  flexBasis: (el, value) => {
15
- el.style.flexBasis = typeof value === "number" ? `${value}px` : String(value);
16
+ el.style.flexBasis = toCssLength(value);
16
17
  },
17
18
 
18
19
  alignContent: (el, value) => {
@@ -80,11 +81,11 @@ export const advancedLayoutHandlers: Record<string, ApplicatorHandler> = {
80
81
  },
81
82
 
82
83
  rowGap: (el, value) => {
83
- el.style.rowGap = typeof value === "number" ? `${value}px` : String(value);
84
+ el.style.rowGap = toCssLength(value);
84
85
  },
85
86
 
86
87
  columnGap: (el, value) => {
87
- el.style.columnGap = typeof value === "number" ? `${value}px` : String(value);
88
+ el.style.columnGap = toCssLength(value);
88
89
  },
89
90
 
90
91
  placeItems: (el, value) => {
@@ -105,23 +106,23 @@ export const advancedLayoutHandlers: Record<string, ApplicatorHandler> = {
105
106
  },
106
107
 
107
108
  top: (el, value) => {
108
- el.style.top = typeof value === "number" ? `${value}px` : String(value);
109
+ el.style.top = toCssLength(value);
109
110
  },
110
111
 
111
112
  right: (el, value) => {
112
- el.style.right = typeof value === "number" ? `${value}px` : String(value);
113
+ el.style.right = toCssLength(value);
113
114
  },
114
115
 
115
116
  bottom: (el, value) => {
116
- el.style.bottom = typeof value === "number" ? `${value}px` : String(value);
117
+ el.style.bottom = toCssLength(value);
117
118
  },
118
119
 
119
120
  left: (el, value) => {
120
- el.style.left = typeof value === "number" ? `${value}px` : String(value);
121
+ el.style.left = toCssLength(value);
121
122
  },
122
123
 
123
124
  inset: (el, value) => {
124
- el.style.inset = typeof value === "number" ? `${value}px` : String(value);
125
+ el.style.inset = toCssLength(value);
125
126
  },
126
127
 
127
128
  zIndex: (el, value) => {
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ApplicatorHandler } from "./types.js";
6
+ import { toCssLength } from "./size.js";
6
7
 
7
8
  export const borderHandlers: Record<string, ApplicatorHandler> = {
8
9
  // Compound border applicator - can take width, color, style, radius
@@ -16,7 +17,7 @@ export const borderHandlers: Record<string, ApplicatorHandler> = {
16
17
 
17
18
  // Width
18
19
  if (obj.width !== undefined) {
19
- el.style.borderWidth = typeof obj.width === "number" ? `${obj.width}px` : String(obj.width);
20
+ el.style.borderWidth = toCssLength(obj.width);
20
21
  }
21
22
 
22
23
  // Color
@@ -34,7 +35,7 @@ export const borderHandlers: Record<string, ApplicatorHandler> = {
34
35
 
35
36
  // Radius
36
37
  if (obj.radius !== undefined) {
37
- el.style.borderRadius = typeof obj.radius === "number" ? `${obj.radius}px` : String(obj.radius);
38
+ el.style.borderRadius = toCssLength(obj.radius);
38
39
  }
39
40
  } else if (typeof value === "string") {
40
41
  // CSS shorthand like "1px solid black"
@@ -43,7 +44,7 @@ export const borderHandlers: Record<string, ApplicatorHandler> = {
43
44
  },
44
45
 
45
46
  borderWidth: (el, value) => {
46
- el.style.borderWidth = typeof value === "number" ? `${value}px` : String(value);
47
+ el.style.borderWidth = toCssLength(value);
47
48
  // CSS `border-style` default is `none`, so a width-only border draws
48
49
  // nothing. The Hypen DSL writes `.borderWidth(2).borderColor(...)`
49
50
  // expecting a visible stroke (the social Stories ring + the Profile
@@ -60,38 +61,30 @@ export const borderHandlers: Record<string, ApplicatorHandler> = {
60
61
  },
61
62
 
62
63
  borderRadius: (el, value) => {
63
- if (typeof value === "number") {
64
- el.style.borderRadius = `${value}px`;
65
- } else if (typeof value === "object" && value !== null) {
64
+ if (typeof value === "object" && value !== null) {
66
65
  // Support for individual corners
67
66
  const obj = value as Record<string, any>;
68
67
  const topLeft = obj.topLeft ?? obj.topStart ?? 0;
69
68
  const topRight = obj.topRight ?? obj.topEnd ?? 0;
70
69
  const bottomRight = obj.bottomRight ?? obj.bottomEnd ?? 0;
71
70
  const bottomLeft = obj.bottomLeft ?? obj.bottomStart ?? 0;
72
-
73
- const formatValue = (v: any) => typeof v === "number" ? `${v}px` : String(v);
74
- el.style.borderRadius = `${formatValue(topLeft)} ${formatValue(topRight)} ${formatValue(bottomRight)} ${formatValue(bottomLeft)}`;
71
+ el.style.borderRadius = `${toCssLength(topLeft)} ${toCssLength(topRight)} ${toCssLength(bottomRight)} ${toCssLength(bottomLeft)}`;
75
72
  } else {
76
- el.style.borderRadius = String(value);
73
+ el.style.borderRadius = toCssLength(value);
77
74
  }
78
75
  },
79
76
 
80
77
  // Alias for borderRadius (Compose naming)
81
78
  cornerRadius: (el, value) => {
82
- if (typeof value === "number") {
83
- el.style.borderRadius = `${value}px`;
84
- } else if (typeof value === "object" && value !== null) {
79
+ if (typeof value === "object" && value !== null) {
85
80
  const obj = value as Record<string, any>;
86
81
  const topLeft = obj.topLeft ?? obj.topStart ?? 0;
87
82
  const topRight = obj.topRight ?? obj.topEnd ?? 0;
88
83
  const bottomRight = obj.bottomRight ?? obj.bottomEnd ?? 0;
89
84
  const bottomLeft = obj.bottomLeft ?? obj.bottomStart ?? 0;
90
-
91
- const formatValue = (v: any) => typeof v === "number" ? `${v}px` : String(v);
92
- el.style.borderRadius = `${formatValue(topLeft)} ${formatValue(topRight)} ${formatValue(bottomRight)} ${formatValue(bottomLeft)}`;
85
+ el.style.borderRadius = `${toCssLength(topLeft)} ${toCssLength(topRight)} ${toCssLength(bottomRight)} ${toCssLength(bottomLeft)}`;
93
86
  } else {
94
- el.style.borderRadius = String(value);
87
+ el.style.borderRadius = toCssLength(value);
95
88
  }
96
89
  },
97
90
  };
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ApplicatorHandler } from "./types.js";
6
+ import { toCssLength } from "./size.js";
6
7
 
7
8
  export const effectsHandlers: Record<string, ApplicatorHandler> = {
8
9
  // Shadow effects
@@ -12,10 +13,10 @@ export const effectsHandlers: Record<string, ApplicatorHandler> = {
12
13
  } else if (typeof value === "object" && value !== null) {
13
14
  // Object format: { x, y, blur, spread, color, inset }
14
15
  const obj = value as Record<string, any>;
15
- const x = typeof obj.x === "number" ? `${obj.x}px` : (obj.x ?? obj.offsetX ?? "0px");
16
- const y = typeof obj.y === "number" ? `${obj.y}px` : (obj.y ?? obj.offsetY ?? "0px");
17
- const blur = typeof obj.blur === "number" ? `${obj.blur}px` : (obj.blur ?? obj.radius ?? "0px");
18
- const spread = typeof obj.spread === "number" ? `${obj.spread}px` : (obj.spread ?? "0px");
16
+ const x = toCssLength(obj.x ?? obj.offsetX ?? 0);
17
+ const y = toCssLength(obj.y ?? obj.offsetY ?? 0);
18
+ const blur = toCssLength(obj.blur ?? obj.radius ?? 0);
19
+ const spread = toCssLength(obj.spread ?? 0);
19
20
  const color = obj.color ?? "rgba(0,0,0,0.2)";
20
21
  const inset = obj.inset ? "inset " : "";
21
22
  el.style.boxShadow = `${inset}${x} ${y} ${blur} ${spread} ${color}`;
@@ -29,9 +30,9 @@ export const effectsHandlers: Record<string, ApplicatorHandler> = {
29
30
  shadow: (el, value) => {
30
31
  if (typeof value === "object" && value !== null) {
31
32
  const obj = value as Record<string, any>;
32
- const x = typeof obj.x === "number" ? `${obj.x}px` : (obj.x ?? obj.offsetX ?? "0px");
33
- const y = typeof obj.y === "number" ? `${obj.y}px` : (obj.y ?? obj.offsetY ?? "0px");
34
- const blur = typeof obj.blur === "number" ? `${obj.blur}px` : (obj.blur ?? obj.radius ?? "4px");
33
+ const x = toCssLength(obj.x ?? obj.offsetX ?? 0);
34
+ const y = toCssLength(obj.y ?? obj.offsetY ?? 0);
35
+ const blur = toCssLength(obj.blur ?? obj.radius ?? 4);
35
36
  const color = obj.color ?? "rgba(0,0,0,0.2)";
36
37
  el.style.boxShadow = `${x} ${y} ${blur} ${color}`;
37
38
  } else if (typeof value === "number") {
@@ -69,7 +70,7 @@ export const effectsHandlers: Record<string, ApplicatorHandler> = {
69
70
 
70
71
  // Individual filter functions
71
72
  blur: (el, value) => {
72
- const val = typeof value === "number" ? `${value}px` : String(value);
73
+ const val = toCssLength(value);
73
74
  const current = el.style.filter || "";
74
75
  el.style.filter = current ? `${current} blur(${val})` : `blur(${val})`;
75
76
  },
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ApplicatorHandler } from "./types.js";
6
+ import { toCssLength } from "./size.js";
6
7
 
7
8
  // Track loaded Google Fonts to avoid duplicate link tags
8
9
  const loadedGoogleFonts = new Set<string>();
@@ -75,7 +76,7 @@ function processFontFamily(value: string): string {
75
76
 
76
77
  export const fontHandlers: Record<string, ApplicatorHandler> = {
77
78
  fontSize: (el, value) => {
78
- el.style.fontSize = typeof value === "number" ? `${value}px` : String(value);
79
+ el.style.fontSize = toCssLength(value);
79
80
  },
80
81
 
81
82
  fontWeight: (el, value) => {
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ApplicatorHandler } from "./types.js";
6
+ import { toCssLength } from "./size.js";
6
7
 
7
8
  /**
8
9
  * Maps Hypen alignment values to CSS flexbox values.
@@ -97,7 +98,7 @@ export const layoutHandlers: Record<string, ApplicatorHandler> = {
97
98
  },
98
99
 
99
100
  gap: (el, value) => {
100
- el.style.gap = typeof value === "number" ? `${value}px` : String(value);
101
+ el.style.gap = toCssLength(value);
101
102
  },
102
103
 
103
104
  // weight: unified cross-platform API (same as flex)
@@ -3,15 +3,15 @@
3
3
  */
4
4
 
5
5
  import type { ApplicatorHandler } from "./types.js";
6
+ import { toCssLength as toCssLengthShared } from "./size.js";
6
7
 
7
- // Format a value as a CSS length: numbers become "Npx", strings pass through.
8
- // Same caveat as `padding.ts#toCssLength`: rem/em/% values must survive,
9
- // otherwise `parseFloat("0.5rem")` collapses to literal `0.5px`.
8
+ // See `padding.ts#toCssLength` shared helper normalises `dp` / `sp` / `pt`
9
+ // (which CSS doesn't understand) to `px`, and passes `rem` / `em` / `%`
10
+ // through unchanged.
10
11
  const toCssLength = (v: any): string => {
11
12
  if (v == null) return "";
12
- if (typeof v === "number") return `${v}px`;
13
13
  if (typeof v === "object" && v["0"] !== undefined) return toCssLength(v["0"]);
14
- return String(v);
14
+ return toCssLengthShared(v);
15
15
  };
16
16
 
17
17
  // Collect positional args ("0", "1", "2", "3") in order, stopping at the first gap.
@@ -30,7 +30,7 @@ export const marginHandler: ApplicatorHandler = (el, value) => {
30
30
  }
31
31
 
32
32
  if (typeof value !== "object" || value === null) {
33
- el.style.margin = String(value);
33
+ el.style.margin = toCssLength(value);
34
34
  return;
35
35
  }
36
36
 
@@ -3,18 +3,18 @@
3
3
  */
4
4
 
5
5
  import type { ApplicatorHandler } from "./types.js";
6
+ import { toCssLength as toCssLengthShared } from "./size.js";
6
7
 
7
- // Format a value as a CSS length: numbers become "Npx", strings pass through.
8
- // Strings come through verbatim because the Tailwind→CSS pipeline emits
9
- // values like `"0.5rem"` (= py-2) or `"1rem"` (= px-4); stripping the unit
10
- // via `parseFloat` collapsed them to literal `0.5px` / `1px` and the
11
- // social feed rendered with no usable spacing (avatars touched the
12
- // container edges, the BottomNav fell off-screen, etc.).
8
+ // Format a value as a CSS length. Delegates to the shared helper in
9
+ // `size.ts` so `dp` / `sp` / `pt` normalise to `px` (CSS doesn't understand
10
+ // those suffixes). Numbers become `${n}px`; anything CSS already knows
11
+ // (`rem`, `em`, `%`, `calc(...)`, …) passes through unchanged. The object
12
+ // form (`v["0"]`) is carried over from the legacy applicator-argument
13
+ // shape that sometimes reaches this handler.
13
14
  const toCssLength = (v: any): string => {
14
15
  if (v == null) return "";
15
- if (typeof v === "number") return `${v}px`;
16
16
  if (typeof v === "object" && v["0"] !== undefined) return toCssLength(v["0"]);
17
- return String(v);
17
+ return toCssLengthShared(v);
18
18
  };
19
19
 
20
20
  // Collect positional args ("0", "1", "2", "3") in order, stopping at the first
@@ -34,7 +34,7 @@ export const paddingHandler: ApplicatorHandler = (el, value) => {
34
34
  }
35
35
 
36
36
  if (typeof value !== "object" || value === null) {
37
- el.style.padding = String(value);
37
+ el.style.padding = toCssLength(value);
38
38
  return;
39
39
  }
40
40
 
@@ -16,8 +16,14 @@ import type { ApplicatorHandler } from "./types.js";
16
16
  /**
17
17
  * Parse a size value and return CSS-compatible string.
18
18
  * Ensures cross-platform compatibility with Android/iOS.
19
+ *
20
+ * Exported for reuse by other DOM applicators (padding, margin, font,
21
+ * typography, border, …) that historically passed strings through
22
+ * untouched. CSS doesn't understand `dp` / `sp`, so `fontSize("24dp")`
23
+ * or `padding("16sp")` would otherwise be silently dropped by the
24
+ * browser even though the Android / iOS renderers accept them.
19
25
  */
20
- function parseSizeValue(value: any): string | null {
26
+ export function parseSizeValue(value: any): string | null {
21
27
  if (value === null || value === undefined) return null;
22
28
 
23
29
  // Numbers default to px
@@ -42,8 +48,10 @@ function parseSizeValue(value: any): string | null {
42
48
  return "100%";
43
49
  }
44
50
 
45
- // Parse value with unit
46
- const match = str.match(/^(-?[\d.]+)\s*(px|dp|pt|%|vw|vh|vmin|vmax|em|rem)?$/);
51
+ // Parse value with unit. `sp` is accepted as an alias for `dp` — on web,
52
+ // density-independent and scale-independent units all collapse to CSS
53
+ // `px` at 96dpi (there's no separate text-scaling knob on the DOM side).
54
+ const match = str.match(/^(-?[\d.]+)\s*(px|dp|pt|sp|%|vw|vh|vmin|vmax|em|rem)?$/);
47
55
  if (!match) {
48
56
  // Pass through other CSS values as-is (e.g., "calc(...)", "fit-content")
49
57
  return str;
@@ -57,13 +65,17 @@ function parseSizeValue(value: any): string | null {
57
65
  // Absolute pixels - use as-is
58
66
  return `${num}px`;
59
67
  case "dp":
60
- case "pt":
61
- // Density-independent points
62
- // On web, 1dp/1pt 1px at standard density (96dpi)
63
- // CSS already handles this via px, so we just use px
64
- // For true density independence, we'd need to query devicePixelRatio
65
- // but CSS px is already defined as 1/96th of an inch
68
+ case "sp":
69
+ // Density/scale-independent logical pixels.
70
+ // On web, 1dp/1sp = 1 CSS px at standard density (96dpi).
71
+ // (`sp` does not yet scale with the user's text-size preference
72
+ // that's a separate cross-renderer change.)
66
73
  return `${num}px`;
74
+ case "pt":
75
+ // Typographic point = 1/72 inch. Emit native CSS `pt` so the
76
+ // browser's own length resolution runs (1pt = 1.333… CSS px at
77
+ // 96dpi). Matches the 96/72 multiplier used on iOS and Android.
78
+ return `${num}pt`;
67
79
  case "%":
68
80
  return `${num}%`;
69
81
  case "vw":
@@ -83,6 +95,19 @@ function parseSizeValue(value: any): string | null {
83
95
  }
84
96
  }
85
97
 
98
+ /**
99
+ * Coerce a Hypen length value to a CSS length string for applicators that
100
+ * feed directly into `el.style.*`. Numbers become `${n}px`; strings with
101
+ * platform-agnostic units (`dp`, `sp`, `pt`) are normalised; anything the
102
+ * browser already understands (`em`, `rem`, `%`, `calc(...)`, …) passes
103
+ * through.
104
+ */
105
+ export function toCssLength(value: any): string {
106
+ if (value === null || value === undefined) return "";
107
+ if (typeof value === "number") return `${value}px`;
108
+ return parseSizeValue(value) ?? String(value);
109
+ }
110
+
86
111
  export const sizeHandlers: Record<string, ApplicatorHandler> = {
87
112
  width: (el, value) => {
88
113
  const size = parseSizeValue(value);
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ApplicatorHandler } from "./types.js";
6
+ import { toCssLength } from "./size.js";
6
7
 
7
8
  export const transformHandlers: Record<string, ApplicatorHandler> = {
8
9
  transform: (el, value) => {
@@ -15,19 +16,19 @@ export const transformHandlers: Record<string, ApplicatorHandler> = {
15
16
 
16
17
  translateX: (el, value) => {
17
18
  const current = el.style.transform || "";
18
- const val = typeof value === "number" ? `${value}px` : String(value);
19
+ const val = toCssLength(value);
19
20
  el.style.transform = current ? `${current} translateX(${val})` : `translateX(${val})`;
20
21
  },
21
22
 
22
23
  translateY: (el, value) => {
23
24
  const current = el.style.transform || "";
24
- const val = typeof value === "number" ? `${value}px` : String(value);
25
+ const val = toCssLength(value);
25
26
  el.style.transform = current ? `${current} translateY(${val})` : `translateY(${val})`;
26
27
  },
27
28
 
28
29
  translateZ: (el, value) => {
29
30
  const current = el.style.transform || "";
30
- const val = typeof value === "number" ? `${value}px` : String(value);
31
+ const val = toCssLength(value);
31
32
  el.style.transform = current ? `${current} translateZ(${val})` : `translateZ(${val})`;
32
33
  },
33
34
 
@@ -86,7 +87,7 @@ export const transformHandlers: Record<string, ApplicatorHandler> = {
86
87
  },
87
88
 
88
89
  perspective: (el, value) => {
89
- el.style.perspective = typeof value === "number" ? `${value}px` : String(value);
90
+ el.style.perspective = toCssLength(value);
90
91
  },
91
92
  };
92
93
 
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ApplicatorHandler } from "./types.js";
6
+ import { toCssLength } from "./size.js";
6
7
 
7
8
  export const typographyHandlers: Record<string, ApplicatorHandler> = {
8
9
  textAlign: (el, value) => {
@@ -36,23 +37,30 @@ export const typographyHandlers: Record<string, ApplicatorHandler> = {
36
37
  },
37
38
 
38
39
  textDecorationThickness: (el, value) => {
39
- el.style.textDecorationThickness = typeof value === "number" ? `${value}px` : String(value);
40
+ el.style.textDecorationThickness = toCssLength(value);
40
41
  },
41
42
 
42
43
  letterSpacing: (el, value) => {
43
- el.style.letterSpacing = typeof value === "number" ? `${value}px` : String(value);
44
+ el.style.letterSpacing = toCssLength(value);
44
45
  },
45
46
 
46
47
  wordSpacing: (el, value) => {
47
- el.style.wordSpacing = typeof value === "number" ? `${value}px` : String(value);
48
+ el.style.wordSpacing = toCssLength(value);
48
49
  },
49
50
 
50
51
  lineHeight: (el, value) => {
51
- el.style.lineHeight = String(value);
52
+ // `line-height` is unitless by convention when the value is a bare
53
+ // number (CSS multiplier on the element's font-size); only normalise
54
+ // when the value carries a length unit like `dp` / `sp`.
55
+ if (typeof value === "string" && /^-?[\d.]+\s*(dp|sp)$/i.test(value.trim())) {
56
+ el.style.lineHeight = toCssLength(value);
57
+ } else {
58
+ el.style.lineHeight = String(value);
59
+ }
52
60
  },
53
61
 
54
62
  textIndent: (el, value) => {
55
- el.style.textIndent = typeof value === "number" ? `${value}px` : String(value);
63
+ el.style.textIndent = toCssLength(value);
56
64
  },
57
65
 
58
66
  textOverflow: (el, value) => {