@momentum-design/components 0.101.4 → 0.102.1
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/dist/browser/index.js +431 -399
- package/dist/browser/index.js.map +4 -4
- package/dist/components/listitem/listitem.component.d.ts +7 -1
- package/dist/components/listitem/listitem.component.js +22 -14
- package/dist/components/listitem/listitem.styles.js +10 -5
- package/dist/components/typewriter/index.d.ts +7 -0
- package/dist/components/typewriter/index.js +4 -0
- package/dist/components/typewriter/typewriter.component.d.ts +192 -0
- package/dist/components/typewriter/typewriter.component.js +454 -0
- package/dist/components/typewriter/typewriter.constants.d.ts +20 -0
- package/dist/components/typewriter/typewriter.constants.js +22 -0
- package/dist/components/typewriter/typewriter.styles.d.ts +2 -0
- package/dist/components/typewriter/typewriter.styles.js +19 -0
- package/dist/components/typewriter/typewriter.types.d.ts +21 -0
- package/dist/components/typewriter/typewriter.types.js +1 -0
- package/dist/custom-elements.json +1543 -987
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/react/index.d.ts +3 -2
- package/dist/react/index.js +3 -2
- package/dist/react/listitem/index.d.ts +7 -1
- package/dist/react/listitem/index.js +7 -1
- package/dist/react/typewriter/index.d.ts +51 -0
- package/dist/react/typewriter/index.js +59 -0
- package/package.json +1 -1
@@ -0,0 +1,454 @@
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
9
|
+
};
|
10
|
+
import { html } from 'lit';
|
11
|
+
import { property, state } from 'lit/decorators.js';
|
12
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
13
|
+
import { Component } from '../../models';
|
14
|
+
import '../text';
|
15
|
+
import styles from './typewriter.styles';
|
16
|
+
import { DEFAULTS, SPEED } from './typewriter.constants';
|
17
|
+
/**
|
18
|
+
* Typewriter component that creates a typewriter effect on text content.
|
19
|
+
* It uses the Text component internally, adding a progressive typing effect.
|
20
|
+
*
|
21
|
+
* The `type` attribute allows changing the text style (passed to the internal Text component).
|
22
|
+
* The `tagname` attribute allows changing the tag name of the text element (passed to the internal Text component).
|
23
|
+
* The default tag name is `p`.
|
24
|
+
*
|
25
|
+
* The `speed` attribute controls typing speed in milliseconds per character:
|
26
|
+
* - 'very-slow' = 240ms per character
|
27
|
+
* - 'slow' = 120ms per character
|
28
|
+
* - 'normal' = 60ms per character (default)
|
29
|
+
* - 'fast' = 20ms per character
|
30
|
+
* - 'very-fast' = 1ms per character
|
31
|
+
* - Or any numeric string representing milliseconds
|
32
|
+
*
|
33
|
+
* Advanced features:
|
34
|
+
* - Dynamic speed adjustment during typing
|
35
|
+
* - Chunked text addition via addTextChunk() method
|
36
|
+
* - Instant text addition via addInstantTextChunk() method or instant parameter
|
37
|
+
* - Mixed instant and animated chunks in queue
|
38
|
+
* - Continues typing in background tabs
|
39
|
+
* - Performance optimized for large text
|
40
|
+
* - maxQueueSize to limit memory usage from excessive queuing
|
41
|
+
* - event handling for typing completion and content changes
|
42
|
+
*
|
43
|
+
* The component includes accessibility features:
|
44
|
+
* - Screen readers announce the complete text, not character by character
|
45
|
+
* - Uses aria-live="polite" for dynamic content updates
|
46
|
+
* - Sets aria-busy during typing animation
|
47
|
+
*
|
48
|
+
* @dependency mdc-text
|
49
|
+
*
|
50
|
+
* @tagname mdc-typewriter
|
51
|
+
* @slot - Default slot for text content
|
52
|
+
*
|
53
|
+
* @csspart container - Container for the text element
|
54
|
+
* @csspart text - The text element (forwarded to mdc-text)
|
55
|
+
*
|
56
|
+
* @event typing-complete - (React: onTypingComplete) Fired when the typewriter finishes typing all content.
|
57
|
+
* Detail: \{ finalContent: string \}
|
58
|
+
* @event change - (React: onChange) Fired when the content of the typewriter changes.
|
59
|
+
* Detail: \{ content: string, isTyping: boolean \}
|
60
|
+
*/
|
61
|
+
class Typewriter extends Component {
|
62
|
+
constructor() {
|
63
|
+
super(...arguments);
|
64
|
+
/**
|
65
|
+
* Specifies the text style to be applied to the internal text component.
|
66
|
+
* Uses the same types as the Text component.
|
67
|
+
* @default body-large-regular
|
68
|
+
*/
|
69
|
+
this.type = DEFAULTS.TYPE;
|
70
|
+
/**
|
71
|
+
* Specifies the HTML tag name for the text element. The default tag name is `p`.
|
72
|
+
* This attribute is optional. When set, it changes the tag name of the internal text element.
|
73
|
+
*
|
74
|
+
* Acceptable values include all valid tag names from the Text component.
|
75
|
+
*/
|
76
|
+
this.tagname = DEFAULTS.TEXT_ELEMENT_TAGNAME;
|
77
|
+
/**
|
78
|
+
* Speed of the typewriter effect in milliseconds per character.
|
79
|
+
* Can be a string preset or a numeric string in milliseconds.
|
80
|
+
* - 'very-slow' = 240ms per character
|
81
|
+
* - 'slow' = 120ms per character
|
82
|
+
* - 'normal' = 60ms per character (default)
|
83
|
+
* - 'fast' = 20ms per character
|
84
|
+
* - 'very-fast' = 1ms per character
|
85
|
+
* - Or any numeric string representing milliseconds (e.g., '100')
|
86
|
+
* @default 'normal' (60ms per character)
|
87
|
+
*/
|
88
|
+
this.speed = DEFAULTS.SPEED;
|
89
|
+
/**
|
90
|
+
* Maximum number of text chunks that can be queued before oldest chunks are dropped.
|
91
|
+
* Set to prevent memory accumulation from excessive queuing.
|
92
|
+
* @default Number.MAX_SAFE_INTEGER (effectively unlimited)
|
93
|
+
*/
|
94
|
+
this.maxQueueSize = Number.MAX_SAFE_INTEGER;
|
95
|
+
/**
|
96
|
+
* Internal state for the displayed text
|
97
|
+
* @internal
|
98
|
+
*/
|
99
|
+
this.displayedText = '';
|
100
|
+
/**
|
101
|
+
* Internal state to track the original text
|
102
|
+
* @internal
|
103
|
+
*/
|
104
|
+
this.originalText = '';
|
105
|
+
/**
|
106
|
+
* Character index for typing animation
|
107
|
+
* @internal
|
108
|
+
*/
|
109
|
+
this.currentIndex = 0;
|
110
|
+
/**
|
111
|
+
* Typing animation timeout id
|
112
|
+
* @internal
|
113
|
+
*/
|
114
|
+
this.typingTimeout = null;
|
115
|
+
/**
|
116
|
+
* Set of pending setTimeout IDs for cleanup
|
117
|
+
* @internal
|
118
|
+
*/
|
119
|
+
this.pendingTimeouts = new Set();
|
120
|
+
/**
|
121
|
+
* Queue of text chunks to be added (limited to prevent memory issues)
|
122
|
+
* @internal
|
123
|
+
*/
|
124
|
+
this.textChunkQueue = [];
|
125
|
+
/**
|
126
|
+
* Stores previous text content for comparison
|
127
|
+
* @internal
|
128
|
+
*/
|
129
|
+
this.previousTextContent = '';
|
130
|
+
/**
|
131
|
+
* Whether the typing animation has completed
|
132
|
+
* @internal
|
133
|
+
*/
|
134
|
+
this.typingComplete = true;
|
135
|
+
}
|
136
|
+
/**
|
137
|
+
* Called when the element is first connected to the document
|
138
|
+
*/
|
139
|
+
connectedCallback() {
|
140
|
+
super.connectedCallback();
|
141
|
+
this.createTimeout(() => {
|
142
|
+
this.captureAndProcessContent();
|
143
|
+
}, 0);
|
144
|
+
}
|
145
|
+
/**
|
146
|
+
* Called when the element is disconnected from the document
|
147
|
+
*/
|
148
|
+
disconnectedCallback() {
|
149
|
+
this.clearTypingAnimation();
|
150
|
+
this.clearAllTimeouts();
|
151
|
+
super.disconnectedCallback();
|
152
|
+
}
|
153
|
+
/**
|
154
|
+
* Helper to create tracked setTimeout that will be cleaned up on disconnect
|
155
|
+
*/
|
156
|
+
createTimeout(callback, delay) {
|
157
|
+
const id = window.setTimeout(() => {
|
158
|
+
this.pendingTimeouts.delete(id);
|
159
|
+
callback();
|
160
|
+
}, delay);
|
161
|
+
this.pendingTimeouts.add(id);
|
162
|
+
return id;
|
163
|
+
}
|
164
|
+
/**
|
165
|
+
* Clear all pending timeouts
|
166
|
+
*/
|
167
|
+
clearAllTimeouts() {
|
168
|
+
this.pendingTimeouts.forEach(id => clearTimeout(id));
|
169
|
+
this.pendingTimeouts.clear();
|
170
|
+
}
|
171
|
+
/**
|
172
|
+
* Clears the text chunk queue and stops processing
|
173
|
+
* Useful for resetting the component state
|
174
|
+
*/
|
175
|
+
clearQueue() {
|
176
|
+
this.textChunkQueue.length = 0;
|
177
|
+
}
|
178
|
+
/**
|
179
|
+
* Adds a chunk of text to be typed out, optionally with a different speed
|
180
|
+
* @param text - The text to add
|
181
|
+
* @param speed - Optional speed override for this chunk
|
182
|
+
* @param instant - If true, text appears instantly without animation
|
183
|
+
*/
|
184
|
+
addTextChunk(text, speed, instant) {
|
185
|
+
if (!text)
|
186
|
+
return;
|
187
|
+
if (this.maxQueueSize < Number.MAX_SAFE_INTEGER && this.textChunkQueue.length >= this.maxQueueSize) {
|
188
|
+
this.textChunkQueue.splice(0, this.textChunkQueue.length - this.maxQueueSize + 1);
|
189
|
+
}
|
190
|
+
this.textChunkQueue.push({ text, speed, instant });
|
191
|
+
this.processChunkQueue();
|
192
|
+
}
|
193
|
+
/**
|
194
|
+
* Adds a chunk of text instantly without typing animation
|
195
|
+
* @param text - The text to add instantly
|
196
|
+
*/
|
197
|
+
addInstantTextChunk(text) {
|
198
|
+
this.addTextChunk(text, undefined, true);
|
199
|
+
}
|
200
|
+
/**
|
201
|
+
* Processes all chunks in the queue
|
202
|
+
*/
|
203
|
+
processChunkQueue() {
|
204
|
+
// Process the next chunk - the callback chain will handle remaining chunks
|
205
|
+
if (this.textChunkQueue.length > 0) {
|
206
|
+
this.processNextChunk();
|
207
|
+
}
|
208
|
+
}
|
209
|
+
/**
|
210
|
+
* Processes the next chunk in the queue
|
211
|
+
*/
|
212
|
+
processNextChunk() {
|
213
|
+
if (this.textChunkQueue.length === 0) {
|
214
|
+
return;
|
215
|
+
}
|
216
|
+
const chunk = this.textChunkQueue.shift();
|
217
|
+
const originalSpeed = this.speed;
|
218
|
+
if (chunk.speed !== undefined) {
|
219
|
+
this.speed = chunk.speed;
|
220
|
+
}
|
221
|
+
this.originalText += chunk.text;
|
222
|
+
this.typingComplete = false;
|
223
|
+
if (chunk.instant) {
|
224
|
+
this.displayedText = this.originalText;
|
225
|
+
this.currentIndex = this.originalText.length;
|
226
|
+
this.typingComplete = true;
|
227
|
+
this.requestUpdate();
|
228
|
+
if (chunk.speed !== undefined) {
|
229
|
+
this.speed = originalSpeed;
|
230
|
+
}
|
231
|
+
if (this.textChunkQueue.length > 0) {
|
232
|
+
this.createTimeout(() => {
|
233
|
+
this.processNextChunk();
|
234
|
+
}, 0);
|
235
|
+
}
|
236
|
+
else {
|
237
|
+
this.dispatchEvent(new CustomEvent(DEFAULTS.CUSTOM_EVENT.TYPING_COMPLETE, {
|
238
|
+
bubbles: true,
|
239
|
+
composed: true,
|
240
|
+
}));
|
241
|
+
}
|
242
|
+
}
|
243
|
+
else {
|
244
|
+
this.startTypingAnimation(() => {
|
245
|
+
if (chunk.speed !== undefined) {
|
246
|
+
this.speed = originalSpeed;
|
247
|
+
}
|
248
|
+
// Continue processing remaining chunks or fire completion event
|
249
|
+
if (this.textChunkQueue.length > 0) {
|
250
|
+
// Use tracked timeout to avoid deep recursion and ensure clean state
|
251
|
+
this.createTimeout(() => {
|
252
|
+
this.processNextChunk();
|
253
|
+
}, 0);
|
254
|
+
}
|
255
|
+
else {
|
256
|
+
this.dispatchEvent(new CustomEvent(DEFAULTS.CUSTOM_EVENT.TYPING_COMPLETE, {
|
257
|
+
bubbles: true,
|
258
|
+
composed: true,
|
259
|
+
}));
|
260
|
+
}
|
261
|
+
});
|
262
|
+
}
|
263
|
+
}
|
264
|
+
/**
|
265
|
+
* Gets the typing delay in milliseconds per character
|
266
|
+
*/
|
267
|
+
getTypingDelayMs() {
|
268
|
+
const speedValue = this.speed;
|
269
|
+
// Handle preset string values
|
270
|
+
switch (speedValue) {
|
271
|
+
case 'slow':
|
272
|
+
return SPEED.SLOW;
|
273
|
+
case 'fast':
|
274
|
+
return SPEED.FAST;
|
275
|
+
case 'very-slow':
|
276
|
+
return SPEED.VERY_SLOW;
|
277
|
+
case 'very-fast':
|
278
|
+
return SPEED.VERY_FAST;
|
279
|
+
case 'normal':
|
280
|
+
return SPEED.NORMAL;
|
281
|
+
default: {
|
282
|
+
// Try to parse as a number string, fallback to normal speed
|
283
|
+
const numericSpeed = parseInt(speedValue, 10);
|
284
|
+
return !Number.isNaN(numericSpeed) ? Math.max(10, numericSpeed) : SPEED.NORMAL;
|
285
|
+
}
|
286
|
+
}
|
287
|
+
}
|
288
|
+
/**
|
289
|
+
* Responds to property changes
|
290
|
+
*/
|
291
|
+
updated(changedProperties) {
|
292
|
+
super.updated(changedProperties);
|
293
|
+
// Only restart animation if speed changed during active typing
|
294
|
+
// and we're not in the middle of chunk processing
|
295
|
+
if (changedProperties.has('speed') && !this.typingComplete && this.textChunkQueue.length === 0) {
|
296
|
+
this.startTypingAnimation();
|
297
|
+
}
|
298
|
+
}
|
299
|
+
/**
|
300
|
+
* Captures slot content and starts typewriter animation
|
301
|
+
*/
|
302
|
+
captureAndProcessContent() {
|
303
|
+
var _a;
|
304
|
+
const slot = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('slot');
|
305
|
+
if (!slot)
|
306
|
+
return;
|
307
|
+
const content = slot
|
308
|
+
.assignedNodes()
|
309
|
+
.filter(node => node.nodeType === Node.TEXT_NODE || node.nodeType === Node.ELEMENT_NODE)
|
310
|
+
.map(node => node.textContent || '')
|
311
|
+
.join('');
|
312
|
+
// If no change in content, don't restart animation
|
313
|
+
if (content === this.previousTextContent)
|
314
|
+
return;
|
315
|
+
// If content is completely different, reset animation
|
316
|
+
if (this.displayedText === '' || !content.includes(this.displayedText)) {
|
317
|
+
this.originalText = content;
|
318
|
+
this.displayedText = '';
|
319
|
+
this.currentIndex = 0;
|
320
|
+
this.typingComplete = false;
|
321
|
+
}
|
322
|
+
else {
|
323
|
+
// For additional content, only type the new part
|
324
|
+
this.originalText = content;
|
325
|
+
this.typingComplete = false;
|
326
|
+
}
|
327
|
+
this.dispatchEvent(new CustomEvent('change', {
|
328
|
+
bubbles: true,
|
329
|
+
composed: true,
|
330
|
+
detail: {
|
331
|
+
content: this.originalText,
|
332
|
+
isTyping: !this.typingComplete,
|
333
|
+
},
|
334
|
+
}));
|
335
|
+
this.previousTextContent = content;
|
336
|
+
this.startTypingAnimation();
|
337
|
+
}
|
338
|
+
/**
|
339
|
+
* Starts the typewriter animation
|
340
|
+
*/
|
341
|
+
startTypingAnimation(onComplete) {
|
342
|
+
this.clearTypingAnimation();
|
343
|
+
// Don't start animation if there's no new content to type
|
344
|
+
if (this.displayedText === this.originalText) {
|
345
|
+
this.typingComplete = true;
|
346
|
+
// IMPORTANT: Always call onComplete even if no animation is needed
|
347
|
+
if (onComplete) {
|
348
|
+
this.createTimeout(() => {
|
349
|
+
onComplete();
|
350
|
+
}, 0);
|
351
|
+
}
|
352
|
+
return;
|
353
|
+
}
|
354
|
+
// Make sure currentIndex is in sync with displayedText
|
355
|
+
this.currentIndex = this.displayedText.length;
|
356
|
+
this.typingComplete = false;
|
357
|
+
const typeNextCharacter = () => {
|
358
|
+
if (this.currentIndex < this.originalText.length) {
|
359
|
+
const nextChar = this.originalText[this.currentIndex];
|
360
|
+
const newText = this.displayedText + nextChar;
|
361
|
+
if (newText !== this.displayedText) {
|
362
|
+
this.displayedText = newText;
|
363
|
+
this.requestUpdate();
|
364
|
+
}
|
365
|
+
this.currentIndex += 1;
|
366
|
+
// Schedule next character
|
367
|
+
this.typingTimeout = window.setTimeout(typeNextCharacter, this.getTypingDelayMs());
|
368
|
+
}
|
369
|
+
else {
|
370
|
+
this.clearTypingAnimation();
|
371
|
+
this.typingComplete = true;
|
372
|
+
if (onComplete) {
|
373
|
+
this.createTimeout(() => {
|
374
|
+
onComplete();
|
375
|
+
}, 0);
|
376
|
+
}
|
377
|
+
else {
|
378
|
+
this.createTimeout(() => {
|
379
|
+
this.dispatchEvent(new CustomEvent(DEFAULTS.CUSTOM_EVENT.TYPING_COMPLETE, {
|
380
|
+
bubbles: true,
|
381
|
+
composed: true,
|
382
|
+
detail: {
|
383
|
+
finalContent: this.originalText,
|
384
|
+
},
|
385
|
+
}));
|
386
|
+
}, 0);
|
387
|
+
}
|
388
|
+
}
|
389
|
+
};
|
390
|
+
this.typingTimeout = window.setTimeout(typeNextCharacter, this.getTypingDelayMs());
|
391
|
+
}
|
392
|
+
/**
|
393
|
+
* Clears the typing animation timeout
|
394
|
+
*/
|
395
|
+
clearTypingAnimation() {
|
396
|
+
if (this.typingTimeout !== null) {
|
397
|
+
clearTimeout(this.typingTimeout);
|
398
|
+
this.typingTimeout = null;
|
399
|
+
}
|
400
|
+
}
|
401
|
+
/**
|
402
|
+
* Handler for slotchange event
|
403
|
+
*/
|
404
|
+
handleSlotChange() {
|
405
|
+
this.captureAndProcessContent();
|
406
|
+
}
|
407
|
+
/**
|
408
|
+
* Render method that uses mdc-text component internally with accessibility features
|
409
|
+
*/
|
410
|
+
render() {
|
411
|
+
return html `
|
412
|
+
<div part="${DEFAULTS.CSS_PART_CONTAINER}" aria-live="polite" aria-busy="${!this.typingComplete}">
|
413
|
+
<mdc-text
|
414
|
+
part="${DEFAULTS.CSS_PART_TEXT}"
|
415
|
+
type="${this.type}"
|
416
|
+
tagname="${ifDefined(this.tagname)}"
|
417
|
+
aria-label="${this.originalText}"
|
418
|
+
>${this.displayedText}</mdc-text
|
419
|
+
>
|
420
|
+
<slot @slotchange=${this.handleSlotChange} class="typewriter-hidden"></slot>
|
421
|
+
</div>
|
422
|
+
`;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
Typewriter.styles = [...Component.styles, ...styles];
|
426
|
+
__decorate([
|
427
|
+
property({ attribute: 'type', reflect: true, type: String }),
|
428
|
+
__metadata("design:type", String)
|
429
|
+
], Typewriter.prototype, "type", void 0);
|
430
|
+
__decorate([
|
431
|
+
property({ attribute: 'tagname', reflect: true, type: String }),
|
432
|
+
__metadata("design:type", String)
|
433
|
+
], Typewriter.prototype, "tagname", void 0);
|
434
|
+
__decorate([
|
435
|
+
property({ attribute: 'speed', reflect: true }),
|
436
|
+
__metadata("design:type", String)
|
437
|
+
], Typewriter.prototype, "speed", void 0);
|
438
|
+
__decorate([
|
439
|
+
property({ attribute: 'max-queue-size', type: Number, reflect: true }),
|
440
|
+
__metadata("design:type", Number)
|
441
|
+
], Typewriter.prototype, "maxQueueSize", void 0);
|
442
|
+
__decorate([
|
443
|
+
state(),
|
444
|
+
__metadata("design:type", String)
|
445
|
+
], Typewriter.prototype, "displayedText", void 0);
|
446
|
+
__decorate([
|
447
|
+
state(),
|
448
|
+
__metadata("design:type", String)
|
449
|
+
], Typewriter.prototype, "originalText", void 0);
|
450
|
+
__decorate([
|
451
|
+
state(),
|
452
|
+
__metadata("design:type", Boolean)
|
453
|
+
], Typewriter.prototype, "typingComplete", void 0);
|
454
|
+
export default Typewriter;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
declare const TAG_NAME: "mdc-typewriter";
|
2
|
+
declare const SPEED: {
|
3
|
+
readonly VERY_SLOW: 240;
|
4
|
+
readonly SLOW: 120;
|
5
|
+
readonly NORMAL: 60;
|
6
|
+
readonly FAST: 20;
|
7
|
+
readonly VERY_FAST: 1;
|
8
|
+
};
|
9
|
+
declare const DEFAULTS: {
|
10
|
+
readonly TYPE: "body-large-regular";
|
11
|
+
readonly TEXT_ELEMENT_TAGNAME: "p";
|
12
|
+
readonly CSS_PART_TEXT: "text";
|
13
|
+
readonly CSS_PART_CONTAINER: "container";
|
14
|
+
readonly CHILDREN: "";
|
15
|
+
readonly SPEED: "normal";
|
16
|
+
readonly CUSTOM_EVENT: {
|
17
|
+
readonly TYPING_COMPLETE: "typing-complete";
|
18
|
+
};
|
19
|
+
};
|
20
|
+
export { TAG_NAME, DEFAULTS, SPEED };
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import utils from '../../utils/tag-name';
|
2
|
+
import { DEFAULTS as TEXT_DEFAULTS } from '../text/text.constants';
|
3
|
+
const TAG_NAME = utils.constructTagName('typewriter');
|
4
|
+
const SPEED = {
|
5
|
+
VERY_SLOW: 240,
|
6
|
+
SLOW: 120,
|
7
|
+
NORMAL: 60,
|
8
|
+
FAST: 20,
|
9
|
+
VERY_FAST: 1,
|
10
|
+
};
|
11
|
+
const DEFAULTS = {
|
12
|
+
TYPE: TEXT_DEFAULTS.TYPE,
|
13
|
+
TEXT_ELEMENT_TAGNAME: TEXT_DEFAULTS.TEXT_ELEMENT_TAGNAME,
|
14
|
+
CSS_PART_TEXT: 'text',
|
15
|
+
CSS_PART_CONTAINER: 'container',
|
16
|
+
CHILDREN: '',
|
17
|
+
SPEED: 'normal',
|
18
|
+
CUSTOM_EVENT: {
|
19
|
+
TYPING_COMPLETE: 'typing-complete',
|
20
|
+
},
|
21
|
+
};
|
22
|
+
export { TAG_NAME, DEFAULTS, SPEED };
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { css } from 'lit';
|
2
|
+
const styles = [
|
3
|
+
css `
|
4
|
+
:host {
|
5
|
+
display: block;
|
6
|
+
position: relative;
|
7
|
+
}
|
8
|
+
|
9
|
+
[part='container'] {
|
10
|
+
display: flex;
|
11
|
+
align-items: baseline;
|
12
|
+
}
|
13
|
+
|
14
|
+
.typewriter-hidden {
|
15
|
+
display: none;
|
16
|
+
}
|
17
|
+
`,
|
18
|
+
];
|
19
|
+
export default styles;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import type { TypedEvent } from '../../utils/types';
|
2
|
+
import type { TextType, TagName } from '../text/text.types';
|
3
|
+
import type Typewriter from './typewriter.component';
|
4
|
+
type TypewriterSpeed = 'slow' | 'normal' | 'fast' | 'very-slow' | 'very-fast' | string;
|
5
|
+
interface TextChunk {
|
6
|
+
text: string;
|
7
|
+
speed?: TypewriterSpeed;
|
8
|
+
instant?: boolean;
|
9
|
+
}
|
10
|
+
type TypewriterChangeEvent = TypedEvent<Typewriter, {
|
11
|
+
content: string;
|
12
|
+
isTyping: boolean;
|
13
|
+
}>;
|
14
|
+
type TypewriterTypingCompleteEvent = TypedEvent<Typewriter, {
|
15
|
+
finalContent: string;
|
16
|
+
}>;
|
17
|
+
interface Events {
|
18
|
+
onChangeEvent: TypewriterChangeEvent;
|
19
|
+
onTypingCompleteEvent: TypewriterTypingCompleteEvent;
|
20
|
+
}
|
21
|
+
export type { TypewriterSpeed, TextType, TagName, Events, TextChunk, TypewriterChangeEvent, TypewriterTypingCompleteEvent, };
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|