@fusion.dev/helix 0.212.2 → 0.214.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.
@@ -1,135 +0,0 @@
1
- import { type ConsoleDetail, HelixElement } from '@fusion.dev/helix-core';
2
- import type { CSSResultGroup, TemplateResult } from 'lit';
3
- import { type ConsoleLevel } from '../levels.js';
4
- /**
5
- * @summary A panel that shows what the previewed example wrote to the console.
6
- *
7
- * @description
8
- * The sandbox receives `helix-console` events from the preview and passes them
9
- * to the terminal. The preview is a separate document, so messages cross
10
- * `postMessage` and arrive as text.
11
- *
12
- * **Repeats collapse.** Consecutive identical lines show as one line with a
13
- * count, so an example with a render loop does not fill the panel with the same
14
- * warning. Only consecutive repeats collapse, so the order of messages is kept.
15
- *
16
- * The panel has `role="log"`, the role for an append-only stream. Screen
17
- * readers announce new output without reading the whole panel again. A line's
18
- * level is read before it, except a plain `log`, so an error does not sound
19
- * like any other line.
20
- *
21
- * **`controls` adds a clear button and a level filter** above the log. Both
22
- * are also yours to drive without them: `clear()` empties the log, and
23
- * `level` hides the quieter lines.
24
- *
25
- * @since 0.1.0
26
- * @status stable
27
- * @aliases Console, Output
28
- * @documentation https://fusion.dev/helix/components/sandbox
29
- *
30
- * @event {Event} change - Fired after the reader chose another level in the filter. `level` holds it.
31
- * @event {HelixBeforeChangeEvent} helix-before-change - Fired before the level filter changes, with the level chosen, `log` for every level. Cancelable: cancel it to keep the current level.
32
- *
33
- * @csspart clear - The button that empties the log, under `controls`.
34
- * @csspart controls - The row holding the clear button and the level filter, under `controls`.
35
- * @csspart count - How many times a repeated line was written.
36
- * @csspart empty - Shown while nothing has been written, or while the level filter hides every line.
37
- * @csspart entry - One line.
38
- * @csspart filter - The level filter, a native select, under `controls`.
39
- * @csspart level - The console level a line was written at.
40
- * @csspart log - The scrolling region.
41
- * @csspart message - The text of a line.
42
- *
43
- * @cssproperty --sandbox-terminal-size - Height of the scrolling region.
44
- */
45
- export declare class HelixSandboxTerminal extends HelixElement {
46
- /**
47
- * The key this part's words are registered under, its tag:
48
- * `registerWords('de', { 'helix-sandbox-terminal': { clearLabel: 'Leeren' } })`.
49
- */
50
- static words: string;
51
- /**
52
- * The clear button's text, under `controls`.
53
- */
54
- clearLabel: string;
55
- /**
56
- * Shows a clear button and a level filter above the log.
57
- *
58
- * Off by default, because a sandbox that puts the terminal in a panel often
59
- * has a toolbar of its own for them.
60
- */
61
- controls: boolean;
62
- /**
63
- * Text shown before anything has been written.
64
- */
65
- emptyLabel: string;
66
- /**
67
- * The log's name, read by screen readers.
68
- */
69
- label: string;
70
- /**
71
- * The quietest level shown: `info` hides plain logs, `warn` shows warnings
72
- * and errors, and `error` shows errors only. Absent shows every line.
73
- *
74
- * Lines it hides are kept, so lowering it shows them again. The filter under
75
- * `controls` sets it.
76
- */
77
- level?: ConsoleLevel | undefined;
78
- /**
79
- * The level filter's name, read by screen readers, under `controls`.
80
- */
81
- levelLabel: string;
82
- /**
83
- * What each choice of the level filter reads, for a page in another
84
- * language, keyed by level, such as `{ warn: '…' }`. A level left out keeps
85
- * its English words. As an attribute it is that object as JSON, and JSON
86
- * that does not parse is no words.
87
- */
88
- levelWords: Partial<Record<ConsoleLevel, string>>;
89
- /**
90
- * What a screen reader is told a repeated line's count is. `{count}` is how
91
- * many times it was written, two or more, in the locale, and a language
92
- * writes the forms it has: `{count, plural, few {# razy} other {# razy}}`.
93
- */
94
- timesLabel: string;
95
- private entries;
96
- /**
97
- * Whether the reader is at the bottom, and so wants to follow new output.
98
- *
99
- * Read before the render that adds a line and applied after it. Scrolling to
100
- * the bottom on every line would drag a reader off whatever they had scrolled
101
- * up to look at, which for a log of errors is the one thing they are doing.
102
- */
103
- private following;
104
- private get log();
105
- /**
106
- * Adds a line, collapsing it into the one above when they are identical.
107
- *
108
- * `write` rather than `append`, which every element already has from
109
- * `ParentNode` and which takes nodes. Shadowing it would break
110
- * `terminal.append(node)` for anyone who reasonably expected the DOM method.
111
- */
112
- write(detail: ConsoleDetail): void;
113
- /** Empties the log. */
114
- clear(): void;
115
- protected updated(): void;
116
- /**
117
- * Takes the level the reader chose in the filter, unless a listener
118
- * refused it, and then says so with the select's own `change`, which stops
119
- * at the shadow root otherwise. A refusal puts the select back.
120
- *
121
- * The select's `input` is stopped where it starts, as Pagination's is. It is
122
- * composed and comes first, so it left this element before
123
- * `helix-before-change` and still left it when the change was refused.
124
- */
125
- private readonly handleLevel;
126
- /** The clear button and the level filter, under `controls`. */
127
- private renderControls;
128
- protected render(): TemplateResult;
129
- static styles: CSSResultGroup;
130
- }
131
- declare global {
132
- interface HTMLElementTagNameMap {
133
- 'helix-sandbox-terminal': HelixSandboxTerminal;
134
- }
135
- }
@@ -1,142 +0,0 @@
1
- import { __decorate } from "tslib";
2
- import { customElement, formatWords, HelixBeforeChangeEvent, HelixElement, requestChange, words, wordsConverter, } from '@fusion.dev/helix-core';
3
- import { html, nothing } from 'lit';
4
- import { property, state } from 'lit/decorators.js';
5
- import { LEVELS, shows } from '../levels.js';
6
- import { styles } from './sandbox-terminal.css.js';
7
- const LIMIT = 200;
8
- const stop = (event) => event.stopPropagation();
9
- let HelixSandboxTerminal = class HelixSandboxTerminal extends HelixElement {
10
- constructor() {
11
- super(...arguments);
12
- this.clearLabel = 'Clear';
13
- this.controls = false;
14
- this.emptyLabel = 'Nothing written to the console yet.';
15
- this.label = 'Console output';
16
- this.levelLabel = 'Levels shown';
17
- this.levelWords = {
18
- error: 'Errors',
19
- info: 'Info and above',
20
- log: 'All levels',
21
- warn: 'Warnings and errors',
22
- };
23
- this.timesLabel = '{count} times';
24
- this.entries = [];
25
- this.following = true;
26
- this.handleLevel = (event) => {
27
- const field = event.target;
28
- const taken = requestChange({
29
- apply: (next) => {
30
- this.level = next === 'log' ? undefined : next;
31
- },
32
- event: (next) => new HelixBeforeChangeEvent({ value: next }),
33
- host: this,
34
- next: field.value,
35
- });
36
- if (taken) {
37
- this.relayNativeEvent(event);
38
- }
39
- else {
40
- field.value = this.level ?? 'log';
41
- }
42
- };
43
- }
44
- static { this.words = 'helix-sandbox-terminal'; }
45
- get log() {
46
- return this.renderRoot.querySelector('[part="log"]');
47
- }
48
- write(detail) {
49
- const log = this.log;
50
- if (log) {
51
- this.following = log.scrollHeight - log.scrollTop - log.clientHeight < 2;
52
- }
53
- const last = this.entries.at(-1);
54
- if (last && last.level === detail.level && last.text === detail.text) {
55
- this.entries = [...this.entries.slice(0, -1), { ...last, count: last.count + 1 }];
56
- return;
57
- }
58
- this.entries = [...this.entries, { ...detail, count: 1 }].slice(-LIMIT);
59
- }
60
- clear() {
61
- this.entries = [];
62
- this.following = true;
63
- }
64
- updated() {
65
- if (this.following) {
66
- const log = this.log;
67
- if (log) {
68
- log.scrollTop = log.scrollHeight;
69
- }
70
- }
71
- }
72
- renderControls() {
73
- if (!this.controls) {
74
- return nothing;
75
- }
76
- const clear = this.clearLabel;
77
- return html `<div part="controls">
78
- <select part="filter" aria-label=${this.levelLabel} @change=${this.handleLevel} @input=${stop}>
79
- ${LEVELS.map((one) => html `<option value=${one} ?selected=${(this.level ?? 'log') === one}>
80
- ${this.levelWords[one]}
81
- </option>`)}
82
- </select>
83
- <button part="clear" type="button" @click=${() => this.clear()}>${clear}</button>
84
- </div>`;
85
- }
86
- render() {
87
- const shown = this.entries.filter((entry) => shows(entry.level, this.level));
88
- return html `${this.renderControls()}<div part="log" role="log" aria-label=${this.label} tabindex="0">
89
- ${shown.length === 0
90
- ? html `<p part="empty">${this.emptyLabel}</p>`
91
- : shown.map((entry) => html `<div part="entry" data-level=${entry.level}>
92
- <span part="level" aria-hidden=${entry.level === 'log' ? 'true' : nothing}
93
- >${entry.level}</span
94
- >
95
- <span part="message">${entry.text}</span>
96
- ${entry.count > 1
97
- ? html `<span part="count" aria-label=${formatWords(this, 'timesLabel', { count: entry.count })}
98
- >${entry.count}</span
99
- >`
100
- : nothing}
101
- </div>`)}
102
- </div>`;
103
- }
104
- static { this.styles = styles; }
105
- };
106
- __decorate([
107
- words,
108
- property({ attribute: 'clear-label' })
109
- ], HelixSandboxTerminal.prototype, "clearLabel", void 0);
110
- __decorate([
111
- property({ reflect: true, type: Boolean })
112
- ], HelixSandboxTerminal.prototype, "controls", void 0);
113
- __decorate([
114
- words,
115
- property({ attribute: 'empty-label' })
116
- ], HelixSandboxTerminal.prototype, "emptyLabel", void 0);
117
- __decorate([
118
- words,
119
- property()
120
- ], HelixSandboxTerminal.prototype, "label", void 0);
121
- __decorate([
122
- property()
123
- ], HelixSandboxTerminal.prototype, "level", void 0);
124
- __decorate([
125
- words,
126
- property({ attribute: 'level-label' })
127
- ], HelixSandboxTerminal.prototype, "levelLabel", void 0);
128
- __decorate([
129
- words,
130
- property({ attribute: 'level-words', converter: wordsConverter })
131
- ], HelixSandboxTerminal.prototype, "levelWords", void 0);
132
- __decorate([
133
- words,
134
- property({ attribute: 'times-label' })
135
- ], HelixSandboxTerminal.prototype, "timesLabel", void 0);
136
- __decorate([
137
- state()
138
- ], HelixSandboxTerminal.prototype, "entries", void 0);
139
- HelixSandboxTerminal = __decorate([
140
- customElement('helix-sandbox-terminal')
141
- ], HelixSandboxTerminal);
142
- export { HelixSandboxTerminal };