@fusion.dev/helix-headless 0.165.0 → 0.166.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/custom-elements.json +578 -54
- package/dist/callout/root/callout-root.d.ts +8 -2
- package/dist/callout/root/callout-root.js +14 -1
- package/dist/code-block/root/code-block-root.d.ts +63 -0
- package/dist/code-block/root/code-block-root.js +117 -6
- package/dist/element-events.generated.js +15 -2
- package/dist/filter-input/menu/filter-menu.d.ts +1 -0
- package/dist/filter-input/menu/filter-menu.js +1 -1
- package/dist/listbox/root/listbox-root.js +2 -5
- package/dist/menu/item/menu-item.d.ts +20 -0
- package/dist/menu/item/menu-item.js +53 -20
- package/dist/menu/root/menu-root.d.ts +84 -1
- package/dist/menu/root/menu-root.js +187 -44
- package/dist/object-inspector/root/object-inspector-root.d.ts +5 -0
- package/dist/object-inspector/root/object-inspector-root.js +5 -0
- package/dist/steps/root/steps-root.d.ts +7 -0
- package/dist/steps/root/steps-root.js +7 -0
- package/dist/video/root/video-root.d.ts +2 -0
- package/dist/video/root/video-root.js +4 -2
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +1 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +1 -1
- package/dist/video-playlist/root/video-playlist-root.js +15 -1
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +262 -20
- package/types/vue.d.ts +59 -5
- package/types/words.d.ts +18 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
1
|
+
import { type HelixDismissEvent, HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
+
import { type CSSResultGroup, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
declare const HelixHeadlessCallout_base: (new (...args: any[]) => import("@fusion.dev/helix-core").DismissibleElement) & typeof HelixElement;
|
|
4
4
|
/**
|
|
5
5
|
* @summary A passage set apart as a note, information, a warning, or an error.
|
|
@@ -52,6 +52,7 @@ declare const HelixHeadlessCallout_base: (new (...args: any[]) => import("@fusio
|
|
|
52
52
|
* @cssstate has-icon - An icon of your own is slotted into `icon`, in place of the tone's.
|
|
53
53
|
*/
|
|
54
54
|
export declare class HelixHeadlessCallout extends HelixHeadlessCallout_base {
|
|
55
|
+
static styles: CSSResultGroup;
|
|
55
56
|
/**
|
|
56
57
|
* The key this family's words are registered under, its styled tag:
|
|
57
58
|
* `registerWords('de', { 'helix-callout': { toneLabels: { danger: 'Fehler' } } })`.
|
|
@@ -141,6 +142,11 @@ export declare class HelixHeadlessCallout extends HelixHeadlessCallout_base {
|
|
|
141
142
|
* heading.
|
|
142
143
|
*/
|
|
143
144
|
private dismissName;
|
|
145
|
+
/**
|
|
146
|
+
* The event a dismissal sends, naming the note by its heading where it has
|
|
147
|
+
* one, the words its dismiss button is named by, and otherwise by its text.
|
|
148
|
+
*/
|
|
149
|
+
protected dismissEvent(): HelixDismissEvent;
|
|
144
150
|
protected firstUpdated(changed: PropertyValues): void;
|
|
145
151
|
protected updated(changed: PropertyValues): void;
|
|
146
152
|
/**
|
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { animationsSettled, customElement, drawDismiss, drawDismissGlyph, formatWords, HelixElement, hostAria, MixinDismissible, slottedWords, TONE_MARKS, toneMark, words, wordsConverter, } from '@fusion.dev/helix-core';
|
|
8
|
-
import { html, nothing } from 'lit';
|
|
8
|
+
import { css, html, nothing, } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
11
11
|
let HelixHeadlessCallout = class HelixHeadlessCallout extends MixinDismissible(HelixElement) {
|
|
@@ -32,6 +32,11 @@ let HelixHeadlessCallout = class HelixHeadlessCallout extends MixinDismissible(H
|
|
|
32
32
|
this.toggleState('has-icon', filled('icon'));
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
+
static { this.styles = css `
|
|
36
|
+
:host {
|
|
37
|
+
display: block;
|
|
38
|
+
}
|
|
39
|
+
`; }
|
|
35
40
|
static { this.words = 'helix-callout'; }
|
|
36
41
|
get present() {
|
|
37
42
|
return this.isConnected && !this.hasAttribute('hidden');
|
|
@@ -66,6 +71,14 @@ let HelixHeadlessCallout = class HelixHeadlessCallout extends MixinDismissible(H
|
|
|
66
71
|
? formatWords(this, 'dismissLabel', { label: heading || tone }).trim()
|
|
67
72
|
: this.dismissLabel;
|
|
68
73
|
}
|
|
74
|
+
dismissEvent() {
|
|
75
|
+
const event = super.dismissEvent();
|
|
76
|
+
const heading = slottedWords(this, ['heading']);
|
|
77
|
+
if (heading) {
|
|
78
|
+
event.detail.label = heading;
|
|
79
|
+
}
|
|
80
|
+
return event;
|
|
81
|
+
}
|
|
69
82
|
firstUpdated(changed) {
|
|
70
83
|
super.firstUpdated(changed);
|
|
71
84
|
this.finishHydration();
|
|
@@ -71,6 +71,18 @@ import '../../copy-button/index.js';
|
|
|
71
71
|
* keeps hydration clean, and draws the diff once it can read the content. Diff
|
|
72
72
|
* mode is experimental. The rest of the family is stable.
|
|
73
73
|
*
|
|
74
|
+
* **Several blocks are files**, one shown at a time under a row of tabs, as
|
|
75
|
+
* Sandbox shows its source panes. Put Code Blocks in the default slot of a
|
|
76
|
+
* Code Block, and each is a file named on its tab by its `label` or, without
|
|
77
|
+
* one, its `language`. `file` holds the name of the file shown. The tabs are a
|
|
78
|
+
* tab list: the arrow keys move to a tab and show its file, the two swapping
|
|
79
|
+
* on a right-to-left page, and Home and End go to the first and the last.
|
|
80
|
+
* Choosing one sends `helix-before-change` with the file's name, which you can
|
|
81
|
+
* cancel, and `change` once `file` holds it. The files not shown carry
|
|
82
|
+
* `hidden`, and the one shown draws no name of its own, its tab naming it. One
|
|
83
|
+
* block draws no tabs. A server cannot see the blocks inside, so the client
|
|
84
|
+
* draws the tabs once it upgrades.
|
|
85
|
+
*
|
|
74
86
|
* @since 0.1.0
|
|
75
87
|
* @status stable
|
|
76
88
|
* @category typography
|
|
@@ -82,7 +94,11 @@ import '../../copy-button/index.js';
|
|
|
82
94
|
* @slot copied-icon - The copy button's icon after a copy. Defaults to a check mark.
|
|
83
95
|
* @slot copy-icon - The copy button's icon before a copy. Defaults to a clipboard.
|
|
84
96
|
*
|
|
97
|
+
* @event {Event} change - A file tab showed its file, whose name `file` now holds.
|
|
98
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - A file tab is about to show its file, with the file's name in `detail.value`. Cancelable: cancel it to keep the file shown.
|
|
85
99
|
* @event {HelixBeforeToggleEvent} helix-before-toggle - The wrap button was pressed, with the `wrap` it asks for in `detail.checked`. Cancelable: cancel it to keep the lines as they are.
|
|
100
|
+
* @event {HelixCopyEvent} helix-copy - The copy button put the code on the clipboard, with the text in `detail.value`.
|
|
101
|
+
* @event {HelixCopyErrorEvent} helix-copy-error - A press on the copy button put nothing on the clipboard: the browser did not allow the write, or there was no code.
|
|
86
102
|
* @event {HelixToggleEvent} helix-toggle - Fired after the wrap button changed `wrap`, with the new value in `detail.checked`.
|
|
87
103
|
*
|
|
88
104
|
* @csspart actions - The box in the header that holds the `actions` slot, drawn while something is slotted there.
|
|
@@ -109,6 +125,8 @@ import '../../copy-button/index.js';
|
|
|
109
125
|
* @csspart copy-tooltip-top - The tooltip while it is above the copy button. Applied with `copy-tooltip`.
|
|
110
126
|
* @csspart expand - The button under a capped block that shows every line, and fewer again. Drawn when `expandable` is set and the cap hides something.
|
|
111
127
|
* @csspart file - In a diff, one file's header and block.
|
|
128
|
+
* @csspart file-tab - One file tab, `aria-selected` while its file is shown.
|
|
129
|
+
* @csspart files - The file tabs over the blocks a block holds, where there are several.
|
|
112
130
|
* @csspart filler - In a split diff, the empty row opposite a line the other side does not have.
|
|
113
131
|
* @csspart fold - In a diff with `context-lines`, the button that shows a folded run of unchanged lines, and hides it again, saying which with `aria-expanded`.
|
|
114
132
|
* @csspart frame - The code, and the copy button beside it where there is no header.
|
|
@@ -132,6 +150,7 @@ import '../../copy-button/index.js';
|
|
|
132
150
|
* @cssproperty --code-block-mark-start - Written by the block on each `mark`: how far down the code its run of lines starts. Do not set it.
|
|
133
151
|
*
|
|
134
152
|
* @cssstate expanded - The expand button has shown every line of a capped block.
|
|
153
|
+
* @cssstate tabbed - The block is one of several files under another block's tabs, which name it, so it draws no name of its own.
|
|
135
154
|
*/
|
|
136
155
|
export declare class HelixHeadlessCodeBlock extends HelixElement {
|
|
137
156
|
/**
|
|
@@ -198,6 +217,17 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
198
217
|
* The expand button's words while the cap hides lines.
|
|
199
218
|
*/
|
|
200
219
|
expandLabel: string;
|
|
220
|
+
/**
|
|
221
|
+
* The name of the file shown, where the block holds several Code Blocks:
|
|
222
|
+
* the `label` of one, or its `language` without one.
|
|
223
|
+
*
|
|
224
|
+
* Unset, or a name no file has, shows the first.
|
|
225
|
+
*/
|
|
226
|
+
file?: string;
|
|
227
|
+
/**
|
|
228
|
+
* The name of the file tabs, read by screen readers.
|
|
229
|
+
*/
|
|
230
|
+
filesLabel: string;
|
|
201
231
|
/**
|
|
202
232
|
* The words of a button that hides a run of unchanged lines it showed, in a
|
|
203
233
|
* diff with `context-lines`. `{count}` is how many, and each language
|
|
@@ -395,6 +425,39 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
395
425
|
* block computed and CSS cannot, and no render follows from them.
|
|
396
426
|
*/
|
|
397
427
|
private placeLines;
|
|
428
|
+
/** The Code Blocks this block holds as its code, once its children can be read. */
|
|
429
|
+
private get blocks();
|
|
430
|
+
/**
|
|
431
|
+
* Whether the block is one of several files under another block's tabs,
|
|
432
|
+
* which name it. Read from the parent, so a block needs no telling.
|
|
433
|
+
*/
|
|
434
|
+
private get tabbed();
|
|
435
|
+
/** The file shown among several: the one `file` names, or the first. */
|
|
436
|
+
private shownFile;
|
|
437
|
+
/** Shows the file a tab names, once nobody refused. */
|
|
438
|
+
private chooseFile;
|
|
439
|
+
/**
|
|
440
|
+
* Arrow keys, `Home` and `End` on the file tabs, which move to a tab and
|
|
441
|
+
* show its file, as a tab list that follows focus does and as Sandbox's file
|
|
442
|
+
* tabs do. Left and Right swap on a right-to-left page.
|
|
443
|
+
*/
|
|
444
|
+
private readonly handleFileKey;
|
|
445
|
+
/** The blocks this element hid, to show them again. */
|
|
446
|
+
private readonly hid;
|
|
447
|
+
/** How many files the block last held, so each is told when that changes. */
|
|
448
|
+
private fileCount;
|
|
449
|
+
/**
|
|
450
|
+
* Hides the files not shown, shows any this element hid that is now, and
|
|
451
|
+
* tells each file when how many there are changes, since a file draws its
|
|
452
|
+
* own name only while it is alone.
|
|
453
|
+
*/
|
|
454
|
+
private showFile;
|
|
455
|
+
/**
|
|
456
|
+
* The tabs over several files, and the file shown under them. One file
|
|
457
|
+
* draws no tabs, only itself.
|
|
458
|
+
*/
|
|
459
|
+
private renderFiles;
|
|
460
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
398
461
|
protected updated(changed: PropertyValues): void;
|
|
399
462
|
connectedCallback(): void;
|
|
400
463
|
disconnectedCallback(): void;
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, formatWords, HelixBeforeToggleEvent, HelixElement, HelixToggleEvent, requestChange, words, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, formatWords, HelixBeforeToggleEvent, HelixElement, HelixToggleEvent, inlineStep, requestChange, requestValue, words, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
10
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
@@ -13,6 +13,17 @@ import '../../copy-button/index.js';
|
|
|
13
13
|
import { highlightedLines } from '../highlight.js';
|
|
14
14
|
import { gutterNumbers, lineCount, lineRuns, lineSpans } from '../lines.js';
|
|
15
15
|
import { foldContext, pairLines, parsePatch, } from '../patch.js';
|
|
16
|
+
const stopPress = (event) => event.stopPropagation();
|
|
17
|
+
const isBlock = (element) => element?.localName.endsWith('code-block') === true;
|
|
18
|
+
const blocksIn = (host) => [...host.children].filter((child) => child.slot === '' && isBlock(child));
|
|
19
|
+
const nameOf = (block) => {
|
|
20
|
+
const { label, language } = block;
|
|
21
|
+
return ((typeof label === 'string' && label) ||
|
|
22
|
+
block.getAttribute('label') ||
|
|
23
|
+
(typeof language === 'string' && language) ||
|
|
24
|
+
block.getAttribute('language') ||
|
|
25
|
+
'');
|
|
26
|
+
};
|
|
16
27
|
let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
17
28
|
constructor() {
|
|
18
29
|
super(...arguments);
|
|
@@ -25,6 +36,7 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
25
36
|
this.diff = false;
|
|
26
37
|
this.expandable = false;
|
|
27
38
|
this.expandLabel = 'Show all lines';
|
|
39
|
+
this.filesLabel = 'Files';
|
|
28
40
|
this.hideUnchangedLabel = '{count, plural, one {Hide # unchanged line} other {Hide # unchanged lines}}';
|
|
29
41
|
this.label = '';
|
|
30
42
|
this.language = '';
|
|
@@ -49,6 +61,30 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
49
61
|
[...this.renderRoot.querySelectorAll('[part="block"], [part="code"]')].some((box) => box.scrollHeight > box.clientHeight + 1);
|
|
50
62
|
}
|
|
51
63
|
};
|
|
64
|
+
this.handleFileKey = (event) => {
|
|
65
|
+
const blocks = this.blocks;
|
|
66
|
+
const count = blocks.length;
|
|
67
|
+
const at = blocks.indexOf(this.shownFile(blocks));
|
|
68
|
+
const step = inlineStep(this, event.key);
|
|
69
|
+
const to = event.key === 'Home'
|
|
70
|
+
? 0
|
|
71
|
+
: event.key === 'End'
|
|
72
|
+
? count - 1
|
|
73
|
+
: step === 0
|
|
74
|
+
? -1
|
|
75
|
+
: (at + step + count) % count;
|
|
76
|
+
const block = blocks[to];
|
|
77
|
+
if (!block) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
this.chooseFile(block);
|
|
82
|
+
void this.updateComplete.then(() => {
|
|
83
|
+
this.renderRoot.querySelector('[part="file-tab"][aria-selected="true"]')?.focus();
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
this.hid = new Set();
|
|
87
|
+
this.fileCount = 0;
|
|
52
88
|
}
|
|
53
89
|
static { this.words = 'helix-code-block'; }
|
|
54
90
|
toggleWrap() {
|
|
@@ -213,6 +249,67 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
213
249
|
}
|
|
214
250
|
});
|
|
215
251
|
}
|
|
252
|
+
get blocks() {
|
|
253
|
+
return this.childrenKnown ? blocksIn(this) : [];
|
|
254
|
+
}
|
|
255
|
+
get tabbed() {
|
|
256
|
+
const parent = this.childrenKnown ? this.parentElement : null;
|
|
257
|
+
return this.slot === '' && isBlock(parent) && blocksIn(parent).length > 1;
|
|
258
|
+
}
|
|
259
|
+
shownFile(blocks) {
|
|
260
|
+
return blocks.find((block) => nameOf(block) === this.file) ?? blocks[0];
|
|
261
|
+
}
|
|
262
|
+
chooseFile(block) {
|
|
263
|
+
if (block !== this.shownFile(this.blocks)) {
|
|
264
|
+
requestValue(this, nameOf(block), (name) => {
|
|
265
|
+
this.file = name;
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
showFile() {
|
|
270
|
+
const blocks = this.blocks;
|
|
271
|
+
const files = blocks.length > 1 ? blocks : [];
|
|
272
|
+
const shown = this.shownFile(files);
|
|
273
|
+
for (const block of files) {
|
|
274
|
+
if (block !== shown && !block.hidden) {
|
|
275
|
+
block.hidden = true;
|
|
276
|
+
this.hid.add(block);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
for (const block of this.hid) {
|
|
280
|
+
if (block === shown || !files.includes(block)) {
|
|
281
|
+
;
|
|
282
|
+
block.hidden = false;
|
|
283
|
+
this.hid.delete(block);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (blocks.length !== this.fileCount) {
|
|
287
|
+
this.fileCount = blocks.length;
|
|
288
|
+
for (const block of blocks) {
|
|
289
|
+
block.requestUpdate?.();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
renderFiles(blocks) {
|
|
294
|
+
const slot = html `<slot @slotchange=${() => this.requestUpdate()}></slot>`;
|
|
295
|
+
if (blocks.length < 2) {
|
|
296
|
+
return slot;
|
|
297
|
+
}
|
|
298
|
+
const shown = this.shownFile(blocks);
|
|
299
|
+
return html `<div part="files" role="tablist" aria-label=${this.filesLabel} @keydown=${this.handleFileKey}>
|
|
300
|
+
${blocks.map((block, at) => {
|
|
301
|
+
const selected = block === shown;
|
|
302
|
+
return html `<button part="file-tab" id=${`file-${at}`} role="tab" type="button"
|
|
303
|
+
aria-controls="files-panel" aria-selected=${selected ? 'true' : 'false'}
|
|
304
|
+
tabindex=${selected ? '0' : '-1'} @click=${() => this.chooseFile(block)}>${nameOf(block)}</button>`;
|
|
305
|
+
})}
|
|
306
|
+
</div>
|
|
307
|
+
<div id="files-panel" role="tabpanel" aria-labelledby=${`file-${blocks.indexOf(shown)}`}>${slot}</div>`;
|
|
308
|
+
}
|
|
309
|
+
willUpdate(changed) {
|
|
310
|
+
super.willUpdate(changed);
|
|
311
|
+
this.toggleState('tabbed', this.tabbed);
|
|
312
|
+
}
|
|
216
313
|
updated(changed) {
|
|
217
314
|
super.updated(changed);
|
|
218
315
|
if (typeof ResizeObserver !== 'undefined') {
|
|
@@ -220,6 +317,7 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
220
317
|
this.sizes.observe(this);
|
|
221
318
|
}
|
|
222
319
|
this.measure();
|
|
320
|
+
this.showFile();
|
|
223
321
|
}
|
|
224
322
|
connectedCallback() {
|
|
225
323
|
super.connectedCallback();
|
|
@@ -239,6 +337,10 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
239
337
|
this.finishHydration();
|
|
240
338
|
}
|
|
241
339
|
render() {
|
|
340
|
+
const blocks = this.blocks;
|
|
341
|
+
if (blocks.length > 0) {
|
|
342
|
+
return this.renderFiles(blocks);
|
|
343
|
+
}
|
|
242
344
|
const files = this.files;
|
|
243
345
|
if (files.length > 0) {
|
|
244
346
|
return this.renderDiff(files);
|
|
@@ -273,10 +375,11 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
273
375
|
? html `<span part="gutter" aria-hidden="true">${numbers}</span>`
|
|
274
376
|
: nothing;
|
|
275
377
|
const name = this.label || this.language;
|
|
276
|
-
|
|
378
|
+
const drawn = this.tabbed ? '' : name;
|
|
379
|
+
return html `${this.renderHeader(name, undefined, drawn)}
|
|
277
380
|
<div part="frame">
|
|
278
381
|
<pre id="block" part="block" translate="no">${gutter}${code}</pre>
|
|
279
|
-
${this.headed(
|
|
382
|
+
${this.headed(drawn) ? nothing : this.renderCopy()}
|
|
280
383
|
</div>${this.renderExpand()}`;
|
|
281
384
|
}
|
|
282
385
|
renderExpand() {
|
|
@@ -299,10 +402,10 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
299
402
|
headed(name) {
|
|
300
403
|
return name !== '' || (this.wrappable && !this.diff) || this.slotted('actions');
|
|
301
404
|
}
|
|
302
|
-
renderHeader(name, value) {
|
|
405
|
+
renderHeader(name, value, drawn = name) {
|
|
303
406
|
const acting = this.slotted('actions');
|
|
304
|
-
return this.headed(
|
|
305
|
-
? html `<div part="header">${
|
|
407
|
+
return this.headed(drawn)
|
|
408
|
+
? html `<div part="header">${drawn ? html `<span part="label">${drawn}</span>` : nothing}${acting ? html `<span part="actions"><slot name="actions"></slot></span>` : nothing}${this.renderWrapToggle()}${this.renderCopy(value, name)}</div>`
|
|
306
409
|
: nothing;
|
|
307
410
|
}
|
|
308
411
|
renderWrapToggle() {
|
|
@@ -331,6 +434,7 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
|
|
|
331
434
|
tooltip-arrow-top: copy-tooltip-arrow-top, tooltip-bottom: copy-tooltip-bottom,
|
|
332
435
|
tooltip-left: copy-tooltip-left, tooltip-right: copy-tooltip-right, tooltip-top: copy-tooltip-top"
|
|
333
436
|
copied-label=${this.copiedLabel}
|
|
437
|
+
@helix-press=${stopPress}
|
|
334
438
|
label=${name ? formatWords(this, 'copyNameLabel', { copy: this.copyLabel, name }) : this.copyLabel}
|
|
335
439
|
.value=${value}
|
|
336
440
|
>${this.renderCopyIcons()}</${this.tag('copy-button')}>`;
|
|
@@ -434,6 +538,13 @@ __decorate([
|
|
|
434
538
|
words,
|
|
435
539
|
property({ attribute: 'expand-label' })
|
|
436
540
|
], HelixHeadlessCodeBlock.prototype, "expandLabel", void 0);
|
|
541
|
+
__decorate([
|
|
542
|
+
property()
|
|
543
|
+
], HelixHeadlessCodeBlock.prototype, "file", void 0);
|
|
544
|
+
__decorate([
|
|
545
|
+
words,
|
|
546
|
+
property({ attribute: 'files-label' })
|
|
547
|
+
], HelixHeadlessCodeBlock.prototype, "filesLabel", void 0);
|
|
437
548
|
__decorate([
|
|
438
549
|
words,
|
|
439
550
|
property({ attribute: 'hide-unchanged-label' })
|
|
@@ -36,7 +36,14 @@ registerElementEvents({
|
|
|
36
36
|
'helix-headless-chat-message': ['helix-send'],
|
|
37
37
|
'helix-headless-checkbox': ['change', 'helix-before-toggle', 'input'],
|
|
38
38
|
'helix-headless-checkbox-group': ['change', 'helix-before-change', 'input'],
|
|
39
|
-
'helix-headless-code-block': [
|
|
39
|
+
'helix-headless-code-block': [
|
|
40
|
+
'change',
|
|
41
|
+
'helix-before-change',
|
|
42
|
+
'helix-before-toggle',
|
|
43
|
+
'helix-copy',
|
|
44
|
+
'helix-copy-error',
|
|
45
|
+
'helix-toggle',
|
|
46
|
+
],
|
|
40
47
|
'helix-headless-color-input': [
|
|
41
48
|
'change',
|
|
42
49
|
'helix-before-change',
|
|
@@ -186,7 +193,13 @@ registerElementEvents({
|
|
|
186
193
|
'helix-headless-map-route': ['helix-map-part-change'],
|
|
187
194
|
'helix-headless-map-terrain': ['helix-map-part-change'],
|
|
188
195
|
'helix-headless-megamenu': ['helix-before-close', 'helix-before-open', 'toggle'],
|
|
189
|
-
'helix-headless-menu': [
|
|
196
|
+
'helix-headless-menu': [
|
|
197
|
+
'helix-before-close',
|
|
198
|
+
'helix-before-open',
|
|
199
|
+
'helix-filter',
|
|
200
|
+
'helix-select',
|
|
201
|
+
'toggle',
|
|
202
|
+
],
|
|
190
203
|
'helix-headless-menu-item': ['helix-before-toggle', 'helix-select'],
|
|
191
204
|
'helix-headless-meter': ['helix-band'],
|
|
192
205
|
'helix-headless-notification': ['helix-dismiss', 'helix-read'],
|
|
@@ -82,6 +82,7 @@ import '../../menu/index.js';
|
|
|
82
82
|
* @csspart menu-header - The bar above a field's page, with the back button and the field's name.
|
|
83
83
|
* @csspart menu-live - The inner menu's `live` part: the region that screen readers announce the empty and loading messages from.
|
|
84
84
|
* @csspart menu-loading - Shown while the fields are loading.
|
|
85
|
+
* @csspart menu-search-field - The inner menu's filter field, drawn with `filterable`.
|
|
85
86
|
* @csspart menu-surface - The floating panel the menu is drawn on.
|
|
86
87
|
* @csspart menu-title - The name of the field whose page is showing.
|
|
87
88
|
*/
|
|
@@ -126,7 +126,7 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
|
|
|
126
126
|
return html `<${menu}
|
|
127
127
|
part="menu"
|
|
128
128
|
exportparts="back: menu-back, back-mark: menu-back-mark, empty: menu-empty, header: menu-header,
|
|
129
|
-
live: menu-live, loading: menu-loading, surface: menu-surface, title: menu-title"
|
|
129
|
+
live: menu-live, loading: menu-loading, search-field: menu-search-field, surface: menu-surface, title: menu-title"
|
|
130
130
|
label=${this.label}
|
|
131
131
|
@helix-select=${this.handleSelect}
|
|
132
132
|
>
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { AriaForwardController, centerInView, chosenValues, columnStep, countLabel, customElement, DelayController, DisabledCascadeController, drawAutofill, endInSight, formatWords, HelixFilterEvent, HelixFormElement, HelixLoadMoreEvent, hostAria, inlineStep, MixinCollection, MixinControllerValue, MixinField, markMatches, OptionWindowController, onApple, pageRows, rangeAdd, reportValues, requestChange, scrollItemIntoView, selectsAll, Typeahead, toggleEvery, typesCharacter, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, centerInView, chosenValues, columnStep, countLabel, customElement, DelayController, DisabledCascadeController, drawAutofill, endInSight, filterKeeps, formatWords, HelixFilterEvent, HelixFormElement, HelixLoadMoreEvent, hostAria, inlineStep, MixinCollection, MixinControllerValue, MixinField, markMatches, OptionWindowController, onApple, pageRows, rangeAdd, reportValues, requestChange, scrollItemIntoView, selectsAll, Typeahead, toggleEvery, typesCharacter, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { magnifyingGlass } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -400,12 +400,9 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
|
|
|
400
400
|
this.forgetRemoved();
|
|
401
401
|
const typed = this.filter.trim();
|
|
402
402
|
const needle = typed.toLowerCase();
|
|
403
|
-
const match = this.filterMatch;
|
|
404
403
|
const chosen = new Set(this.values);
|
|
405
404
|
for (const option of this.entries) {
|
|
406
|
-
option.hidden =
|
|
407
|
-
needle !== '' &&
|
|
408
|
-
!(match ? match(option.text, typed) : option.text.toLowerCase().includes(needle));
|
|
405
|
+
option.hidden = !filterKeeps(option.text, typed, this.filterMatch);
|
|
409
406
|
option.selected = chosen.has(option.value);
|
|
410
407
|
}
|
|
411
408
|
for (const group of this.groups) {
|
|
@@ -47,6 +47,12 @@ import '../../kbd/index.js';
|
|
|
47
47
|
* slots, so a mark of your own replaces either by being slotted. Neither is
|
|
48
48
|
* read as part of the row's name.
|
|
49
49
|
*
|
|
50
|
+
* In a menu with `filterable`, focus stays in the menu's filter field and the
|
|
51
|
+
* row the arrow keys reach is highlighted: the field names it with
|
|
52
|
+
* `aria-activedescendant`, the row carries its role on its host so the field
|
|
53
|
+
* can point at it, and `:state(highlighted)` says which row it is. A row with
|
|
54
|
+
* an `href` then follows its link without an anchor, as `Option` does.
|
|
55
|
+
*
|
|
50
56
|
* @since 0.1.0
|
|
51
57
|
* @status stable
|
|
52
58
|
* @aliases Menu option, Menu row
|
|
@@ -75,6 +81,7 @@ import '../../kbd/index.js';
|
|
|
75
81
|
* @csspart surface - The panel a submenu opens in beside the row, under the menu's `submenus="flyout"`.
|
|
76
82
|
*
|
|
77
83
|
* @cssstate checked - The row is checked.
|
|
84
|
+
* @cssstate highlighted - In a menu with `filterable`, the arrow keys or the pointer reached the row while focus stays in the filter field.
|
|
78
85
|
* @cssstate submenu-mark - Under `submenus="flyout"`, a row in this row's submenu can be ticked or opens a submenu, so the submenu keeps its trailing column.
|
|
79
86
|
* @cssstate submenu-start - Under `submenus="flyout"`, a row in this row's submenu has content before its label, so the submenu keeps its leading column.
|
|
80
87
|
*/
|
|
@@ -144,6 +151,11 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
|
|
|
144
151
|
* `submenus="flyout"`. Written by the menu.
|
|
145
152
|
*/
|
|
146
153
|
flyout: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* @internal Whether the row is the one the keys reached in a menu that keeps
|
|
156
|
+
* focus in its filter field. Written by the menu.
|
|
157
|
+
*/
|
|
158
|
+
highlighted: boolean;
|
|
147
159
|
/**
|
|
148
160
|
* The URL the row links to. Setting it renders the row as a link.
|
|
149
161
|
*
|
|
@@ -200,6 +212,12 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
|
|
|
200
212
|
* The row's value, sent in `helix-select` when the row is chosen.
|
|
201
213
|
*/
|
|
202
214
|
value: string;
|
|
215
|
+
/**
|
|
216
|
+
* @internal Whether the menu keeps focus in its filter field, so the row is
|
|
217
|
+
* highlighted rather than focused and says what it is from its host, where
|
|
218
|
+
* the field's `aria-activedescendant` can reach it. Written by the menu.
|
|
219
|
+
*/
|
|
220
|
+
virtual: boolean;
|
|
203
221
|
/**
|
|
204
222
|
* @internal Read by a parent to identify its children across the light DOM,
|
|
205
223
|
* which is cheaper than `instanceof` and is why this is public rather than
|
|
@@ -414,6 +432,8 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
|
|
|
414
432
|
* still line up without every row carrying an empty box to line them up with.
|
|
415
433
|
*/
|
|
416
434
|
protected renderMark(submenu: boolean): TemplateResult | typeof nothing;
|
|
435
|
+
/** Whether the row says what it is from its host, for a field's `aria-activedescendant`. */
|
|
436
|
+
private get onHost();
|
|
417
437
|
protected render(): TemplateResult | typeof nothing;
|
|
418
438
|
}
|
|
419
439
|
declare global {
|