@fusion.dev/helix-headless 0.219.0 → 0.220.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/api.json +1 -1
- package/custom-elements.json +1 -1
- package/dist/code-editor/root/code-editor-root.d.ts +48 -51
- package/dist/code-editor/root/code-editor-root.js +67 -249
- package/dist/element-events.generated.js +3 -1
- package/dist/find/index.d.ts +1 -0
- package/dist/find/index.js +1 -0
- package/dist/find/root/find-root.d.ts +314 -0
- package/dist/find/root/find-root.js +577 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/log/group/log-group.d.ts +11 -2
- package/dist/log/group/log-group.js +17 -3
- package/dist/terminal/root/terminal-root.d.ts +49 -32
- package/dist/terminal/root/terminal-root.js +72 -181
- package/dist/tree/item/tree-item.d.ts +11 -0
- package/dist/tree/item/tree-item.js +19 -1
- package/examples.json +1 -1
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +849 -66
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +156 -2
- package/types/words.d.ts +87 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { customElement, deepActiveElement, deepContains, drawIcon, elementById, findPattern, formatWords, HelixElement, HelixFoundEvent, MIRROR_RULE, MixinControllerOpen, matchesChord, onApple, stopPress, textFinder, words, } from '@fusion.dev/helix-core';
|
|
3
|
+
import { asterisk, caretDown, caretRight, caretUp, textAa, textAUnderline, x, } from '@fusion.dev/helix-icons';
|
|
4
|
+
import { nothing } from 'lit';
|
|
5
|
+
import { property, state } from 'lit/decorators.js';
|
|
6
|
+
import { keyed } from 'lit/directives/keyed.js';
|
|
7
|
+
import { live } from 'lit/directives/live.js';
|
|
8
|
+
import { html } from 'lit/static-html.js';
|
|
9
|
+
import '../../button/index.js';
|
|
10
|
+
import '../../icon-button/index.js';
|
|
11
|
+
import '../../toolbar/index.js';
|
|
12
|
+
const SEARCHED = ['for', 'matchCase', 'open', 'query', 'regex', 'skip', 'wholeWord'];
|
|
13
|
+
let HelixHeadlessFind = class HelixHeadlessFind extends MixinControllerOpen(HelixElement) {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.closeLabel = 'Close find';
|
|
17
|
+
this.controlsLabel = 'Find controls';
|
|
18
|
+
this.for = '';
|
|
19
|
+
this.invalidLabel = 'Not a valid regular expression';
|
|
20
|
+
this.label = 'Find';
|
|
21
|
+
this.matchCase = false;
|
|
22
|
+
this.matchCaseLabel = 'Match case';
|
|
23
|
+
this.matchesLabel = '{count, plural, =0 {No matches} one {{index} of # match} other {{index} of # matches}}';
|
|
24
|
+
this.nextLabel = 'Next match';
|
|
25
|
+
this.options = 'match-case whole-word regex';
|
|
26
|
+
this.previousLabel = 'Previous match';
|
|
27
|
+
this.query = '';
|
|
28
|
+
this.readOnly = false;
|
|
29
|
+
this.regex = false;
|
|
30
|
+
this.regexLabel = 'Use regular expression';
|
|
31
|
+
this.replaceAllLabel = 'Replace all';
|
|
32
|
+
this.replaceFieldLabel = 'Replace with';
|
|
33
|
+
this.replaceLabel = 'Replace';
|
|
34
|
+
this.replacement = '';
|
|
35
|
+
this.replaceToggleLabel = 'Find and replace';
|
|
36
|
+
this.shortcut = 'mod+f';
|
|
37
|
+
this.skip = '';
|
|
38
|
+
this.wholeWord = false;
|
|
39
|
+
this.wholeWordLabel = 'Match whole word';
|
|
40
|
+
this.result = undefined;
|
|
41
|
+
this.replaceOpen = false;
|
|
42
|
+
this.attached = undefined;
|
|
43
|
+
this.announcement = '';
|
|
44
|
+
this.said = 0;
|
|
45
|
+
this.inside = false;
|
|
46
|
+
this.handleWhere = (event) => {
|
|
47
|
+
this.inside = this.within(event);
|
|
48
|
+
};
|
|
49
|
+
this.handleShortcut = (event) => {
|
|
50
|
+
if (event.defaultPrevented ||
|
|
51
|
+
event.isComposing ||
|
|
52
|
+
this.shortcut === '' ||
|
|
53
|
+
!matchesChord(event, this.shortcut, onApple()) ||
|
|
54
|
+
!(this.inside || this.within(event)) ||
|
|
55
|
+
this.finder === undefined) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
void this.show();
|
|
60
|
+
};
|
|
61
|
+
this.handleInput = (event) => {
|
|
62
|
+
this.query = event.target.value;
|
|
63
|
+
};
|
|
64
|
+
this.handleReplaceInput = (event) => {
|
|
65
|
+
this.replacement = event.target.value;
|
|
66
|
+
};
|
|
67
|
+
this.handleKeys = (event) => {
|
|
68
|
+
if (event.defaultPrevented || event.isComposing) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (event.key === 'Escape') {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
event.stopPropagation();
|
|
74
|
+
this.hide();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (event.key !== 'Enter') {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const origin = event.composedPath()[0];
|
|
81
|
+
if (!(origin instanceof HTMLInputElement)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
if (origin.getAttribute('part') === 'replace-field') {
|
|
86
|
+
this.replace(event.metaKey || event.ctrlKey);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this.search(event.shiftKey ? 'previous' : 'next');
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
static { this.markRules = [MIRROR_RULE]; }
|
|
94
|
+
static { this.words = 'helix-find'; }
|
|
95
|
+
attach(finder) {
|
|
96
|
+
this.endSearch();
|
|
97
|
+
this.attached = finder;
|
|
98
|
+
this.replaceOpen = this.replaceOpen && finder.replace !== undefined;
|
|
99
|
+
if (this.open) {
|
|
100
|
+
queueMicrotask(() => this.search('first'));
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
detach: () => {
|
|
104
|
+
if (this.attached === finder) {
|
|
105
|
+
this.endSearch();
|
|
106
|
+
this.attached = undefined;
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
found: (result) => {
|
|
110
|
+
if (this.attached === finder) {
|
|
111
|
+
this.report(result);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
async show() {
|
|
117
|
+
const active = deepActiveElement();
|
|
118
|
+
if (active !== null && !deepContains(this, active)) {
|
|
119
|
+
this.returnTo = active;
|
|
120
|
+
}
|
|
121
|
+
const selected = this.attached ? '' : this.selectedText();
|
|
122
|
+
if (selected !== '') {
|
|
123
|
+
this.query = selected;
|
|
124
|
+
}
|
|
125
|
+
if (!this.requestOpen(true)) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
await this.updateComplete;
|
|
129
|
+
const field = this.partNamed('field');
|
|
130
|
+
field?.focus();
|
|
131
|
+
field?.select();
|
|
132
|
+
}
|
|
133
|
+
hide() {
|
|
134
|
+
const active = deepActiveElement();
|
|
135
|
+
const focused = active !== null && deepContains(this, active);
|
|
136
|
+
if (!this.requestOpen(false)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const back = this.returnTo;
|
|
140
|
+
this.returnTo = undefined;
|
|
141
|
+
if (focused && back?.isConnected) {
|
|
142
|
+
;
|
|
143
|
+
back.focus();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
next() {
|
|
147
|
+
if (this.open) {
|
|
148
|
+
this.search('next');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
previous() {
|
|
152
|
+
if (this.open) {
|
|
153
|
+
this.search('previous');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
refresh() {
|
|
157
|
+
if (this.open) {
|
|
158
|
+
this.search('first');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
connectedCallback() {
|
|
162
|
+
super.connectedCallback();
|
|
163
|
+
const document = this.ownerDocument;
|
|
164
|
+
document.addEventListener('keydown', this.handleShortcut, true);
|
|
165
|
+
document.addEventListener('pointerdown', this.handleWhere, true);
|
|
166
|
+
document.addEventListener('focusin', this.handleWhere, true);
|
|
167
|
+
}
|
|
168
|
+
disconnectedCallback() {
|
|
169
|
+
super.disconnectedCallback();
|
|
170
|
+
const document = this.ownerDocument;
|
|
171
|
+
document.removeEventListener('keydown', this.handleShortcut, true);
|
|
172
|
+
document.removeEventListener('pointerdown', this.handleWhere, true);
|
|
173
|
+
document.removeEventListener('focusin', this.handleWhere, true);
|
|
174
|
+
this.endSearch();
|
|
175
|
+
}
|
|
176
|
+
firstUpdated(changed) {
|
|
177
|
+
super.firstUpdated(changed);
|
|
178
|
+
this.finishHydration();
|
|
179
|
+
}
|
|
180
|
+
willUpdate(changed) {
|
|
181
|
+
super.willUpdate(changed);
|
|
182
|
+
this.toggleState('replace-open', this.replacing);
|
|
183
|
+
}
|
|
184
|
+
updated(changed) {
|
|
185
|
+
super.updated(changed);
|
|
186
|
+
if (!this.open) {
|
|
187
|
+
if (changed.has('open')) {
|
|
188
|
+
this.endSearch();
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (SEARCHED.some((name) => changed.has(name))) {
|
|
193
|
+
queueMicrotask(() => this.search('first'));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
get target() {
|
|
197
|
+
return this.for === '' ? null : elementById(this, this.for);
|
|
198
|
+
}
|
|
199
|
+
get finder() {
|
|
200
|
+
if (this.attached) {
|
|
201
|
+
return this.attached;
|
|
202
|
+
}
|
|
203
|
+
const root = this.target;
|
|
204
|
+
if (root === null) {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
if (this.own?.root !== root || this.own.skip !== this.skip) {
|
|
208
|
+
this.own?.finder.end();
|
|
209
|
+
this.own = {
|
|
210
|
+
finder: textFinder(root, { found: (result) => this.report(result), skip: this.skip }),
|
|
211
|
+
root,
|
|
212
|
+
skip: this.skip,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return this.own.finder;
|
|
216
|
+
}
|
|
217
|
+
get findQuery() {
|
|
218
|
+
return {
|
|
219
|
+
caseSensitive: this.matchCase,
|
|
220
|
+
regex: this.regex,
|
|
221
|
+
replace: this.replacement,
|
|
222
|
+
search: this.query,
|
|
223
|
+
wholeWord: this.wholeWord,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
get readable() {
|
|
227
|
+
return this.query === '' || findPattern(this.findQuery) !== undefined;
|
|
228
|
+
}
|
|
229
|
+
get replaceable() {
|
|
230
|
+
return !this.hydrating && !this.readOnly && this.attached?.replace !== undefined;
|
|
231
|
+
}
|
|
232
|
+
get replacing() {
|
|
233
|
+
return this.replaceOpen && this.replaceable;
|
|
234
|
+
}
|
|
235
|
+
get countText() {
|
|
236
|
+
if (!this.readable) {
|
|
237
|
+
return this.invalidLabel;
|
|
238
|
+
}
|
|
239
|
+
return this.result === undefined
|
|
240
|
+
? ''
|
|
241
|
+
: formatWords(this, 'matchesLabel', {
|
|
242
|
+
count: this.result.count,
|
|
243
|
+
index: Math.max(this.result.index, 0) + 1,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
offers(option) {
|
|
247
|
+
return this.options.split(/\s+/).includes(option);
|
|
248
|
+
}
|
|
249
|
+
selectedText() {
|
|
250
|
+
const selection = this.ownerDocument.getSelection?.();
|
|
251
|
+
const root = this.target;
|
|
252
|
+
const text = selection?.toString() ?? '';
|
|
253
|
+
const anchor = selection?.anchorNode ?? null;
|
|
254
|
+
return root !== null &&
|
|
255
|
+
anchor !== null &&
|
|
256
|
+
root.contains(anchor) &&
|
|
257
|
+
text.trim() !== '' &&
|
|
258
|
+
!/[\r\n]/.test(text)
|
|
259
|
+
? text
|
|
260
|
+
: '';
|
|
261
|
+
}
|
|
262
|
+
search(direction) {
|
|
263
|
+
const finder = this.finder;
|
|
264
|
+
if (!finder) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (this.marking !== finder) {
|
|
268
|
+
this.endSearch();
|
|
269
|
+
}
|
|
270
|
+
if (this.query === '' || !this.readable) {
|
|
271
|
+
this.endSearch();
|
|
272
|
+
if (!this.readable) {
|
|
273
|
+
this.say(this.invalidLabel);
|
|
274
|
+
}
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
this.marking = finder;
|
|
278
|
+
const result = finder.find(this.findQuery, direction);
|
|
279
|
+
if (result) {
|
|
280
|
+
this.report(result);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
endSearch() {
|
|
284
|
+
this.marking?.end();
|
|
285
|
+
this.marking = undefined;
|
|
286
|
+
this.result = undefined;
|
|
287
|
+
}
|
|
288
|
+
report(result) {
|
|
289
|
+
if (!this.open) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
this.result = result;
|
|
293
|
+
this.say(this.countText);
|
|
294
|
+
this.dispatchEvent(new HelixFoundEvent({ count: result.count, index: result.index }));
|
|
295
|
+
}
|
|
296
|
+
replace(all) {
|
|
297
|
+
const finder = this.finder;
|
|
298
|
+
if (!finder?.replace || this.readOnly || this.query === '' || !this.readable) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const result = finder.replace(this.findQuery, all);
|
|
302
|
+
if (result) {
|
|
303
|
+
this.report(result);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
say(text) {
|
|
307
|
+
this.announcement = text;
|
|
308
|
+
this.said += 1;
|
|
309
|
+
}
|
|
310
|
+
within(event) {
|
|
311
|
+
const path = event.composedPath();
|
|
312
|
+
const root = this.target;
|
|
313
|
+
return path.includes(this) || (root !== null && path.includes(root));
|
|
314
|
+
}
|
|
315
|
+
toggleOption(option) {
|
|
316
|
+
this[option] = !this[option];
|
|
317
|
+
}
|
|
318
|
+
renderReplaceToggle() {
|
|
319
|
+
if (!this.replaceable) {
|
|
320
|
+
return nothing;
|
|
321
|
+
}
|
|
322
|
+
const button = this.tag('icon-button');
|
|
323
|
+
return html `<${button}
|
|
324
|
+
part="replace-toggle"
|
|
325
|
+
exportparts="button: replace-toggle-button, live: replace-toggle-live, spinner: replace-toggle-spinner, text: replace-toggle-text"
|
|
326
|
+
.expanded=${this.replacing}
|
|
327
|
+
label=${this.replaceToggleLabel}
|
|
328
|
+
@click=${() => {
|
|
329
|
+
this.replaceOpen = !this.replaceOpen;
|
|
330
|
+
}}
|
|
331
|
+
@helix-press=${stopPress}
|
|
332
|
+
>
|
|
333
|
+
${this.replacing ? drawIcon(caretDown) : html `<span data-mirror>${drawIcon(caretRight)}</span>`}
|
|
334
|
+
</${button}>`;
|
|
335
|
+
}
|
|
336
|
+
renderOptionButtons() {
|
|
337
|
+
const button = this.tag('icon-button');
|
|
338
|
+
return html `${this.offers('match-case')
|
|
339
|
+
? html `<${button}
|
|
340
|
+
part="match-case${this.matchCase ? ' match-case-pressed' : ''}"
|
|
341
|
+
exportparts="button: match-case-button, live: match-case-live, spinner: match-case-spinner, text: match-case-text"
|
|
342
|
+
aria-pressed=${this.matchCase ? 'true' : 'false'}
|
|
343
|
+
label=${this.matchCaseLabel}
|
|
344
|
+
@click=${() => this.toggleOption('matchCase')}
|
|
345
|
+
@helix-press=${stopPress}
|
|
346
|
+
>
|
|
347
|
+
<slot name="match-case-icon">${drawIcon(textAa)}</slot>
|
|
348
|
+
</${button}>`
|
|
349
|
+
: nothing}${this.offers('whole-word')
|
|
350
|
+
? html `<${button}
|
|
351
|
+
part="whole-word${this.wholeWord ? ' whole-word-pressed' : ''}"
|
|
352
|
+
exportparts="button: whole-word-button, live: whole-word-live, spinner: whole-word-spinner, text: whole-word-text"
|
|
353
|
+
aria-pressed=${this.wholeWord ? 'true' : 'false'}
|
|
354
|
+
label=${this.wholeWordLabel}
|
|
355
|
+
@click=${() => this.toggleOption('wholeWord')}
|
|
356
|
+
@helix-press=${stopPress}
|
|
357
|
+
>
|
|
358
|
+
<slot name="whole-word-icon">${drawIcon(textAUnderline)}</slot>
|
|
359
|
+
</${button}>`
|
|
360
|
+
: nothing}${this.offers('regex')
|
|
361
|
+
? html `<${button}
|
|
362
|
+
part="regex${this.regex ? ' regex-pressed' : ''}"
|
|
363
|
+
exportparts="button: regex-button, live: regex-live, spinner: regex-spinner, text: regex-text"
|
|
364
|
+
aria-pressed=${this.regex ? 'true' : 'false'}
|
|
365
|
+
label=${this.regexLabel}
|
|
366
|
+
@click=${() => this.toggleOption('regex')}
|
|
367
|
+
@helix-press=${stopPress}
|
|
368
|
+
>
|
|
369
|
+
<slot name="regex-icon">${drawIcon(asterisk)}</slot>
|
|
370
|
+
</${button}>`
|
|
371
|
+
: nothing}`;
|
|
372
|
+
}
|
|
373
|
+
renderControls() {
|
|
374
|
+
const toolbar = this.tag('toolbar');
|
|
375
|
+
const button = this.tag('icon-button');
|
|
376
|
+
const searchable = this.readable && (this.result?.count ?? 0) > 0;
|
|
377
|
+
return html `<${toolbar} part="controls" exportparts="toolbar: controls-toolbar" label=${this.controlsLabel}>
|
|
378
|
+
${this.renderOptionButtons()}
|
|
379
|
+
<slot name="actions" part="actions"></slot>
|
|
380
|
+
<${button}
|
|
381
|
+
part="previous"
|
|
382
|
+
exportparts="button: previous-button, live: previous-live, spinner: previous-spinner, text: previous-text"
|
|
383
|
+
?disabled=${!searchable}
|
|
384
|
+
label=${this.previousLabel}
|
|
385
|
+
@click=${() => this.search('previous')}
|
|
386
|
+
@helix-press=${stopPress}
|
|
387
|
+
>
|
|
388
|
+
<slot name="previous-icon">${drawIcon(caretUp)}</slot>
|
|
389
|
+
</${button}>
|
|
390
|
+
<${button}
|
|
391
|
+
part="next"
|
|
392
|
+
exportparts="button: next-button, live: next-live, spinner: next-spinner, text: next-text"
|
|
393
|
+
?disabled=${!searchable}
|
|
394
|
+
label=${this.nextLabel}
|
|
395
|
+
@click=${() => this.search('next')}
|
|
396
|
+
@helix-press=${stopPress}
|
|
397
|
+
>
|
|
398
|
+
<slot name="next-icon">${drawIcon(caretDown)}</slot>
|
|
399
|
+
</${button}>
|
|
400
|
+
<${button}
|
|
401
|
+
part="close"
|
|
402
|
+
exportparts="button: close-button, live: close-live, spinner: close-spinner, text: close-text"
|
|
403
|
+
label=${this.closeLabel}
|
|
404
|
+
@click=${() => this.hide()}
|
|
405
|
+
@helix-press=${stopPress}
|
|
406
|
+
>
|
|
407
|
+
<slot name="close-icon">${drawIcon(x)}</slot>
|
|
408
|
+
</${button}>
|
|
409
|
+
</${toolbar}>`;
|
|
410
|
+
}
|
|
411
|
+
renderReplace() {
|
|
412
|
+
if (!this.replacing) {
|
|
413
|
+
return nothing;
|
|
414
|
+
}
|
|
415
|
+
const button = this.tag('button');
|
|
416
|
+
const searchable = this.readable && (this.result?.count ?? 0) > 0;
|
|
417
|
+
return html `<input
|
|
418
|
+
part="replace-field"
|
|
419
|
+
aria-label=${this.replaceFieldLabel}
|
|
420
|
+
autocomplete="off"
|
|
421
|
+
placeholder=${this.replaceFieldLabel}
|
|
422
|
+
spellcheck="false"
|
|
423
|
+
type="text"
|
|
424
|
+
.value=${live(this.replacement)}
|
|
425
|
+
@input=${this.handleReplaceInput}
|
|
426
|
+
/>
|
|
427
|
+
<${button}
|
|
428
|
+
part="replace"
|
|
429
|
+
exportparts="button: replace-button, live: replace-live, spinner: replace-spinner, text: replace-text"
|
|
430
|
+
?disabled=${!searchable}
|
|
431
|
+
@click=${() => this.replace(false)}
|
|
432
|
+
@helix-press=${stopPress}
|
|
433
|
+
>
|
|
434
|
+
${this.replaceLabel}
|
|
435
|
+
</${button}>
|
|
436
|
+
<${button}
|
|
437
|
+
part="replace-all"
|
|
438
|
+
exportparts="button: replace-all-button, live: replace-all-live, spinner: replace-all-spinner, text: replace-all-text"
|
|
439
|
+
?disabled=${!searchable}
|
|
440
|
+
@click=${() => this.replace(true)}
|
|
441
|
+
@helix-press=${stopPress}
|
|
442
|
+
>
|
|
443
|
+
${this.replaceAllLabel}
|
|
444
|
+
</${button}>`;
|
|
445
|
+
}
|
|
446
|
+
render() {
|
|
447
|
+
return html `<div
|
|
448
|
+
part="bar"
|
|
449
|
+
role="search"
|
|
450
|
+
aria-label=${this.label}
|
|
451
|
+
?hidden=${!this.open}
|
|
452
|
+
@keydown=${this.handleKeys}
|
|
453
|
+
>
|
|
454
|
+
${this.renderReplaceToggle()}
|
|
455
|
+
<input
|
|
456
|
+
part="field"
|
|
457
|
+
aria-invalid=${this.readable ? nothing : 'true'}
|
|
458
|
+
aria-label=${this.label}
|
|
459
|
+
autocomplete="off"
|
|
460
|
+
placeholder=${this.label}
|
|
461
|
+
spellcheck="false"
|
|
462
|
+
type="search"
|
|
463
|
+
.value=${live(this.query)}
|
|
464
|
+
@input=${this.handleInput}
|
|
465
|
+
/>
|
|
466
|
+
<span part="count" aria-hidden="true">${this.countText || nothing}</span>
|
|
467
|
+
${this.renderControls()}
|
|
468
|
+
${this.renderReplace()}
|
|
469
|
+
</div>
|
|
470
|
+
<span part="live" role="status">${keyed(this.said, this.announcement)}</span>`;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
__decorate([
|
|
474
|
+
words,
|
|
475
|
+
property({ attribute: 'close-label' })
|
|
476
|
+
], HelixHeadlessFind.prototype, "closeLabel", void 0);
|
|
477
|
+
__decorate([
|
|
478
|
+
words,
|
|
479
|
+
property({ attribute: 'controls-label' })
|
|
480
|
+
], HelixHeadlessFind.prototype, "controlsLabel", void 0);
|
|
481
|
+
__decorate([
|
|
482
|
+
property()
|
|
483
|
+
], HelixHeadlessFind.prototype, "for", void 0);
|
|
484
|
+
__decorate([
|
|
485
|
+
words,
|
|
486
|
+
property({ attribute: 'invalid-label' })
|
|
487
|
+
], HelixHeadlessFind.prototype, "invalidLabel", void 0);
|
|
488
|
+
__decorate([
|
|
489
|
+
words,
|
|
490
|
+
property()
|
|
491
|
+
], HelixHeadlessFind.prototype, "label", void 0);
|
|
492
|
+
__decorate([
|
|
493
|
+
property({ attribute: 'match-case', type: Boolean })
|
|
494
|
+
], HelixHeadlessFind.prototype, "matchCase", void 0);
|
|
495
|
+
__decorate([
|
|
496
|
+
words,
|
|
497
|
+
property({ attribute: 'match-case-label' })
|
|
498
|
+
], HelixHeadlessFind.prototype, "matchCaseLabel", void 0);
|
|
499
|
+
__decorate([
|
|
500
|
+
words,
|
|
501
|
+
property({ attribute: 'matches-label' })
|
|
502
|
+
], HelixHeadlessFind.prototype, "matchesLabel", void 0);
|
|
503
|
+
__decorate([
|
|
504
|
+
words,
|
|
505
|
+
property({ attribute: 'next-label' })
|
|
506
|
+
], HelixHeadlessFind.prototype, "nextLabel", void 0);
|
|
507
|
+
__decorate([
|
|
508
|
+
property()
|
|
509
|
+
], HelixHeadlessFind.prototype, "options", void 0);
|
|
510
|
+
__decorate([
|
|
511
|
+
words,
|
|
512
|
+
property({ attribute: 'previous-label' })
|
|
513
|
+
], HelixHeadlessFind.prototype, "previousLabel", void 0);
|
|
514
|
+
__decorate([
|
|
515
|
+
property()
|
|
516
|
+
], HelixHeadlessFind.prototype, "query", void 0);
|
|
517
|
+
__decorate([
|
|
518
|
+
property({ attribute: 'readonly', type: Boolean })
|
|
519
|
+
], HelixHeadlessFind.prototype, "readOnly", void 0);
|
|
520
|
+
__decorate([
|
|
521
|
+
property({ type: Boolean })
|
|
522
|
+
], HelixHeadlessFind.prototype, "regex", void 0);
|
|
523
|
+
__decorate([
|
|
524
|
+
words,
|
|
525
|
+
property({ attribute: 'regex-label' })
|
|
526
|
+
], HelixHeadlessFind.prototype, "regexLabel", void 0);
|
|
527
|
+
__decorate([
|
|
528
|
+
words,
|
|
529
|
+
property({ attribute: 'replace-all-label' })
|
|
530
|
+
], HelixHeadlessFind.prototype, "replaceAllLabel", void 0);
|
|
531
|
+
__decorate([
|
|
532
|
+
words,
|
|
533
|
+
property({ attribute: 'replace-field-label' })
|
|
534
|
+
], HelixHeadlessFind.prototype, "replaceFieldLabel", void 0);
|
|
535
|
+
__decorate([
|
|
536
|
+
words,
|
|
537
|
+
property({ attribute: 'replace-label' })
|
|
538
|
+
], HelixHeadlessFind.prototype, "replaceLabel", void 0);
|
|
539
|
+
__decorate([
|
|
540
|
+
property()
|
|
541
|
+
], HelixHeadlessFind.prototype, "replacement", void 0);
|
|
542
|
+
__decorate([
|
|
543
|
+
words,
|
|
544
|
+
property({ attribute: 'replace-toggle-label' })
|
|
545
|
+
], HelixHeadlessFind.prototype, "replaceToggleLabel", void 0);
|
|
546
|
+
__decorate([
|
|
547
|
+
property()
|
|
548
|
+
], HelixHeadlessFind.prototype, "shortcut", void 0);
|
|
549
|
+
__decorate([
|
|
550
|
+
property()
|
|
551
|
+
], HelixHeadlessFind.prototype, "skip", void 0);
|
|
552
|
+
__decorate([
|
|
553
|
+
property({ attribute: 'whole-word', type: Boolean })
|
|
554
|
+
], HelixHeadlessFind.prototype, "wholeWord", void 0);
|
|
555
|
+
__decorate([
|
|
556
|
+
words,
|
|
557
|
+
property({ attribute: 'whole-word-label' })
|
|
558
|
+
], HelixHeadlessFind.prototype, "wholeWordLabel", void 0);
|
|
559
|
+
__decorate([
|
|
560
|
+
state()
|
|
561
|
+
], HelixHeadlessFind.prototype, "result", void 0);
|
|
562
|
+
__decorate([
|
|
563
|
+
state()
|
|
564
|
+
], HelixHeadlessFind.prototype, "replaceOpen", void 0);
|
|
565
|
+
__decorate([
|
|
566
|
+
state()
|
|
567
|
+
], HelixHeadlessFind.prototype, "attached", void 0);
|
|
568
|
+
__decorate([
|
|
569
|
+
state()
|
|
570
|
+
], HelixHeadlessFind.prototype, "announcement", void 0);
|
|
571
|
+
__decorate([
|
|
572
|
+
state()
|
|
573
|
+
], HelixHeadlessFind.prototype, "said", void 0);
|
|
574
|
+
HelixHeadlessFind = __decorate([
|
|
575
|
+
customElement('helix-headless-find')
|
|
576
|
+
], HelixHeadlessFind);
|
|
577
|
+
export { HelixHeadlessFind };
|
package/dist/index.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ export * from './empty/index.js';
|
|
|
50
50
|
export * from './file-input/index.js';
|
|
51
51
|
export * from './filter-input/index.js';
|
|
52
52
|
export * from './filter-input/menu/index.js';
|
|
53
|
+
export * from './find/index.js';
|
|
53
54
|
export * from './format-date/index.js';
|
|
54
55
|
export * from './graph/index.js';
|
|
55
56
|
export * from './heatmap/index.js';
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ export * from './empty/index.js';
|
|
|
41
41
|
export * from './file-input/index.js';
|
|
42
42
|
export * from './filter-input/index.js';
|
|
43
43
|
export * from './filter-input/menu/index.js';
|
|
44
|
+
export * from './find/index.js';
|
|
44
45
|
export * from './format-date/index.js';
|
|
45
46
|
export * from './graph/index.js';
|
|
46
47
|
export * from './heatmap/index.js';
|
|
@@ -15,7 +15,9 @@ declare const HelixHeadlessLogGroup_base: (new (...args: any[]) => import("@fusi
|
|
|
15
15
|
* the heading, as you write it, such as `12s`.
|
|
16
16
|
*
|
|
17
17
|
* A group starts shut. Write `default-open` on the step a reader should see,
|
|
18
|
-
* such as the one that failed.
|
|
18
|
+
* such as the one that failed. A shut group's lines are hidden until found:
|
|
19
|
+
* the browser's find and Find search them, and the group opens on the one
|
|
20
|
+
* that holds the match, unless `helix-before-open` is canceled.
|
|
19
21
|
*
|
|
20
22
|
* @since 0.200.0
|
|
21
23
|
* @status experimental
|
|
@@ -28,7 +30,7 @@ declare const HelixHeadlessLogGroup_base: (new (...args: any[]) => import("@fusi
|
|
|
28
30
|
* @event {HelixBeforeOpenEvent} helix-before-open - Fired before the group opens. Cancelable.
|
|
29
31
|
* @event {ToggleEvent} toggle - Fired after the group opens or closes, with `newState` and `oldState`.
|
|
30
32
|
*
|
|
31
|
-
* @csspart content - The lines, hidden while the group is shut.
|
|
33
|
+
* @csspart content - The lines, hidden until found while the group is shut.
|
|
32
34
|
* @csspart duration - How long the step took.
|
|
33
35
|
* @csspart heading - The heading.
|
|
34
36
|
* @csspart mark - The caret that turns as the group opens, an `<svg>` you size.
|
|
@@ -65,6 +67,13 @@ export declare class HelixHeadlessLogGroup extends HelixHeadlessLogGroup_base {
|
|
|
65
67
|
*/
|
|
66
68
|
statusLabel: string;
|
|
67
69
|
private readonly handlePress;
|
|
70
|
+
/**
|
|
71
|
+
* A search found a match in the shut group, and shows it next: the
|
|
72
|
+
* browser's find or Find. The group opens, and where the page refuses, its
|
|
73
|
+
* lines are hidden again once the search has shown them, as Accordion's
|
|
74
|
+
* section is.
|
|
75
|
+
*/
|
|
76
|
+
private readonly handleBeforeMatch;
|
|
68
77
|
/** Records whether the group holds anything, and whether a step is among it. */
|
|
69
78
|
private readonly handleSlotChange;
|
|
70
79
|
/** A slot that is never filled fires no `slotchange`, so the first render reads it once. */
|
|
@@ -22,6 +22,19 @@ let HelixHeadlessLogGroup = class HelixHeadlessLogGroup extends MixinControllerO
|
|
|
22
22
|
this.handlePress = () => {
|
|
23
23
|
this.toggleOpen();
|
|
24
24
|
};
|
|
25
|
+
this.handleBeforeMatch = (event) => {
|
|
26
|
+
if (this.open || this.requestOpen(true)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const content = event.currentTarget;
|
|
30
|
+
const observer = new MutationObserver(() => {
|
|
31
|
+
observer.disconnect();
|
|
32
|
+
if (!this.open && !content.hasAttribute('hidden')) {
|
|
33
|
+
content.setAttribute('hidden', 'until-found');
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
observer.observe(content, { attributeFilter: ['hidden'] });
|
|
37
|
+
};
|
|
25
38
|
this.handleSlotChange = () => {
|
|
26
39
|
const slot = this.renderRoot.querySelector('[part="content"] > slot');
|
|
27
40
|
if (!slot) {
|
|
@@ -61,9 +74,10 @@ let HelixHeadlessLogGroup = class HelixHeadlessLogGroup extends MixinControllerO
|
|
|
61
74
|
: html `<div
|
|
62
75
|
part="content"
|
|
63
76
|
id="content"
|
|
64
|
-
role
|
|
65
|
-
aria-labelledby
|
|
66
|
-
|
|
77
|
+
role=${this.open ? 'group' : nothing}
|
|
78
|
+
aria-labelledby=${this.open ? 'summary' : nothing}
|
|
79
|
+
hidden=${this.open ? nothing : 'until-found'}
|
|
80
|
+
@beforematch=${this.handleBeforeMatch}
|
|
67
81
|
><slot @slotchange=${this.handleSlotChange}></slot></div>`}`;
|
|
68
82
|
}
|
|
69
83
|
};
|