@fusion.dev/helix-headless 0.199.0 → 0.200.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.
@@ -0,0 +1,772 @@
1
+ var HelixHeadlessLog_1;
2
+ import { __decorate } from "tslib";
3
+ import { customElement, drawIcon, formatWords, HelixBeforePinEvent, HelixElement, HelixExpandEvent, HelixPinEvent, hostAria, MixinCollection, onUnlessFalse, requestChange, SCROLLER_RULE, VIRTUAL_RULE, VirtualizeController, whenHydrated, words, } from '@fusion.dev/helix-core';
4
+ import { arrowDown } from '@fusion.dev/helix-icons';
5
+ import { nothing } from 'lit';
6
+ import { property, state } from 'lit/decorators.js';
7
+ import { keyed } from 'lit/directives/keyed.js';
8
+ import { repeat } from 'lit/directives/repeat.js';
9
+ import { html } from 'lit/static-html.js';
10
+ import { lineRuns } from '../../code-block/lines.js';
11
+ import { stripAnsi } from '../ansi.js';
12
+ import { LogBuffer, } from '../buffer.js';
13
+ import { timeOf } from '../line/log-line.js';
14
+ import { logRows } from '../rows.js';
15
+ const STATUS_NAMES = {
16
+ done: 'summary: group-summary-done',
17
+ failed: 'summary: group-summary-failed',
18
+ pending: 'summary: group-summary-pending',
19
+ running: 'summary: group-summary-running',
20
+ skipped: 'summary: group-summary-skipped',
21
+ };
22
+ const secondNames = (table, key) => key !== undefined && Object.hasOwn(table, key) ? `, ${table[key]}` : '';
23
+ const inRuns = (runs, number) => runs.some(([first, last]) => number >= first && number <= last);
24
+ let HelixHeadlessLog = class HelixHeadlessLog extends MixinCollection(HelixElement) {
25
+ constructor() {
26
+ super(...arguments);
27
+ this.defaultPinned = true;
28
+ this.doneLabel = 'Finished';
29
+ this.droppedLabel = '{count, plural, one {# earlier line is} other {# earlier lines are}} not kept';
30
+ this.emptyText = 'No output yet';
31
+ this.errorLabel = '{count, plural, one {Error} other {# errors}}: {text}';
32
+ this.fallbackLabel = 'Log';
33
+ this.groupLabel = '{status, select, failed {{heading} failed} other {{heading} finished}}';
34
+ this.groups = [];
35
+ this.label = '';
36
+ this.limit = 0;
37
+ this.lineHref = '';
38
+ this.lineLabel = 'Line {number}';
39
+ this.lineNumbers = false;
40
+ this.markLines = '';
41
+ this.matchesLabel = '{count, plural, =0 {No lines match} one {# line matches} other {# lines match}}';
42
+ this.query = '';
43
+ this.resumeLabel = 'Jump to latest';
44
+ this.threshold = 48;
45
+ this.wrap = false;
46
+ this.pinnedState = undefined;
47
+ this.doneState = undefined;
48
+ this.reading = false;
49
+ this.announcement = '';
50
+ this.said = 0;
51
+ this.buffer = new LogBuffer();
52
+ this.sourceValue = null;
53
+ this.readToken = 0;
54
+ this.stopReading = undefined;
55
+ this.opened = new Map();
56
+ this.view = { matched: 0, rows: [] };
57
+ this.fresh = false;
58
+ this.droppedBefore = 0;
59
+ this.owed = 0;
60
+ this.childLines = [];
61
+ this.childGroups = [];
62
+ this.watcher = undefined;
63
+ this.grower = undefined;
64
+ this.stuckAt = -1;
65
+ this.opening = true;
66
+ this.heard = undefined;
67
+ this.virtualize = new VirtualizeController(this, {
68
+ anchor: () => !this.pinned,
69
+ container: () => (this.fed ? this.log : null),
70
+ count: () => this.view.rows.length,
71
+ estimate: () => HelixHeadlessLog_1.ESTIMATE,
72
+ measured: () => this.wrap,
73
+ rows: () => (this.fed ? this.drawn() : []),
74
+ });
75
+ this.handleResize = () => {
76
+ this.markScroller();
77
+ if (this.pinned) {
78
+ this.stick();
79
+ }
80
+ };
81
+ this.handleMutation = () => {
82
+ this.requestUpdate();
83
+ };
84
+ this.handleScroll = () => {
85
+ const log = this.log;
86
+ if (this.pinned && log && log.scrollTop >= this.stuckAt - 1 && !this.atBottom) {
87
+ this.stick();
88
+ return;
89
+ }
90
+ const wanted = this.atBottom;
91
+ if (wanted !== this.pinned) {
92
+ this.requestPinned(wanted);
93
+ }
94
+ };
95
+ this.handleResume = () => {
96
+ this.resume();
97
+ };
98
+ this.handleGroupToggle = (event) => {
99
+ const group = event.currentTarget;
100
+ const id = group.dataset.group;
101
+ if (id === undefined || this.query.trim() !== '') {
102
+ return;
103
+ }
104
+ this.opened.set(id, group.open);
105
+ this.requestUpdate();
106
+ const open = this.groups.filter((each) => this.isOpen(each.id)).map((each) => each.id);
107
+ this.dispatchEvent(new HelixExpandEvent({ value: open.join(',') }));
108
+ };
109
+ }
110
+ static { HelixHeadlessLog_1 = this; }
111
+ static { this.markRules = [SCROLLER_RULE, VIRTUAL_RULE]; }
112
+ static { this.words = 'helix-log'; }
113
+ static { this.ESTIMATE = 20; }
114
+ get done() {
115
+ return this.doneState ?? false;
116
+ }
117
+ set done(next) {
118
+ const previous = this.done;
119
+ this.doneState = next;
120
+ this.requestUpdate('done', previous);
121
+ }
122
+ get lines() {
123
+ return this.buffer.lines;
124
+ }
125
+ set lines(next) {
126
+ const previous = this.buffer.lines;
127
+ this.buffer.replace(next ?? []);
128
+ this.fresh = true;
129
+ this.requestUpdate('lines', previous);
130
+ }
131
+ get parse() {
132
+ return this.buffer.parse;
133
+ }
134
+ set parse(next) {
135
+ const previous = this.buffer.parse;
136
+ this.buffer.parse = next;
137
+ this.requestUpdate('parse', previous);
138
+ }
139
+ get pinned() {
140
+ return this.pinnedState ?? this.defaultPinned;
141
+ }
142
+ set pinned(next) {
143
+ const previous = this.pinned;
144
+ this.pinnedState = next;
145
+ this.requestUpdate('pinned', previous);
146
+ }
147
+ get source() {
148
+ return this.sourceValue;
149
+ }
150
+ set source(next) {
151
+ const previous = this.sourceValue;
152
+ this.sourceValue = next ?? null;
153
+ this.requestUpdate('source', previous);
154
+ if (this.isConnected && next !== previous) {
155
+ void this.readSource(this.sourceValue);
156
+ }
157
+ }
158
+ get fed() {
159
+ return (this.buffer.lines.length > 0 ||
160
+ this.buffer.current() !== undefined ||
161
+ this.groups.length > 0 ||
162
+ this.sourceValue !== null);
163
+ }
164
+ get log() {
165
+ return this.partNamed('log');
166
+ }
167
+ get text() {
168
+ if (this.fed) {
169
+ const current = this.buffer.current();
170
+ return [...this.buffer.lines, ...(current ? [current] : [])]
171
+ .map((line) => stripAnsi(line.text))
172
+ .join('\n');
173
+ }
174
+ return this.childLines.map((line) => (line.textContent ?? '').trim()).join('\n');
175
+ }
176
+ write(chunk) {
177
+ if (chunk === '') {
178
+ return;
179
+ }
180
+ this.buffer.write(chunk);
181
+ this.requestUpdate();
182
+ }
183
+ clear() {
184
+ this.buffer.clear();
185
+ this.opened.clear();
186
+ this.fresh = true;
187
+ this.droppedBefore = 0;
188
+ this.requestUpdate();
189
+ }
190
+ resume() {
191
+ this.stick();
192
+ this.requestPinned(true);
193
+ }
194
+ async scrollToLine(number, options = {}) {
195
+ const align = options.align ?? 'center';
196
+ if (this.fed) {
197
+ const line = this.buffer.lines[number - this.buffer.dropped - 1];
198
+ if (line?.group !== undefined && !this.isOpen(line.group)) {
199
+ this.opened.set(line.group, true);
200
+ this.requestUpdate();
201
+ await this.updateComplete;
202
+ }
203
+ const index = this.view.rows.findIndex((row) => row.kind === 'line' && row.number === number);
204
+ if (index < 0) {
205
+ return false;
206
+ }
207
+ if (this.pinned && this.requestPinned(false)) {
208
+ await this.updateComplete;
209
+ }
210
+ this.virtualize.reveal(index, 0, {
211
+ align,
212
+ ...(options.behavior ? { behavior: options.behavior } : {}),
213
+ });
214
+ return true;
215
+ }
216
+ const line = this.childLines[number - 1];
217
+ if (!line || line.logFiltered) {
218
+ return false;
219
+ }
220
+ for (const group of this.childGroups) {
221
+ if (!group.open && group.contains(line)) {
222
+ group.open = true;
223
+ }
224
+ }
225
+ if (this.pinned && this.requestPinned(false)) {
226
+ await this.updateComplete;
227
+ }
228
+ await line.updateComplete;
229
+ const log = this.log;
230
+ if (log) {
231
+ const box = log.getBoundingClientRect();
232
+ const rect = line.getBoundingClientRect();
233
+ const offset = align === 'start'
234
+ ? rect.top - box.top
235
+ : align === 'end'
236
+ ? rect.bottom - box.bottom
237
+ : align === 'nearest'
238
+ ? Math.min(0, rect.top - box.top) || Math.max(0, rect.bottom - box.bottom)
239
+ : rect.top - box.top - (box.height - rect.height) / 2;
240
+ if (options.behavior && typeof log.scrollBy === 'function') {
241
+ log.scrollBy({ behavior: options.behavior, top: offset });
242
+ }
243
+ else {
244
+ log.scrollTop += offset;
245
+ }
246
+ }
247
+ return true;
248
+ }
249
+ isOpen(id) {
250
+ const known = this.opened.get(id);
251
+ if (known !== undefined) {
252
+ return known;
253
+ }
254
+ const seeded = this.groups.find((group) => group.id === id)?.open ?? false;
255
+ this.opened.set(id, seeded);
256
+ return seeded;
257
+ }
258
+ reopen(previous) {
259
+ const before = new Map((previous ?? []).map((group) => [group.id, group.open]));
260
+ for (const group of this.groups) {
261
+ if (group.open !== undefined && before.has(group.id) && before.get(group.id) !== group.open) {
262
+ this.opened.set(group.id, group.open);
263
+ }
264
+ }
265
+ }
266
+ get atBottom() {
267
+ const log = this.log;
268
+ if (!log) {
269
+ return true;
270
+ }
271
+ return log.scrollHeight - log.scrollTop - log.clientHeight <= Math.max(0, this.threshold);
272
+ }
273
+ stick() {
274
+ const log = this.log;
275
+ if (log) {
276
+ log.scrollTop = log.scrollHeight;
277
+ this.stuckAt = log.scrollTop;
278
+ }
279
+ }
280
+ requestPinned(next) {
281
+ if (next === this.pinned) {
282
+ return false;
283
+ }
284
+ return requestChange({
285
+ apply: (value) => {
286
+ const previous = this.pinned;
287
+ this.pinnedState = value;
288
+ this.requestUpdate('pinned', previous);
289
+ this.dispatchEvent(new HelixPinEvent({ value: String(value) }));
290
+ },
291
+ event: (value) => new HelixBeforePinEvent({ value: String(value) }),
292
+ host: this,
293
+ next,
294
+ });
295
+ }
296
+ drawn() {
297
+ return [...(this.renderRoot?.querySelectorAll?.('[part="row"]') ?? [])].map((element) => ({ element, index: Number(element.dataset.index) }));
298
+ }
299
+ readChildren() {
300
+ if (!this.childrenKnown) {
301
+ this.childLines = [];
302
+ this.childGroups = [];
303
+ return;
304
+ }
305
+ const lines = [];
306
+ const groups = [];
307
+ for (const element of this.querySelectorAll('*')) {
308
+ if ('isLogLine' in element && element.isLogLine === true) {
309
+ lines.push(element);
310
+ }
311
+ else if ('isLogGroup' in element && element.isLogGroup === true) {
312
+ groups.push(element);
313
+ }
314
+ }
315
+ this.childLines = lines;
316
+ this.childGroups = groups;
317
+ }
318
+ tellLines() {
319
+ const marks = lineRuns(this.markLines);
320
+ const needle = this.query.trim().toLowerCase();
321
+ const start = this.childLines.map((line) => timeOf(line.at)).find((time) => time !== undefined);
322
+ this.childLines.forEach((line, at) => {
323
+ const filtered = needle !== '' && !(line.textContent ?? '').toLowerCase().includes(needle);
324
+ whenHydrated(line, () => {
325
+ line.logNumber = at + 1;
326
+ line.logNumbers = this.lineNumbers;
327
+ line.logHref = this.lineHref;
328
+ line.logTimes = this.timestamps ?? '';
329
+ line.logStart = start;
330
+ line.logMarked = inRuns(marks, at + 1);
331
+ line.logFiltered = filtered;
332
+ });
333
+ if (!filtered && needle !== '') {
334
+ for (const group of this.childGroups) {
335
+ if (!group.open && group.contains(line)) {
336
+ whenHydrated(group, () => {
337
+ group.open = true;
338
+ });
339
+ }
340
+ }
341
+ }
342
+ });
343
+ }
344
+ markScroller() {
345
+ const log = this.log;
346
+ if (!log) {
347
+ return;
348
+ }
349
+ if (log.scrollHeight > log.clientHeight || log.scrollWidth > log.clientWidth) {
350
+ log.tabIndex = 0;
351
+ }
352
+ else {
353
+ log.removeAttribute('tabindex');
354
+ }
355
+ }
356
+ listen() {
357
+ const groups = new Map();
358
+ if (this.fed) {
359
+ for (const group of this.groups) {
360
+ groups.set(group.id, { heading: group.heading, status: group.status });
361
+ }
362
+ }
363
+ else {
364
+ for (const group of this.childGroups) {
365
+ groups.set(group, {
366
+ heading: group.heading || (group.textContent ?? '').trim(),
367
+ status: group.status,
368
+ });
369
+ }
370
+ }
371
+ return {
372
+ done: this.done,
373
+ groups,
374
+ matched: this.fed
375
+ ? this.view.matched
376
+ : this.childLines.filter((line) => !line.logFiltered).length,
377
+ query: this.query,
378
+ total: this.fed ? this.buffer.dropped + this.buffer.lines.length : this.childLines.length,
379
+ };
380
+ }
381
+ announce() {
382
+ const now = this.listen();
383
+ const before = this.heard;
384
+ this.heard = now;
385
+ if (this.opening || !before) {
386
+ return;
387
+ }
388
+ const said = [];
389
+ if (now.query !== before.query && now.query.trim() !== '') {
390
+ said.push(formatWords(this, 'matchesLabel', { count: now.matched }));
391
+ }
392
+ const arrived = now.total - before.total;
393
+ if (arrived > 0) {
394
+ const fresh = this.fed
395
+ ? this.buffer.lines.slice(Math.max(0, this.buffer.lines.length - arrived))
396
+ : this.childLines.slice(before.total).map((line) => ({
397
+ level: line.level,
398
+ text: (line.textContent ?? '').trim(),
399
+ }));
400
+ const errors = fresh.filter((line) => line.level === 'error');
401
+ if (errors.length > 0) {
402
+ said.push(formatWords(this, 'errorLabel', {
403
+ count: errors.length,
404
+ text: stripAnsi(errors[0]?.text ?? ''),
405
+ }));
406
+ }
407
+ }
408
+ for (const [id, group] of now.groups) {
409
+ const was = before.groups.get(id)?.status;
410
+ if (group.status !== was &&
411
+ (group.status === 'done' || group.status === 'failed') &&
412
+ before.groups.has(id)) {
413
+ said.push(formatWords(this, 'groupLabel', { heading: group.heading, status: group.status }));
414
+ }
415
+ }
416
+ if (now.done && !before.done) {
417
+ said.push(this.doneLabel);
418
+ }
419
+ if (said.length > 0) {
420
+ this.announcement = said.join(' ');
421
+ this.said += 1;
422
+ }
423
+ }
424
+ async readSource(source) {
425
+ this.stopReading?.();
426
+ this.stopReading = undefined;
427
+ this.readToken += 1;
428
+ const token = this.readToken;
429
+ this.reading = source !== null;
430
+ if (!source) {
431
+ return;
432
+ }
433
+ const decoder = new TextDecoder();
434
+ const take = (chunk) => {
435
+ if (token !== this.readToken) {
436
+ return false;
437
+ }
438
+ this.write(typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true }));
439
+ return true;
440
+ };
441
+ try {
442
+ if ('getReader' in source) {
443
+ const reader = source.getReader();
444
+ this.stopReading = () => {
445
+ reader.cancel().catch(() => undefined);
446
+ };
447
+ for (;;) {
448
+ const { done, value } = await reader.read();
449
+ if (done || !take(value)) {
450
+ break;
451
+ }
452
+ }
453
+ }
454
+ else {
455
+ for await (const chunk of source) {
456
+ if (!take(chunk)) {
457
+ break;
458
+ }
459
+ }
460
+ }
461
+ if (token === this.readToken) {
462
+ this.write(decoder.decode());
463
+ this.done = true;
464
+ }
465
+ }
466
+ catch (error) {
467
+ if (token === this.readToken) {
468
+ globalThis.reportError?.(error);
469
+ }
470
+ }
471
+ finally {
472
+ if (token === this.readToken) {
473
+ this.reading = false;
474
+ this.stopReading = undefined;
475
+ }
476
+ }
477
+ }
478
+ connectedCallback() {
479
+ super.connectedCallback();
480
+ this.watcher = new MutationObserver(this.handleMutation);
481
+ this.watcher.observe(this, {
482
+ attributeFilter: ['status', 'level'],
483
+ childList: true,
484
+ subtree: true,
485
+ });
486
+ this.opening = true;
487
+ requestAnimationFrame(() => {
488
+ this.opening = false;
489
+ });
490
+ if (this.sourceValue !== null && !this.reading) {
491
+ void this.readSource(this.sourceValue);
492
+ }
493
+ }
494
+ disconnectedCallback() {
495
+ super.disconnectedCallback();
496
+ this.watcher?.disconnect();
497
+ this.watcher = undefined;
498
+ this.grower?.disconnect();
499
+ this.grower = undefined;
500
+ this.stopReading?.();
501
+ this.stopReading = undefined;
502
+ this.readToken += 1;
503
+ this.reading = false;
504
+ }
505
+ willUpdate(changed) {
506
+ super.willUpdate(changed);
507
+ hostAria(this.internals, { label: this.label || this.fallbackLabel, role: 'region' });
508
+ if (changed.has('groups')) {
509
+ this.reopen(changed.get('groups'));
510
+ }
511
+ if (changed.has('limit')) {
512
+ this.buffer.limit = Math.max(0, Math.floor(this.limit || 0));
513
+ this.buffer.write('');
514
+ }
515
+ if (!this.fed) {
516
+ this.readChildren();
517
+ }
518
+ const dropped = this.buffer.dropped - this.droppedBefore;
519
+ if (this.fresh) {
520
+ this.fresh = false;
521
+ this.virtualize.forget();
522
+ }
523
+ else if (dropped > 0) {
524
+ if (!this.pinned) {
525
+ this.owed += dropped * this.virtualize.sizeOf(0);
526
+ }
527
+ if (this.wrap) {
528
+ this.virtualize.forget();
529
+ }
530
+ }
531
+ this.droppedBefore = this.buffer.dropped;
532
+ if (this.fed) {
533
+ this.view = logRows({
534
+ current: this.buffer.current(),
535
+ groups: this.groups,
536
+ lines: this.buffer.lines,
537
+ open: (id) => this.isOpen(id),
538
+ query: this.query,
539
+ start: this.buffer.dropped,
540
+ });
541
+ }
542
+ else {
543
+ this.view = { matched: 0, rows: [] };
544
+ }
545
+ this.toggleState('pinned', this.pinned);
546
+ this.toggleState('done', this.done);
547
+ this.toggleState('filtered', this.query.trim() !== '');
548
+ this.toggleState('empty', this.childrenKnown && !this.fed && this.childLines.length === 0);
549
+ }
550
+ updated(changed) {
551
+ super.updated(changed);
552
+ if (!this.fed) {
553
+ this.tellLines();
554
+ }
555
+ const log = this.log;
556
+ if (this.pinned) {
557
+ this.stick();
558
+ }
559
+ else if (this.owed > 0 && log) {
560
+ log.scrollTop = Math.max(0, log.scrollTop - this.owed);
561
+ }
562
+ this.owed = 0;
563
+ if (this.fed) {
564
+ this.virtualize.measure();
565
+ }
566
+ if (log && typeof ResizeObserver !== 'undefined' && !this.grower) {
567
+ this.grower = new ResizeObserver(this.handleResize);
568
+ this.grower.observe(log);
569
+ }
570
+ this.markScroller();
571
+ this.announce();
572
+ }
573
+ renderRow(row, marks, start) {
574
+ if (row.kind === 'group') {
575
+ const group = this.tag('log-group');
576
+ const { duration, heading, id, status } = row.group;
577
+ return html `<${group}
578
+ exportparts="content: group-content, duration: group-duration, heading: group-heading,
579
+ mark: group-mark, status: group-status, summary: group-summary${secondNames(STATUS_NAMES, status)}"
580
+ data-group=${id}
581
+ duration=${duration ?? nothing}
582
+ heading=${heading}
583
+ status=${status ?? nothing}
584
+ .logDrawn=${true}
585
+ .open=${row.open}
586
+ @toggle=${this.handleGroupToggle}
587
+ ></${group}>`;
588
+ }
589
+ const line = this.tag('log-line');
590
+ const { at, level } = row.line;
591
+ return html `<${line}
592
+ exportparts="line, line-debug, line-error, line-marked, line-warn, match: line-match,
593
+ number: line-number, run: line-run, run-bold: line-run-bold, run-dim: line-run-dim,
594
+ run-italic: line-run-italic, run-strike: line-run-strike, run-underline: line-run-underline,
595
+ text: line-text, time: line-time"
596
+ level=${level ?? nothing}
597
+ .at=${at ?? ''}
598
+ .lineLabel=${this.lineLabel}
599
+ .logHref=${this.lineHref}
600
+ .logMarked=${inRuns(marks, row.number)}
601
+ .logNumber=${row.number}
602
+ .logNumbers=${this.lineNumbers}
603
+ .logQuery=${this.query}
604
+ .logStart=${start}
605
+ .logTimes=${this.timestamps ?? ''}
606
+ .runs=${this.buffer.runsOf(row.line)}
607
+ ></${line}>`;
608
+ }
609
+ get firstTime() {
610
+ for (const line of this.buffer.lines) {
611
+ const time = timeOf(line.at);
612
+ if (time !== undefined) {
613
+ return time;
614
+ }
615
+ }
616
+ return undefined;
617
+ }
618
+ get digits() {
619
+ if (!this.lineNumbers) {
620
+ return 0;
621
+ }
622
+ const largest = this.fed
623
+ ? this.buffer.dropped + this.buffer.lines.length + 1
624
+ : this.childLines.length;
625
+ return largest > 0 ? String(largest).length : 0;
626
+ }
627
+ renderRows() {
628
+ const { after, before, first, last } = this.virtualize.window;
629
+ const marks = lineRuns(this.markLines);
630
+ const start = this.timestamps === 'relative' ? this.firstTime : undefined;
631
+ return html `<div part="before" role="presentation" style="block-size: ${before}px; flex: none"></div>
632
+ ${repeat(this.view.rows.slice(first, last), (row) => (row.kind === 'group' ? `group:${row.group.id}` : `line:${row.number}`), (row, offset) => html `<div part="row" data-index=${first + offset}>${this.renderRow(row, marks, start)}</div>`)}
633
+ <div part="after" role="presentation" style="block-size: ${after}px; flex: none"></div>`;
634
+ }
635
+ renderResume() {
636
+ return html `<slot name="resume"
637
+ ><button part="resume-button" type="button">
638
+ <span part="resume-mark" aria-hidden="true">${drawIcon(arrowDown)}</span>${this.resumeLabel}
639
+ </button></slot
640
+ >`;
641
+ }
642
+ render() {
643
+ const fed = this.fed;
644
+ const dropped = this.buffer.dropped;
645
+ const content = this.query.trim() !== '' ||
646
+ (fed ? this.view.rows.length > 0 : this.childLines.length > 0 || !this.childrenKnown);
647
+ return html `<slot name="toolbar" part="toolbar"></slot>
648
+ <p part="dropped" ?hidden=${dropped === 0}>${dropped === 0 ? nothing : formatWords(this, 'droppedLabel', { count: dropped })}</p>
649
+ <div
650
+ part="log"
651
+ role="log"
652
+ aria-live="off"
653
+ data-scroller
654
+ aria-label=${this.label || this.fallbackLabel}
655
+ aria-busy=${this.reading && !this.done ? 'true' : nothing}
656
+ style=${this.digits === 0 ? nothing : `--log-digits: ${this.digits}`}
657
+ ?data-windowed=${fed}
658
+ @scroll=${this.handleScroll}
659
+ >
660
+ ${fed ? this.renderRows() : nothing}
661
+ <slot></slot>
662
+ ${this.renderStatus(content)}
663
+ </div>
664
+ <span part="live" role="status">${keyed(this.said, this.announcement)}</span>
665
+ <div part="resume" ?hidden=${this.pinned} @click=${this.handleResume}>
666
+ ${this.renderResume()}
667
+ </div>`;
668
+ }
669
+ };
670
+ __decorate([
671
+ property({ attribute: 'default-pinned', converter: onUnlessFalse })
672
+ ], HelixHeadlessLog.prototype, "defaultPinned", void 0);
673
+ __decorate([
674
+ property({ type: Boolean })
675
+ ], HelixHeadlessLog.prototype, "done", null);
676
+ __decorate([
677
+ words,
678
+ property({ attribute: 'done-label' })
679
+ ], HelixHeadlessLog.prototype, "doneLabel", void 0);
680
+ __decorate([
681
+ words,
682
+ property({ attribute: 'dropped-label' })
683
+ ], HelixHeadlessLog.prototype, "droppedLabel", void 0);
684
+ __decorate([
685
+ words,
686
+ property({ attribute: 'empty-text' })
687
+ ], HelixHeadlessLog.prototype, "emptyText", void 0);
688
+ __decorate([
689
+ words,
690
+ property({ attribute: 'error-label' })
691
+ ], HelixHeadlessLog.prototype, "errorLabel", void 0);
692
+ __decorate([
693
+ words,
694
+ property({ attribute: 'fallback-label' })
695
+ ], HelixHeadlessLog.prototype, "fallbackLabel", void 0);
696
+ __decorate([
697
+ words,
698
+ property({ attribute: 'group-label' })
699
+ ], HelixHeadlessLog.prototype, "groupLabel", void 0);
700
+ __decorate([
701
+ property({ attribute: false })
702
+ ], HelixHeadlessLog.prototype, "groups", void 0);
703
+ __decorate([
704
+ property()
705
+ ], HelixHeadlessLog.prototype, "label", void 0);
706
+ __decorate([
707
+ property({ type: Number })
708
+ ], HelixHeadlessLog.prototype, "limit", void 0);
709
+ __decorate([
710
+ property({ attribute: 'line-href' })
711
+ ], HelixHeadlessLog.prototype, "lineHref", void 0);
712
+ __decorate([
713
+ words,
714
+ property({ attribute: 'line-label' })
715
+ ], HelixHeadlessLog.prototype, "lineLabel", void 0);
716
+ __decorate([
717
+ property({ attribute: 'line-numbers', type: Boolean })
718
+ ], HelixHeadlessLog.prototype, "lineNumbers", void 0);
719
+ __decorate([
720
+ property({ attribute: false })
721
+ ], HelixHeadlessLog.prototype, "lines", null);
722
+ __decorate([
723
+ property({ attribute: 'mark-lines' })
724
+ ], HelixHeadlessLog.prototype, "markLines", void 0);
725
+ __decorate([
726
+ words,
727
+ property({ attribute: 'matches-label' })
728
+ ], HelixHeadlessLog.prototype, "matchesLabel", void 0);
729
+ __decorate([
730
+ property({ attribute: false })
731
+ ], HelixHeadlessLog.prototype, "parse", null);
732
+ __decorate([
733
+ property({ type: Boolean })
734
+ ], HelixHeadlessLog.prototype, "pinned", null);
735
+ __decorate([
736
+ property()
737
+ ], HelixHeadlessLog.prototype, "query", void 0);
738
+ __decorate([
739
+ words,
740
+ property({ attribute: 'resume-label' })
741
+ ], HelixHeadlessLog.prototype, "resumeLabel", void 0);
742
+ __decorate([
743
+ property({ attribute: false })
744
+ ], HelixHeadlessLog.prototype, "source", null);
745
+ __decorate([
746
+ property({ type: Number })
747
+ ], HelixHeadlessLog.prototype, "threshold", void 0);
748
+ __decorate([
749
+ property()
750
+ ], HelixHeadlessLog.prototype, "timestamps", void 0);
751
+ __decorate([
752
+ property({ reflect: true, type: Boolean })
753
+ ], HelixHeadlessLog.prototype, "wrap", void 0);
754
+ __decorate([
755
+ state()
756
+ ], HelixHeadlessLog.prototype, "pinnedState", void 0);
757
+ __decorate([
758
+ state()
759
+ ], HelixHeadlessLog.prototype, "doneState", void 0);
760
+ __decorate([
761
+ state()
762
+ ], HelixHeadlessLog.prototype, "reading", void 0);
763
+ __decorate([
764
+ state()
765
+ ], HelixHeadlessLog.prototype, "announcement", void 0);
766
+ __decorate([
767
+ state()
768
+ ], HelixHeadlessLog.prototype, "said", void 0);
769
+ HelixHeadlessLog = HelixHeadlessLog_1 = __decorate([
770
+ customElement('helix-headless-log')
771
+ ], HelixHeadlessLog);
772
+ export { HelixHeadlessLog };