@chayns-components/typewriter 5.0.0-beta.997 → 5.0.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/lib/cjs/components/typewriter/AnimatedTypewriterText.js +4 -3
- package/lib/cjs/components/typewriter/AnimatedTypewriterText.js.map +1 -1
- package/lib/cjs/components/typewriter/Typewriter.js +30 -15
- package/lib/cjs/components/typewriter/Typewriter.js.map +1 -1
- package/lib/cjs/components/typewriter/Typewriter.styles.js +13 -5
- package/lib/cjs/components/typewriter/Typewriter.styles.js.map +1 -1
- package/lib/cjs/components/typewriter/utils.js +88 -24
- package/lib/cjs/components/typewriter/utils.js.map +1 -1
- package/lib/esm/components/typewriter/AnimatedTypewriterText.js +9 -8
- package/lib/esm/components/typewriter/AnimatedTypewriterText.js.map +1 -1
- package/lib/esm/components/typewriter/Typewriter.js +51 -40
- package/lib/esm/components/typewriter/Typewriter.js.map +1 -1
- package/lib/esm/components/typewriter/Typewriter.styles.js +33 -37
- package/lib/esm/components/typewriter/Typewriter.styles.js.map +1 -1
- package/lib/esm/components/typewriter/utils.js +93 -30
- package/lib/esm/components/typewriter/utils.js.map +1 -1
- package/lib/types/components/typewriter/AnimatedTypewriterText.d.ts +4 -2
- package/lib/types/components/typewriter/Typewriter.d.ts +8 -3
- package/lib/types/components/typewriter/Typewriter.styles.d.ts +1 -0
- package/lib/types/components/typewriter/utils.d.ts +19 -6
- package/package.json +18 -17
|
@@ -1,51 +1,113 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* returned in the result. In addition, the function ensures that the closing tag of the Bold HTML
|
|
4
|
-
* element is also returned for text that is cut off in the middle of a Bold element, for example.
|
|
2
|
+
* Returns a substring of an HTML string while preserving HTML structure.
|
|
5
3
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Core rules:
|
|
5
|
+
* - Element nodes are re-serialized as tags (start/end) to keep structure.
|
|
6
|
+
* - Text nodes are always HTML-escaped on output. This prevents that previously
|
|
7
|
+
* escaped text (like "<div>") turns into real tags during the DOM round trip.
|
|
8
|
+
* - Attribute values are HTML-escaped on output.
|
|
9
|
+
* - Void elements are serialized without closing tags.
|
|
10
|
+
* - For TWIGNORE/TW-IGNORE elements, the innerHTML is passed through so that
|
|
11
|
+
* their content (including real HTML) remains untouched.
|
|
12
|
+
* - On early cutoff (once the length limit is reached), already opened tags are
|
|
13
|
+
* properly closed to keep the result valid HTML.
|
|
8
14
|
*
|
|
9
|
-
*
|
|
15
|
+
* Note on length counting:
|
|
16
|
+
* - The length is based on the decoded textContent length (as the DOM provides),
|
|
17
|
+
* not on byte length nor escaped entity length. This mirrors how the text is perceived.
|
|
18
|
+
*
|
|
19
|
+
* @param html The input HTML string; may contain a mix of real HTML and already escaped HTML.
|
|
20
|
+
* @param length The maximum number of text characters (based on textContent) to include.
|
|
21
|
+
* @returns A valid HTML string containing up to the specified number of text characters,
|
|
22
|
+
* preserving HTML tags and keeping escaped text escaped.
|
|
10
23
|
*/
|
|
11
24
|
export const getSubTextFromHTML = (html, length) => {
|
|
12
25
|
const div = document.createElement('div');
|
|
13
26
|
div.innerHTML = html;
|
|
14
27
|
let text = '';
|
|
15
28
|
let currLength = 0;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
|
|
30
|
+
// Escape text node content to ensure that decoded "<" and ">" do not become real tags.
|
|
31
|
+
const escapeText = value => value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
32
|
+
|
|
33
|
+
// Escape attribute values safely.
|
|
34
|
+
const escapeAttr = value => String(value).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
35
|
+
|
|
36
|
+
// HTML void elements (must not have closing tags)
|
|
37
|
+
const VOID_ELEMENTS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
|
38
|
+
|
|
39
|
+
// Traverses nodes and appends to "text".
|
|
40
|
+
// Returns false to signal "stop traversal" once the length limit is reached.
|
|
41
|
+
const traverse = node => {
|
|
42
|
+
// Text node
|
|
43
|
+
if (node.nodeType === 3 && typeof node.textContent === 'string') {
|
|
44
|
+
const nodeText = node.textContent;
|
|
45
|
+
const remaining = length - currLength;
|
|
46
|
+
if (remaining <= 0) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (nodeText.length <= remaining) {
|
|
50
|
+
// Always escape text before writing to output
|
|
51
|
+
text += escapeText(nodeText);
|
|
23
52
|
currLength += nodeText.length;
|
|
24
53
|
} else {
|
|
25
|
-
|
|
54
|
+
// Cut the text and stop traversal
|
|
55
|
+
text += escapeText(nodeText.substring(0, remaining));
|
|
56
|
+
currLength += remaining;
|
|
26
57
|
return false;
|
|
27
58
|
}
|
|
28
|
-
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Element node
|
|
63
|
+
if (node.nodeType === 1) {
|
|
64
|
+
const element = node;
|
|
65
|
+
|
|
66
|
+
// Pass-through for TWIGNORE/TW-IGNORE: keep their HTML as-is.
|
|
67
|
+
if (element.nodeName === 'TWIGNORE' || element.nodeName === 'TW-IGNORE') {
|
|
68
|
+
// element.innerHTML serializes children; escaped text stays escaped,
|
|
69
|
+
// real HTML stays HTML — exactly what we want here.
|
|
70
|
+
text += element.innerHTML;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
29
73
|
const nodeName = element.nodeName.toLowerCase();
|
|
30
|
-
let attributes = '';
|
|
31
74
|
|
|
32
|
-
//
|
|
75
|
+
// Serialize attributes safely
|
|
76
|
+
let attributes = '';
|
|
77
|
+
// @ts-expect-error: attributes is a NodeListOf<Attr>
|
|
33
78
|
// eslint-disable-next-line no-restricted-syntax
|
|
34
79
|
for (const attribute of element.attributes) {
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/restrict-template-expressions
|
|
36
|
-
attributes += ` ${attribute.name}="${attribute.value}"`;
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/restrict-template-expressions,@typescript-eslint/no-unsafe-argument
|
|
81
|
+
attributes += ` ${attribute.name}="${escapeAttr(attribute.value)}"`;
|
|
37
82
|
}
|
|
83
|
+
|
|
84
|
+
// Open tag
|
|
38
85
|
text += `<${nodeName}${attributes}>`;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
86
|
+
|
|
87
|
+
// Void elements: do not recurse children and do not emit a closing tag
|
|
88
|
+
const isVoid = VOID_ELEMENTS.has(nodeName);
|
|
89
|
+
if (!isVoid) {
|
|
90
|
+
// Recurse through children until limit is reached
|
|
91
|
+
for (let i = 0; i < element.childNodes.length; i++) {
|
|
92
|
+
const childNode = element.childNodes[i];
|
|
93
|
+
if (childNode && !traverse(childNode)) {
|
|
94
|
+
// On early stop: close this tag to keep valid HTML, then bubble stop.
|
|
95
|
+
text += `</${nodeName}>`;
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
43
98
|
}
|
|
99
|
+
|
|
100
|
+
// Close tag after all children
|
|
101
|
+
text += `</${nodeName}>`;
|
|
44
102
|
}
|
|
45
|
-
|
|
103
|
+
return true;
|
|
46
104
|
}
|
|
105
|
+
|
|
106
|
+
// Other node types (comments, etc.) are ignored for text length
|
|
47
107
|
return true;
|
|
48
108
|
};
|
|
109
|
+
|
|
110
|
+
// Traverse top-level children
|
|
49
111
|
for (let i = 0; i < div.childNodes.length; i++) {
|
|
50
112
|
const childNode = div.childNodes[i];
|
|
51
113
|
if (childNode && !traverse(childNode)) {
|
|
@@ -78,16 +140,17 @@ export const shuffleArray = array => {
|
|
|
78
140
|
const result = Array.from(array);
|
|
79
141
|
for (let i = result.length - 1; i > 0; i--) {
|
|
80
142
|
const j = Math.floor(Math.random() * (i + 1));
|
|
143
|
+
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
81
145
|
[result[i], result[j]] = [result[j], result[i]];
|
|
82
146
|
}
|
|
83
147
|
return result;
|
|
84
148
|
};
|
|
85
|
-
export const calculateAutoSpeed =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
} = _ref;
|
|
149
|
+
export const calculateAutoSpeed = ({
|
|
150
|
+
fullTextLength,
|
|
151
|
+
currentPosition,
|
|
152
|
+
baseSpeedFactor
|
|
153
|
+
}) => {
|
|
91
154
|
const MIN_SPEED = 1;
|
|
92
155
|
const MAX_SPEED = 10;
|
|
93
156
|
const remainingLength = fullTextLength - currentPosition;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":["getSubTextFromHTML","html","length","div","document","createElement","innerHTML","text","currLength","traverse","element","nodeName","nodeType","textContent","nodeText","substring","toLowerCase","attributes","attribute","name","value","i","childNodes","childNode","getCharactersCount","count","node","trim","Array","from","forEach","shuffleArray","array","result","j","Math","floor","random","calculateAutoSpeed","_ref","fullTextLength","currentPosition","baseSpeedFactor","MIN_SPEED","MAX_SPEED","remainingLength","speed","min","steps"],"sources":["../../../../src/components/typewriter/utils.ts"],"sourcesContent":["/**\n * This function extracts a part of the text from an HTML text. The HTML elements themselves are\n * returned in the result. In addition, the function ensures that the closing tag of the Bold HTML\n * element is also returned for text that is cut off in the middle of a Bold element, for example.\n *\n * @param html - The text from which a part should be taken\n * @param length - The length of the text to be extracted\n *\n * @return string - The text part with the specified length - additionally the HTML elements are added\n */\nexport const getSubTextFromHTML = (html: string, length: number): string => {\n const div = document.createElement('div');\n\n div.innerHTML = html;\n\n let text = '';\n let currLength = 0;\n\n const traverse = (element: Element): boolean => {\n if (element.nodeName === 'TWIGNORE') {\n text += element.innerHTML;\n } else if (element.nodeType === 3 && typeof element.textContent === 'string') {\n const nodeText = element.textContent;\n\n if (currLength + nodeText.length <= length) {\n text += nodeText;\n currLength += nodeText.length;\n } else {\n text += nodeText.substring(0, length - currLength);\n\n return false;\n }\n } else if (element.nodeType === 1) {\n const nodeName = element.nodeName.toLowerCase();\n\n let attributes = '';\n\n // @ts-expect-error: Type is correct here\n // eslint-disable-next-line no-restricted-syntax\n for (const attribute of element.attributes) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/restrict-template-expressions\n attributes += ` ${attribute.name}=\"${attribute.value}\"`;\n }\n\n text += `<${nodeName}${attributes}>`;\n\n for (let i = 0; i < element.childNodes.length; i++) {\n const childNode = element.childNodes[i];\n\n if (childNode && !traverse(childNode as Element)) {\n return false;\n }\n }\n\n text += `</${nodeName}>`;\n }\n\n return true;\n };\n\n for (let i = 0; i < div.childNodes.length; i++) {\n const childNode = div.childNodes[i];\n\n if (childNode && !traverse(childNode as Element)) {\n return text;\n }\n }\n\n return text;\n};\n\nexport const getCharactersCount = (html: string): number => {\n const div = document.createElement('div');\n\n div.innerHTML = html;\n\n let count = 0;\n\n const traverse = (node: Node): void => {\n if (node.nodeName === 'TWIGNORE') {\n count += 1;\n } else if (node.nodeType === 3 && typeof node.textContent === 'string') {\n count += node.textContent.trim().length;\n } else if (node.nodeType === 1) {\n if (node.nodeName === 'CODE' && node.textContent !== null) {\n count += node.textContent.length;\n\n return;\n }\n\n Array.from(node.childNodes).forEach(traverse);\n }\n };\n\n Array.from(div.childNodes).forEach(traverse);\n\n return count;\n};\n\nexport const shuffleArray = <T>(array: T[]): T[] => {\n const result = Array.from(array);\n\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n\n [result[i], result[j]] = [result[j]!, result[i]!];\n }\n\n return result;\n};\n\ninterface CalculateAutoSpeedProps {\n fullTextLength: number;\n currentPosition: number;\n baseSpeedFactor: number;\n}\n\nexport const calculateAutoSpeed = ({\n fullTextLength,\n currentPosition,\n baseSpeedFactor,\n}: CalculateAutoSpeedProps): { speed: number; steps: number } => {\n const MIN_SPEED = 1;\n const MAX_SPEED = 10;\n\n const remainingLength = fullTextLength - currentPosition;\n\n // Calculate the speed with the remaining text length and the baseSpeedFactor\n const speed = Math.min(baseSpeedFactor / remainingLength, MAX_SPEED);\n\n if (speed < MIN_SPEED) {\n return { speed: 1, steps: 2 };\n }\n\n return { speed, steps: 1 };\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"utils.js","names":["getSubTextFromHTML","html","length","div","document","createElement","innerHTML","text","currLength","escapeText","value","replace","escapeAttr","String","VOID_ELEMENTS","Set","traverse","node","nodeType","textContent","nodeText","remaining","substring","element","nodeName","toLowerCase","attributes","attribute","name","isVoid","has","i","childNodes","childNode","getCharactersCount","count","trim","Array","from","forEach","shuffleArray","array","result","j","Math","floor","random","calculateAutoSpeed","fullTextLength","currentPosition","baseSpeedFactor","MIN_SPEED","MAX_SPEED","remainingLength","speed","min","steps"],"sources":["../../../../src/components/typewriter/utils.ts"],"sourcesContent":["/**\n * Returns a substring of an HTML string while preserving HTML structure.\n *\n * Core rules:\n * - Element nodes are re-serialized as tags (start/end) to keep structure.\n * - Text nodes are always HTML-escaped on output. This prevents that previously\n * escaped text (like \"<div>\") turns into real tags during the DOM round trip.\n * - Attribute values are HTML-escaped on output.\n * - Void elements are serialized without closing tags.\n * - For TWIGNORE/TW-IGNORE elements, the innerHTML is passed through so that\n * their content (including real HTML) remains untouched.\n * - On early cutoff (once the length limit is reached), already opened tags are\n * properly closed to keep the result valid HTML.\n *\n * Note on length counting:\n * - The length is based on the decoded textContent length (as the DOM provides),\n * not on byte length nor escaped entity length. This mirrors how the text is perceived.\n *\n * @param html The input HTML string; may contain a mix of real HTML and already escaped HTML.\n * @param length The maximum number of text characters (based on textContent) to include.\n * @returns A valid HTML string containing up to the specified number of text characters,\n * preserving HTML tags and keeping escaped text escaped.\n */\nexport const getSubTextFromHTML = (html: string, length: number): string => {\n const div = document.createElement('div');\n\n div.innerHTML = html;\n\n let text = '';\n let currLength = 0;\n\n // Escape text node content to ensure that decoded \"<\" and \">\" do not become real tags.\n const escapeText = (value: string): string =>\n value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n\n // Escape attribute values safely.\n const escapeAttr = (value: string): string =>\n String(value)\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n\n // HTML void elements (must not have closing tags)\n const VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n ]);\n\n // Traverses nodes and appends to \"text\".\n // Returns false to signal \"stop traversal\" once the length limit is reached.\n const traverse = (node: Node): boolean => {\n // Text node\n if (node.nodeType === 3 && typeof node.textContent === 'string') {\n const nodeText = node.textContent;\n const remaining = length - currLength;\n\n if (remaining <= 0) {\n return false;\n }\n\n if (nodeText.length <= remaining) {\n // Always escape text before writing to output\n text += escapeText(nodeText);\n currLength += nodeText.length;\n } else {\n // Cut the text and stop traversal\n text += escapeText(nodeText.substring(0, remaining));\n currLength += remaining;\n return false;\n }\n\n return true;\n }\n\n // Element node\n if (node.nodeType === 1) {\n const element = node as Element;\n\n // Pass-through for TWIGNORE/TW-IGNORE: keep their HTML as-is.\n if (element.nodeName === 'TWIGNORE' || element.nodeName === 'TW-IGNORE') {\n // element.innerHTML serializes children; escaped text stays escaped,\n // real HTML stays HTML — exactly what we want here.\n text += element.innerHTML;\n return true;\n }\n\n const nodeName = element.nodeName.toLowerCase();\n\n // Serialize attributes safely\n let attributes = '';\n // @ts-expect-error: attributes is a NodeListOf<Attr>\n // eslint-disable-next-line no-restricted-syntax\n for (const attribute of element.attributes) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/restrict-template-expressions,@typescript-eslint/no-unsafe-argument\n attributes += ` ${attribute.name}=\"${escapeAttr(attribute.value)}\"`;\n }\n\n // Open tag\n text += `<${nodeName}${attributes}>`;\n\n // Void elements: do not recurse children and do not emit a closing tag\n const isVoid = VOID_ELEMENTS.has(nodeName);\n if (!isVoid) {\n // Recurse through children until limit is reached\n for (let i = 0; i < element.childNodes.length; i++) {\n const childNode = element.childNodes[i];\n if (childNode && !traverse(childNode)) {\n // On early stop: close this tag to keep valid HTML, then bubble stop.\n text += `</${nodeName}>`;\n return false;\n }\n }\n\n // Close tag after all children\n text += `</${nodeName}>`;\n }\n\n return true;\n }\n\n // Other node types (comments, etc.) are ignored for text length\n return true;\n };\n\n // Traverse top-level children\n for (let i = 0; i < div.childNodes.length; i++) {\n const childNode = div.childNodes[i];\n if (childNode && !traverse(childNode)) {\n return text;\n }\n }\n\n return text;\n};\n\nexport const getCharactersCount = (html: string): number => {\n const div = document.createElement('div');\n\n div.innerHTML = html;\n\n let count = 0;\n\n const traverse = (node: Node): void => {\n if (node.nodeName === 'TWIGNORE') {\n count += 1;\n } else if (node.nodeType === 3 && typeof node.textContent === 'string') {\n count += node.textContent.trim().length;\n } else if (node.nodeType === 1) {\n if (node.nodeName === 'CODE' && node.textContent !== null) {\n count += node.textContent.length;\n\n return;\n }\n\n Array.from(node.childNodes).forEach(traverse);\n }\n };\n\n Array.from(div.childNodes).forEach(traverse);\n\n return count;\n};\n\nexport const shuffleArray = <T>(array: T[]): T[] => {\n const result = Array.from(array);\n\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n [result[i], result[j]] = [result[j]!, result[i]!];\n }\n\n return result;\n};\n\ninterface CalculateAutoSpeedProps {\n fullTextLength: number;\n currentPosition: number;\n baseSpeedFactor: number;\n}\n\nexport const calculateAutoSpeed = ({\n fullTextLength,\n currentPosition,\n baseSpeedFactor,\n}: CalculateAutoSpeedProps): { speed: number; steps: number } => {\n const MIN_SPEED = 1;\n const MAX_SPEED = 10;\n\n const remainingLength = fullTextLength - currentPosition;\n\n // Calculate the speed with the remaining text length and the baseSpeedFactor\n const speed = Math.min(baseSpeedFactor / remainingLength, MAX_SPEED);\n\n if (speed < MIN_SPEED) {\n return { speed: 1, steps: 2 };\n }\n\n return { speed, steps: 1 };\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { CSSPropertiesWithVars } from 'styled-components/dist/types';
|
|
2
3
|
type AnimatedTypewriterTextProps = {
|
|
3
4
|
shouldHideCursor: boolean;
|
|
4
5
|
shownText: string;
|
|
5
|
-
textStyle?:
|
|
6
|
+
textStyle?: CSSPropertiesWithVars;
|
|
7
|
+
shouldRemainSingleLine: boolean;
|
|
6
8
|
};
|
|
7
9
|
declare const AnimatedTypewriterText: FC<AnimatedTypewriterTextProps>;
|
|
8
10
|
export default AnimatedTypewriterText;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, ReactElement } from 'react';
|
|
2
|
+
import { CSSPropertiesWithVars } from 'styled-components/dist/types';
|
|
2
3
|
import { CursorType } from '../../types/cursor';
|
|
3
4
|
import { TypewriterDelay, TypewriterSpeed } from '../../types/speed';
|
|
4
5
|
export type TypewriterProps = {
|
|
5
6
|
/**
|
|
6
|
-
* The
|
|
7
|
+
* The number of characters that will be animated per animation cycle.
|
|
7
8
|
*/
|
|
8
9
|
animationSteps?: number;
|
|
9
10
|
/**
|
|
@@ -70,6 +71,10 @@ export type TypewriterProps = {
|
|
|
70
71
|
* Specifies whether the cursor should be hidden
|
|
71
72
|
*/
|
|
72
73
|
shouldHideCursor?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Whether the content should remain a single line.
|
|
76
|
+
*/
|
|
77
|
+
shouldRemainSingleLine?: boolean;
|
|
73
78
|
/**
|
|
74
79
|
* Specifies whether the children should be sorted randomly if there are multiple texts.
|
|
75
80
|
* This makes the typewriter start with a different text each time and also changes them
|
|
@@ -105,7 +110,7 @@ export type TypewriterProps = {
|
|
|
105
110
|
/**
|
|
106
111
|
* The style of the typewriter text element
|
|
107
112
|
*/
|
|
108
|
-
textStyle?:
|
|
113
|
+
textStyle?: CSSPropertiesWithVars;
|
|
109
114
|
};
|
|
110
115
|
declare const Typewriter: FC<TypewriterProps>;
|
|
111
116
|
export default Typewriter;
|
|
@@ -14,6 +14,7 @@ type StyledTypewriterPseudoTextProps = WithTheme<{
|
|
|
14
14
|
export declare const StyledTypewriterPseudoText: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, StyledTypewriterPseudoTextProps>> & string;
|
|
15
15
|
type StyledTypewriterTextProps = WithTheme<{
|
|
16
16
|
$isAnimatingText?: boolean;
|
|
17
|
+
$shouldRemainSingleLine: boolean;
|
|
17
18
|
}>;
|
|
18
19
|
export declare const StyledTypewriterText: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, StyledTypewriterTextProps>> & string;
|
|
19
20
|
export {};
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* returned in the result. In addition, the function ensures that the closing tag of the Bold HTML
|
|
4
|
-
* element is also returned for text that is cut off in the middle of a Bold element, for example.
|
|
2
|
+
* Returns a substring of an HTML string while preserving HTML structure.
|
|
5
3
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Core rules:
|
|
5
|
+
* - Element nodes are re-serialized as tags (start/end) to keep structure.
|
|
6
|
+
* - Text nodes are always HTML-escaped on output. This prevents that previously
|
|
7
|
+
* escaped text (like "<div>") turns into real tags during the DOM round trip.
|
|
8
|
+
* - Attribute values are HTML-escaped on output.
|
|
9
|
+
* - Void elements are serialized without closing tags.
|
|
10
|
+
* - For TWIGNORE/TW-IGNORE elements, the innerHTML is passed through so that
|
|
11
|
+
* their content (including real HTML) remains untouched.
|
|
12
|
+
* - On early cutoff (once the length limit is reached), already opened tags are
|
|
13
|
+
* properly closed to keep the result valid HTML.
|
|
8
14
|
*
|
|
9
|
-
*
|
|
15
|
+
* Note on length counting:
|
|
16
|
+
* - The length is based on the decoded textContent length (as the DOM provides),
|
|
17
|
+
* not on byte length nor escaped entity length. This mirrors how the text is perceived.
|
|
18
|
+
*
|
|
19
|
+
* @param html The input HTML string; may contain a mix of real HTML and already escaped HTML.
|
|
20
|
+
* @param length The maximum number of text characters (based on textContent) to include.
|
|
21
|
+
* @returns A valid HTML string containing up to the specified number of text characters,
|
|
22
|
+
* preserving HTML tags and keeping escaped text escaped.
|
|
10
23
|
*/
|
|
11
24
|
export declare const getSubTextFromHTML: (html: string, length: number) => string;
|
|
12
25
|
export declare const getCharactersCount: (html: string) => number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chayns-components/typewriter",
|
|
3
|
-
"version": "5.0.0
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "A set of beautiful React components for developing your own applications with chayns.",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"browserslist": [
|
|
@@ -23,8 +23,9 @@
|
|
|
23
23
|
"exports": {
|
|
24
24
|
".": {
|
|
25
25
|
"types": "./lib/types/index.d.ts",
|
|
26
|
+
"node": "./lib/cjs/index.js",
|
|
26
27
|
"require": "./lib/cjs/index.js",
|
|
27
|
-
"
|
|
28
|
+
"default": "./lib/esm/index.js"
|
|
28
29
|
}
|
|
29
30
|
},
|
|
30
31
|
"directories": {
|
|
@@ -51,29 +52,29 @@
|
|
|
51
52
|
"url": "https://github.com/TobitSoftware/chayns-components/issues"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
|
-
"@babel/cli": "^7.
|
|
55
|
-
"@babel/core": "^7.
|
|
56
|
-
"@babel/preset-env": "^7.
|
|
57
|
-
"@babel/preset-react": "^7.
|
|
58
|
-
"@babel/preset-typescript": "^7.
|
|
59
|
-
"@types/react": "^18.3.
|
|
60
|
-
"@types/react-dom": "^18.3.
|
|
61
|
-
"@types/styled-components": "^5.1.
|
|
55
|
+
"@babel/cli": "^7.28.6",
|
|
56
|
+
"@babel/core": "^7.29.0",
|
|
57
|
+
"@babel/preset-env": "^7.29.0",
|
|
58
|
+
"@babel/preset-react": "^7.28.5",
|
|
59
|
+
"@babel/preset-typescript": "^7.28.5",
|
|
60
|
+
"@types/react": "^18.3.28",
|
|
61
|
+
"@types/react-dom": "^18.3.7",
|
|
62
|
+
"@types/styled-components": "^5.1.36",
|
|
62
63
|
"@types/uuid": "^10.0.0",
|
|
63
64
|
"babel-loader": "^9.2.1",
|
|
64
65
|
"cross-env": "^7.0.3",
|
|
65
|
-
"lerna": "^8.
|
|
66
|
+
"lerna": "^8.2.4",
|
|
66
67
|
"react": "^18.3.1",
|
|
67
68
|
"react-dom": "^18.3.1",
|
|
68
|
-
"styled-components": "^6.
|
|
69
|
-
"typescript": "^5.
|
|
69
|
+
"styled-components": "^6.3.9",
|
|
70
|
+
"typescript": "^5.9.3"
|
|
70
71
|
},
|
|
71
72
|
"dependencies": {
|
|
72
|
-
"@chayns-components/core": "^5.0.0
|
|
73
|
+
"@chayns-components/core": "^5.0.0"
|
|
73
74
|
},
|
|
74
75
|
"peerDependencies": {
|
|
75
|
-
"chayns-api": ">=2.
|
|
76
|
-
"
|
|
76
|
+
"chayns-api": ">=2.2.0",
|
|
77
|
+
"motion": ">=12.4.1",
|
|
77
78
|
"react": ">=18.0.0",
|
|
78
79
|
"react-dom": ">=18.0.0",
|
|
79
80
|
"styled-components": ">=5.3.11"
|
|
@@ -81,5 +82,5 @@
|
|
|
81
82
|
"publishConfig": {
|
|
82
83
|
"access": "public"
|
|
83
84
|
},
|
|
84
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "3d554c67b058b3b25e2666a34ee543fea2cad6e2"
|
|
85
86
|
}
|