@remotion/rounded-text-box 4.0.369 → 4.0.371
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/package.json +4 -4
- package/dist/cjs/layouts/fill-text-box.d.ts +0 -10
- package/dist/cjs/layouts/fill-text-box.js +0 -63
- package/dist/cjs/layouts/fit-text-on-n-lines.d.ts +0 -19
- package/dist/cjs/layouts/fit-text-on-n-lines.js +0 -67
- package/dist/cjs/layouts/fit-text.d.ts +0 -14
- package/dist/cjs/layouts/fit-text.js +0 -24
- package/dist/cjs/layouts/measure-text.d.ts +0 -23
- package/dist/cjs/layouts/measure-text.js +0 -94
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/rounded-text-box"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/rounded-text-box",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.371",
|
|
7
7
|
"description": "Create a TikTok-like multiline text box SVG path with rounded corners",
|
|
8
8
|
"main": "dist/cjs/index.js",
|
|
9
9
|
"types": "dist/cjs/index.d.ts",
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@remotion/layout-utils": "4.0.
|
|
28
|
-
"@remotion/paths": "4.0.
|
|
27
|
+
"@remotion/layout-utils": "4.0.371",
|
|
28
|
+
"@remotion/paths": "4.0.371"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
31
|
+
"@remotion/eslint-config-internal": "4.0.371",
|
|
32
32
|
"eslint": "9.19.0"
|
|
33
33
|
},
|
|
34
34
|
"author": "Jonny Burger <jonny@remotion.dev>",
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type Word } from './measure-text';
|
|
2
|
-
export declare const fillTextBox: ({ maxBoxWidth, maxLines, }: {
|
|
3
|
-
maxBoxWidth: number;
|
|
4
|
-
maxLines: number;
|
|
5
|
-
}) => {
|
|
6
|
-
add: ({ text, fontFamily, fontWeight, fontSize, letterSpacing, fontVariantNumeric, validateFontIsLoaded, textTransform, additionalStyles, }: Word) => {
|
|
7
|
-
exceedsBox: boolean;
|
|
8
|
-
newLine: boolean;
|
|
9
|
-
};
|
|
10
|
-
};
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fillTextBox = void 0;
|
|
4
|
-
const measure_text_1 = require("./measure-text");
|
|
5
|
-
const fillTextBox = ({ maxBoxWidth, maxLines, }) => {
|
|
6
|
-
const lines = new Array(maxLines).fill(0).map(() => []);
|
|
7
|
-
return {
|
|
8
|
-
add: ({ text, fontFamily, fontWeight, fontSize, letterSpacing, fontVariantNumeric, validateFontIsLoaded, textTransform, additionalStyles, }) => {
|
|
9
|
-
const lastLineIndex = lines.reduceRight((acc, curr, index) => {
|
|
10
|
-
if (acc === -1 && curr.length > 0) {
|
|
11
|
-
return index;
|
|
12
|
-
}
|
|
13
|
-
return acc;
|
|
14
|
-
}, -1);
|
|
15
|
-
const currentlyAt = lastLineIndex === -1 ? 0 : lastLineIndex;
|
|
16
|
-
const lineToUse = lines[currentlyAt];
|
|
17
|
-
const lineWithWord = [
|
|
18
|
-
...lineToUse,
|
|
19
|
-
{
|
|
20
|
-
text,
|
|
21
|
-
fontFamily,
|
|
22
|
-
fontWeight,
|
|
23
|
-
fontSize,
|
|
24
|
-
letterSpacing,
|
|
25
|
-
fontVariantNumeric,
|
|
26
|
-
validateFontIsLoaded,
|
|
27
|
-
textTransform,
|
|
28
|
-
additionalStyles,
|
|
29
|
-
},
|
|
30
|
-
];
|
|
31
|
-
const widths = lineWithWord.map((w) => (0, measure_text_1.measureText)(w).width);
|
|
32
|
-
const lineWidthWithWordAdded = widths.reduce((a, b) => a + b, 0);
|
|
33
|
-
if (Math.ceil(lineWidthWithWordAdded) < maxBoxWidth) {
|
|
34
|
-
lines[currentlyAt].push({
|
|
35
|
-
text: lines[currentlyAt].length === 0 ? text.trimStart() : text,
|
|
36
|
-
fontFamily,
|
|
37
|
-
fontWeight,
|
|
38
|
-
fontSize,
|
|
39
|
-
letterSpacing,
|
|
40
|
-
textTransform,
|
|
41
|
-
fontVariantNumeric,
|
|
42
|
-
});
|
|
43
|
-
return { exceedsBox: false, newLine: false };
|
|
44
|
-
}
|
|
45
|
-
if (currentlyAt === maxLines - 1) {
|
|
46
|
-
return { exceedsBox: true, newLine: false };
|
|
47
|
-
}
|
|
48
|
-
lines[currentlyAt + 1] = [
|
|
49
|
-
{
|
|
50
|
-
text: text.trimStart(),
|
|
51
|
-
fontFamily,
|
|
52
|
-
fontWeight,
|
|
53
|
-
fontSize,
|
|
54
|
-
letterSpacing,
|
|
55
|
-
textTransform,
|
|
56
|
-
fontVariantNumeric,
|
|
57
|
-
},
|
|
58
|
-
];
|
|
59
|
-
return { exceedsBox: false, newLine: true };
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
};
|
|
63
|
-
exports.fillTextBox = fillTextBox;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { TextTransform } from './measure-text';
|
|
2
|
-
type FitTextOnNLinesProps = {
|
|
3
|
-
text: string;
|
|
4
|
-
maxLines: number;
|
|
5
|
-
maxBoxWidth: number;
|
|
6
|
-
fontFamily: string;
|
|
7
|
-
fontWeight?: number | string;
|
|
8
|
-
letterSpacing?: string;
|
|
9
|
-
fontVariantNumeric?: string;
|
|
10
|
-
validateFontIsLoaded?: boolean;
|
|
11
|
-
textTransform?: TextTransform;
|
|
12
|
-
additionalStyles?: Record<string, string>;
|
|
13
|
-
maxFontSize?: number;
|
|
14
|
-
};
|
|
15
|
-
export declare const fitTextOnNLines: ({ text, maxLines, maxBoxWidth, fontFamily, fontWeight, letterSpacing, fontVariantNumeric, validateFontIsLoaded, textTransform, additionalStyles, maxFontSize, }: FitTextOnNLinesProps) => {
|
|
16
|
-
fontSize: number;
|
|
17
|
-
lines: string[];
|
|
18
|
-
};
|
|
19
|
-
export {};
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fitTextOnNLines = void 0;
|
|
4
|
-
const fill_text_box_1 = require("./fill-text-box");
|
|
5
|
-
const PRECISION = 100;
|
|
6
|
-
const fitTextOnNLines = ({ text, maxLines, maxBoxWidth, fontFamily, fontWeight, letterSpacing, fontVariantNumeric, validateFontIsLoaded, textTransform, additionalStyles, maxFontSize, }) => {
|
|
7
|
-
// Fixed max font size since we are using binary search a
|
|
8
|
-
const minFontSize = 0.1;
|
|
9
|
-
// Binary search to find the optimal font size
|
|
10
|
-
let left = Math.floor(minFontSize * PRECISION);
|
|
11
|
-
let right = Math.floor((maxFontSize !== null && maxFontSize !== void 0 ? maxFontSize : 2000) * PRECISION);
|
|
12
|
-
let optimalFontSize = minFontSize;
|
|
13
|
-
let optimalLines = [];
|
|
14
|
-
while (left <= right) {
|
|
15
|
-
const mid = Math.floor((left + right) / 2);
|
|
16
|
-
const fontSize = mid / PRECISION;
|
|
17
|
-
// Create a text box with current font size
|
|
18
|
-
const textBox = (0, fill_text_box_1.fillTextBox)({
|
|
19
|
-
maxBoxWidth,
|
|
20
|
-
maxLines,
|
|
21
|
-
});
|
|
22
|
-
// Split text into words and try to fit them
|
|
23
|
-
const words = text.split(' ');
|
|
24
|
-
let exceedsBox = false;
|
|
25
|
-
let currentLine = 0;
|
|
26
|
-
const lines = [''];
|
|
27
|
-
for (const word of words) {
|
|
28
|
-
const result = textBox.add({
|
|
29
|
-
text: lines[currentLine].length === 0 ? word : ' ' + word,
|
|
30
|
-
fontFamily,
|
|
31
|
-
fontWeight,
|
|
32
|
-
fontSize,
|
|
33
|
-
letterSpacing,
|
|
34
|
-
fontVariantNumeric,
|
|
35
|
-
validateFontIsLoaded,
|
|
36
|
-
textTransform,
|
|
37
|
-
additionalStyles,
|
|
38
|
-
});
|
|
39
|
-
if (result.exceedsBox) {
|
|
40
|
-
exceedsBox = true;
|
|
41
|
-
break;
|
|
42
|
-
}
|
|
43
|
-
if (result.newLine) {
|
|
44
|
-
lines.push('');
|
|
45
|
-
currentLine++;
|
|
46
|
-
}
|
|
47
|
-
lines[currentLine] += word + ' ';
|
|
48
|
-
}
|
|
49
|
-
// If text fits within the box and number of lines
|
|
50
|
-
if (!exceedsBox && currentLine < maxLines) {
|
|
51
|
-
optimalFontSize = fontSize;
|
|
52
|
-
optimalLines = lines;
|
|
53
|
-
left = mid + 1;
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
right = mid - 1;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
for (let i = 0; i < optimalLines.length; i++) {
|
|
60
|
-
optimalLines[i] = optimalLines[i].trimEnd();
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
fontSize: optimalFontSize,
|
|
64
|
-
lines: optimalLines,
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
exports.fitTextOnNLines = fitTextOnNLines;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ModifyableCSSProperties, TextTransform } from '../layouts/measure-text';
|
|
2
|
-
export declare const fitText: ({ text, withinWidth, fontFamily, fontVariantNumeric, fontWeight, letterSpacing, validateFontIsLoaded, additionalStyles, textTransform, }: {
|
|
3
|
-
text: string;
|
|
4
|
-
withinWidth: number;
|
|
5
|
-
fontFamily: string;
|
|
6
|
-
fontWeight?: number | string;
|
|
7
|
-
letterSpacing?: string;
|
|
8
|
-
fontVariantNumeric?: string;
|
|
9
|
-
validateFontIsLoaded?: boolean;
|
|
10
|
-
textTransform?: TextTransform;
|
|
11
|
-
additionalStyles?: ModifyableCSSProperties;
|
|
12
|
-
}) => {
|
|
13
|
-
fontSize: number;
|
|
14
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fitText = void 0;
|
|
4
|
-
const measure_text_1 = require("../layouts/measure-text");
|
|
5
|
-
const sampleSize = 100;
|
|
6
|
-
/*
|
|
7
|
-
* @description Calculates the font size needed to fit text into a specified width container.
|
|
8
|
-
* @see [Documentation](https://remotion.dev/docs/layout-utils/fit-text)
|
|
9
|
-
*/
|
|
10
|
-
const fitText = ({ text, withinWidth, fontFamily, fontVariantNumeric, fontWeight, letterSpacing, validateFontIsLoaded, additionalStyles, textTransform, }) => {
|
|
11
|
-
const estimate = (0, measure_text_1.measureText)({
|
|
12
|
-
text,
|
|
13
|
-
fontFamily,
|
|
14
|
-
fontSize: sampleSize,
|
|
15
|
-
fontWeight,
|
|
16
|
-
fontVariantNumeric,
|
|
17
|
-
letterSpacing,
|
|
18
|
-
validateFontIsLoaded,
|
|
19
|
-
textTransform,
|
|
20
|
-
additionalStyles,
|
|
21
|
-
});
|
|
22
|
-
return { fontSize: (withinWidth / estimate.width) * sampleSize };
|
|
23
|
-
};
|
|
24
|
-
exports.fitText = fitText;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export type Dimensions = {
|
|
2
|
-
width: number;
|
|
3
|
-
height: number;
|
|
4
|
-
};
|
|
5
|
-
export type ModifyableCSSProperties<T = Partial<CSSStyleDeclaration>> = {
|
|
6
|
-
[P in keyof T as P extends 'length' ? never : P extends keyof CSSPropertiesOnWord ? never : T[P] extends string | number ? P : never]: T[P];
|
|
7
|
-
};
|
|
8
|
-
export type TextTransform = '-moz-initial' | 'inherit' | 'initial' | 'revert' | 'revert-layer' | 'unset' | 'none' | 'capitalize' | 'full-size-kana' | 'full-width' | 'lowercase' | 'uppercase';
|
|
9
|
-
type CSSPropertiesOnWord = {
|
|
10
|
-
fontFamily: string;
|
|
11
|
-
fontSize: number | string;
|
|
12
|
-
fontWeight?: number | string;
|
|
13
|
-
letterSpacing?: string;
|
|
14
|
-
fontVariantNumeric?: string;
|
|
15
|
-
textTransform?: TextTransform;
|
|
16
|
-
};
|
|
17
|
-
export type Word = {
|
|
18
|
-
text: string;
|
|
19
|
-
validateFontIsLoaded?: boolean;
|
|
20
|
-
additionalStyles?: ModifyableCSSProperties;
|
|
21
|
-
} & CSSPropertiesOnWord;
|
|
22
|
-
export declare const measureText: ({ text, fontFamily, fontSize, fontWeight, letterSpacing, fontVariantNumeric, validateFontIsLoaded, additionalStyles, textTransform, }: Word) => Dimensions;
|
|
23
|
-
export {};
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.measureText = void 0;
|
|
4
|
-
const wordCache = new Map();
|
|
5
|
-
const takeMeasurement = ({ text, fontFamily, fontSize, fontWeight, letterSpacing, fontVariantNumeric, additionalStyles, textTransform, }) => {
|
|
6
|
-
if (typeof document === 'undefined') {
|
|
7
|
-
throw new Error('measureText() can only be called in a browser.');
|
|
8
|
-
}
|
|
9
|
-
const node = document.createElement('span');
|
|
10
|
-
if (fontFamily) {
|
|
11
|
-
node.style.fontFamily = fontFamily;
|
|
12
|
-
}
|
|
13
|
-
node.style.display = 'inline-block';
|
|
14
|
-
node.style.position = 'absolute';
|
|
15
|
-
node.style.top = `-10000px`;
|
|
16
|
-
node.style.whiteSpace = 'pre';
|
|
17
|
-
node.style.fontSize =
|
|
18
|
-
typeof fontSize === 'string' ? fontSize : `${fontSize}px`;
|
|
19
|
-
if (additionalStyles) {
|
|
20
|
-
for (const key of Object.keys(additionalStyles)) {
|
|
21
|
-
node.style[key] = additionalStyles[key];
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
if (fontWeight) {
|
|
25
|
-
node.style.fontWeight = fontWeight.toString();
|
|
26
|
-
}
|
|
27
|
-
if (letterSpacing) {
|
|
28
|
-
node.style.letterSpacing = letterSpacing;
|
|
29
|
-
}
|
|
30
|
-
if (fontVariantNumeric) {
|
|
31
|
-
node.style.fontVariantNumeric = fontVariantNumeric;
|
|
32
|
-
}
|
|
33
|
-
if (textTransform) {
|
|
34
|
-
node.style.textTransform = textTransform;
|
|
35
|
-
}
|
|
36
|
-
node.innerText = text;
|
|
37
|
-
document.body.appendChild(node);
|
|
38
|
-
const computedFontFamily = window.getComputedStyle(node).fontFamily;
|
|
39
|
-
const boundingBox = node.getBoundingClientRect();
|
|
40
|
-
document.body.removeChild(node);
|
|
41
|
-
return {
|
|
42
|
-
boundingBox,
|
|
43
|
-
computedFontFamily,
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
/*
|
|
47
|
-
* @description Calculates the width and height of specified text to be used for layout calculations. Only works in the browser, not in Node.js or Bun.
|
|
48
|
-
* @see [Documentation](https://remotion.dev/docs/layout-utils/measure-text)
|
|
49
|
-
*/
|
|
50
|
-
const measureText = ({ text, fontFamily, fontSize, fontWeight, letterSpacing, fontVariantNumeric, validateFontIsLoaded, additionalStyles, textTransform, }) => {
|
|
51
|
-
const key = `${text}-${fontFamily}-${fontWeight}-${fontSize}-${letterSpacing}-${textTransform}-${JSON.stringify(additionalStyles)}`;
|
|
52
|
-
if (wordCache.has(key)) {
|
|
53
|
-
return wordCache.get(key);
|
|
54
|
-
}
|
|
55
|
-
const { boundingBox, computedFontFamily } = takeMeasurement({
|
|
56
|
-
fontFamily,
|
|
57
|
-
fontSize,
|
|
58
|
-
text,
|
|
59
|
-
fontVariantNumeric,
|
|
60
|
-
fontWeight,
|
|
61
|
-
letterSpacing,
|
|
62
|
-
additionalStyles,
|
|
63
|
-
textTransform,
|
|
64
|
-
});
|
|
65
|
-
if (validateFontIsLoaded && text.trim().length > 0) {
|
|
66
|
-
const { boundingBox: boundingBoxOfFallbackFont, computedFontFamily: computedFallback, } = takeMeasurement({
|
|
67
|
-
fontFamily: null,
|
|
68
|
-
fontSize,
|
|
69
|
-
text,
|
|
70
|
-
fontVariantNumeric,
|
|
71
|
-
fontWeight,
|
|
72
|
-
letterSpacing,
|
|
73
|
-
additionalStyles,
|
|
74
|
-
textTransform,
|
|
75
|
-
});
|
|
76
|
-
const sameAsFallbackFont = boundingBox.height === boundingBoxOfFallbackFont.height &&
|
|
77
|
-
boundingBox.width === boundingBoxOfFallbackFont.width;
|
|
78
|
-
// Ensure there are at least 4 unique characters, with just a few, there is more likely to be a false positive
|
|
79
|
-
if (sameAsFallbackFont &&
|
|
80
|
-
computedFallback !== computedFontFamily &&
|
|
81
|
-
new Set(text).size > 4) {
|
|
82
|
-
const err = [
|
|
83
|
-
`Called measureText() with "fontFamily": ${JSON.stringify(fontFamily)} but it looks like the font is not loaded at the time of calling.`,
|
|
84
|
-
`A measurement with the fallback font ${computedFallback} was taken and had the same dimensions, indicating that the browser used the fallback font.`,
|
|
85
|
-
'See https://remotion.dev/docs/layout-utils/best-practices for best practices.',
|
|
86
|
-
];
|
|
87
|
-
throw new Error(err.join('\n'));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const result = { height: boundingBox.height, width: boundingBox.width };
|
|
91
|
-
wordCache.set(key, result);
|
|
92
|
-
return result;
|
|
93
|
-
};
|
|
94
|
-
exports.measureText = measureText;
|