-
Notifications
You must be signed in to change notification settings - Fork 0
/
text.ts
59 lines (53 loc) · 2.04 KB
/
text.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import type { IConsumable, Primitive, TextObj } from './types.js';
import { isConsumable } from './consumables.js';
import { isObject } from './util.js';
/**
* Create a **TextNode** from text, and optionally reacts to a {@link IConsumable}, interpolating the defined variables in the text each time the state changes.
*
* If you provide a {@link IConsumable} as the second argument, the text will act as a template
* and can reference properties in the state: `$count`, `$someValue`.
*
* When the state properties changes, the text node will be automatically updated with the new text.
* Only the properties that are referenced in the template will be listened to.
*
* **NOTE** If you're not interpolating, and dont need to change the text, you can directly pass in a string ('string') instead of (`text('string')`).
*
* @see https://github.com/nombrekeff/cardboard-js/wiki/Managing-Text
*
* @example
* ```ts
* const st = state({ count: 0 });
*
* p(text('Raw text!'));
* p(text(`Count: $count`, st));
* ```
*/
export const text = <T extends Record<string, Primitive>, K extends TextObj>(textTemplate: string, obj?: IConsumable<T> | K): Node => {
const node = document.createTextNode(''),
interpolatePattern = /\B\$([0-9]+|[a-z][a-z0-9_$]*)/gi;
if (!obj) {
node.nodeValue = textTemplate;
return node;
}
const updateNode = (data: Record<string, Primitive>) => {
node.nodeValue = !data
? textTemplate
: textTemplate.replace(interpolatePattern, (m, g1) =>
(data[g1] ?? m).toString(),
);
};
if (isConsumable(obj)) {
(obj as IConsumable<Record<string, any>>).changed((val) => updateNode(val));
updateNode((obj as IConsumable).value);
}
else if (isObject(obj)) {
for (const key of Object.getOwnPropertyNames(obj)) {
// We're just interested in listening to the obj that are references in the text.
if (textTemplate.includes(`$${key}`) && isConsumable(obj[key])) {
obj[key].changed(() => updateNode(obj as any));
}
}
updateNode(obj as any);
}
return node;
};