visualfries 0.1.9 → 0.1.10
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.
|
@@ -67,7 +67,8 @@ export class HtmlToCanvasHook {
|
|
|
67
67
|
}
|
|
68
68
|
const { width, height } = this.state;
|
|
69
69
|
if (!this.svgBase) {
|
|
70
|
-
const { base, content, end } = await svgGenerator.generateSVG(this.#htmlEl, this.#context.data.appearance.text, width, height, 'svg-' + this.#context.contextData.id, encodeURIComponent(this.state.getCharactersList().join(''))
|
|
70
|
+
const { base, content, end } = await svgGenerator.generateSVG(this.#htmlEl, this.#context.data.appearance.text, width, height, 'svg-' + this.#context.contextData.id, encodeURIComponent(this.state.getCharactersList().join('')) // current component text encoded
|
|
71
|
+
);
|
|
71
72
|
this.svgBase = base;
|
|
72
73
|
this.svgEnd = end;
|
|
73
74
|
this.svg = base + content + end;
|
|
@@ -262,7 +262,7 @@ export declare const SceneSettingsShape: z.ZodObject<{
|
|
|
262
262
|
radial: "radial";
|
|
263
263
|
}>;
|
|
264
264
|
colors: z.ZodArray<z.ZodString>;
|
|
265
|
-
stops: z.ZodOptional<z.ZodArray<z.
|
|
265
|
+
stops: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodCoercedNumber<unknown>>>>;
|
|
266
266
|
angle: z.ZodOptional<z.ZodPrefault<z.ZodNumber>>;
|
|
267
267
|
position: z.ZodOptional<z.ZodString>;
|
|
268
268
|
shape: z.ZodOptional<z.ZodEnum<{
|
|
@@ -10723,7 +10723,7 @@ export declare const SceneShape: z.ZodObject<{
|
|
|
10723
10723
|
radial: "radial";
|
|
10724
10724
|
}>;
|
|
10725
10725
|
colors: z.ZodArray<z.ZodString>;
|
|
10726
|
-
stops: z.ZodOptional<z.ZodArray<z.
|
|
10726
|
+
stops: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodCoercedNumber<unknown>>>>;
|
|
10727
10727
|
angle: z.ZodOptional<z.ZodPrefault<z.ZodNumber>>;
|
|
10728
10728
|
position: z.ZodOptional<z.ZodString>;
|
|
10729
10729
|
shape: z.ZodOptional<z.ZodEnum<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { isValidColor } from './utils.js';
|
|
2
|
+
import { coerceNumber, isValidColor } from './utils.js';
|
|
3
3
|
import { ComponentShape } from './components.js';
|
|
4
4
|
import { SubtitleCollectionShape, SubtitleWithCompactWordsShape } from './subtitles.js';
|
|
5
5
|
// Utility functions
|
|
@@ -69,7 +69,7 @@ export const SceneSettingsShape = z.object({
|
|
|
69
69
|
z.object({
|
|
70
70
|
type: z.enum(['linear', 'radial']),
|
|
71
71
|
colors: z.array(z.string().refine(isValidColor)).min(2),
|
|
72
|
-
stops: z.array(
|
|
72
|
+
stops: z.array(coerceNumber(0, 100)).optional(),
|
|
73
73
|
angle: z.number().min(0).max(360).prefault(180).optional(),
|
|
74
74
|
position: z.string().optional(),
|
|
75
75
|
shape: z.enum(['ellipse', 'circle']).optional()
|
|
@@ -16,11 +16,13 @@ export const GradientDefinitionShape = z.object({
|
|
|
16
16
|
/** Gradient type */
|
|
17
17
|
type: z.enum(['linear', 'radial']),
|
|
18
18
|
/** Array of color strings */
|
|
19
|
-
colors: z
|
|
19
|
+
colors: z
|
|
20
|
+
.array(z.string().refine(isValidColor, {
|
|
20
21
|
error: 'Invalid gradient color'
|
|
21
|
-
}))
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
}))
|
|
23
|
+
.min(2),
|
|
24
|
+
/** Optional array of stop positions (0-100) matching colors */
|
|
25
|
+
stops: z.array(coerceNumber(0, 100)).optional(),
|
|
24
26
|
/** Angle in degrees (for linear gradients) */
|
|
25
27
|
angle: coerceNumber(-360, 360).optional(),
|
|
26
28
|
/** Position description (for radial gradients) */
|
|
@@ -106,9 +108,12 @@ export const ShadowShape = z.object({
|
|
|
106
108
|
/** Optional preset name */
|
|
107
109
|
preset: z.string().optional(),
|
|
108
110
|
/** Shadow color */
|
|
109
|
-
color: z
|
|
111
|
+
color: z
|
|
112
|
+
.string()
|
|
113
|
+
.refine(isValidColor, {
|
|
110
114
|
error: 'Invalid shadow color format'
|
|
111
|
-
})
|
|
115
|
+
})
|
|
116
|
+
.optional(),
|
|
112
117
|
/** Shadow blur radius in pixels */
|
|
113
118
|
blur: coerceNonNegativeNumber().optional(),
|
|
114
119
|
/** Shadow size in pixels */
|
|
@@ -191,7 +196,7 @@ export const GradientShape = z.object({
|
|
|
191
196
|
/** Gradient stops */
|
|
192
197
|
stops: z.array(GradientStopShape).min(2),
|
|
193
198
|
/** Angle in degrees (for linear gradients) */
|
|
194
|
-
angle: z.number().min(
|
|
199
|
+
angle: z.number().min(-360).max(360).prefault(0).optional(),
|
|
195
200
|
/** Center position (for radial gradients) */
|
|
196
201
|
center: z
|
|
197
202
|
.object({
|
package/dist/utils/utils.js
CHANGED
|
@@ -19,6 +19,19 @@ export function changeIdDeep(obj) {
|
|
|
19
19
|
}
|
|
20
20
|
return obj;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Checks if a character is an emoji.
|
|
24
|
+
* Preserves all legitimate Unicode letters and numbers (Chinese, Japanese, Korean, Arabic, etc.).
|
|
25
|
+
*/
|
|
26
|
+
function isEmoji(char) {
|
|
27
|
+
// If it's a legitimate Unicode letter or number, it's NOT an emoji
|
|
28
|
+
// This includes Chinese, Japanese, Korean, Arabic, and all other writing systems
|
|
29
|
+
if (/\p{L}|\p{N}/u.test(char)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
// Use Unicode emoji property - automatically maintained by the Unicode standard
|
|
33
|
+
return /\p{Emoji}/u.test(char);
|
|
34
|
+
}
|
|
22
35
|
export const buildCharactersListFromComponentsAndSubtitles = function (layers, subtitlesCharactersList) {
|
|
23
36
|
const characters = ' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-,;:!$?\'"';
|
|
24
37
|
const charactestList = characters.split('');
|
|
@@ -31,8 +44,11 @@ export const buildCharactersListFromComponentsAndSubtitles = function (layers, s
|
|
|
31
44
|
const textList = text.split('');
|
|
32
45
|
const missingChars = textList.filter((char) => {
|
|
33
46
|
// Check if the character is not whitespace, not in the characters list,
|
|
34
|
-
//
|
|
35
|
-
return !/\s/.test(char) &&
|
|
47
|
+
// is a Unicode letter or number, and is NOT an emoji
|
|
48
|
+
return (!/\s/.test(char) &&
|
|
49
|
+
!characters.includes(char) &&
|
|
50
|
+
/\p{L}|\p{N}/u.test(char) &&
|
|
51
|
+
!isEmoji(char));
|
|
36
52
|
});
|
|
37
53
|
// Add both uppercase and lowercase variants of missing chars
|
|
38
54
|
const variantChars = missingChars.flatMap((char) => [
|
|
@@ -44,7 +60,7 @@ export const buildCharactersListFromComponentsAndSubtitles = function (layers, s
|
|
|
44
60
|
}
|
|
45
61
|
if (subtitlesCharactersList.length > 0) {
|
|
46
62
|
for (const char of subtitlesCharactersList) {
|
|
47
|
-
if (!characters.includes(char)) {
|
|
63
|
+
if (!characters.includes(char) && !isEmoji(char)) {
|
|
48
64
|
// Add both uppercase and lowercase variants of missing chars
|
|
49
65
|
charactestList.push(char.toLowerCase(), char.toUpperCase());
|
|
50
66
|
}
|