@fusion.dev/helix-headless 0.172.0 → 0.173.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 +912 -60
- package/dist/button-group/root/button-group-root.d.ts +30 -0
- package/dist/button-group/root/button-group-root.js +50 -4
- package/dist/canvas/root/canvas-root.d.ts +7 -0
- package/dist/canvas/root/canvas-root.js +7 -0
- package/dist/copy-button/root/copy-button-root.d.ts +43 -3
- package/dist/copy-button/root/copy-button-root.js +49 -3
- package/dist/element-events.generated.js +2 -0
- package/dist/graph/root/graph-root.d.ts +22 -0
- package/dist/graph/root/graph-root.js +21 -5
- package/dist/list/root/list-root.d.ts +6 -1
- package/dist/list/root/list-root.js +3 -2
- package/dist/outline/root/outline-root.d.ts +57 -0
- package/dist/outline/root/outline-root.js +98 -29
- package/dist/speed-dial/root/speed-dial-root.d.ts +14 -0
- package/dist/speed-dial/root/speed-dial-root.js +34 -2
- package/dist/splitter/root/splitter-root.d.ts +25 -2
- package/dist/splitter/root/splitter-root.js +19 -4
- package/dist/tag/group/tag-group.d.ts +8 -1
- package/dist/tag/group/tag-group.js +8 -0
- package/dist/tag/root/tag-root.d.ts +12 -0
- package/dist/tag/root/tag-root.js +12 -0
- package/dist/time-picker/root/time-picker-root.d.ts +14 -0
- package/dist/time-picker/root/time-picker-root.js +8 -1
- package/dist/timeline/item/timeline-item.d.ts +5 -1
- package/dist/timeline/item/timeline-item.js +9 -0
- package/dist/timeline/root/timeline-root.d.ts +23 -0
- package/dist/timeline/root/timeline-root.js +17 -3
- package/dist/tooltip/root/tooltip-root.d.ts +10 -0
- package/dist/tooltip/root/tooltip-root.js +14 -2
- package/dist/virtual-list/reorder/index.d.ts +1 -0
- package/dist/virtual-list/reorder/index.js +4 -0
- package/dist/virtual-list/reorder/virtual-list-reorder.d.ts +86 -0
- package/dist/virtual-list/reorder/virtual-list-reorder.js +193 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +49 -11
- package/dist/virtual-list/root/virtual-list-root.js +10 -1
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +568 -18
- package/types/vue.d.ts +115 -11
- package/types/words.d.ts +14 -0
|
@@ -57,6 +57,12 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
57
57
|
* a named `group`, and the toolbar's own arrow keys walk its buttons, so a
|
|
58
58
|
* reader meets one toolbar. Under `single` it is a `radiogroup` either way.
|
|
59
59
|
*
|
|
60
|
+
* **Disabled.** `disabled` on the group disables every button in it, Helix
|
|
61
|
+
* and native alike, and says so on the group with `aria-disabled`, as React
|
|
62
|
+
* Aria's `isDisabled` does. A button disabled on its own stays disabled when
|
|
63
|
+
* the group is enabled again, and a button that leaves the group gets back
|
|
64
|
+
* what it said for itself.
|
|
65
|
+
*
|
|
60
66
|
* @since 0.1.0
|
|
61
67
|
* @status stable
|
|
62
68
|
* @category actions
|
|
@@ -73,6 +79,11 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
73
79
|
* @cssstate pressed - While a group with `selection-mode` has a button pressed.
|
|
74
80
|
*/
|
|
75
81
|
export declare class HelixHeadlessButtonGroup extends HelixElement {
|
|
82
|
+
/**
|
|
83
|
+
* Disables every button in the group, and says so on the group with
|
|
84
|
+
* `aria-disabled`. Reflected, so a stylesheet can select on it.
|
|
85
|
+
*/
|
|
86
|
+
disabled: boolean;
|
|
76
87
|
/**
|
|
77
88
|
* Keeps at least one button pressed once one is, as React Aria's
|
|
78
89
|
* `disallowEmptySelection`: a press that would leave none pressed is
|
|
@@ -122,6 +133,12 @@ export declare class HelixHeadlessButtonGroup extends HelixElement {
|
|
|
122
133
|
* not reflect, as a native control's `value` does not.
|
|
123
134
|
*/
|
|
124
135
|
value: string;
|
|
136
|
+
/**
|
|
137
|
+
* The pressed values as a list, in a selection mode, and an empty list
|
|
138
|
+
* otherwise. Written, it presses exactly those buttons.
|
|
139
|
+
*/
|
|
140
|
+
get values(): string[];
|
|
141
|
+
set values(next: string[]);
|
|
125
142
|
/**
|
|
126
143
|
* The Helix buttons of a group in a selection mode, in the order they are
|
|
127
144
|
* written, and none otherwise. Empty on a server, which has no tree.
|
|
@@ -146,6 +163,19 @@ export declare class HelixHeadlessButtonGroup extends HelixElement {
|
|
|
146
163
|
*/
|
|
147
164
|
private readonly told;
|
|
148
165
|
private watcher;
|
|
166
|
+
/** The children that can be disabled: Helix buttons and native ones alike. Empty on a server. */
|
|
167
|
+
private get members();
|
|
168
|
+
/** The members this group has disabled, so one that leaves is given back its own answer. */
|
|
169
|
+
private readonly held;
|
|
170
|
+
/**
|
|
171
|
+
* Passes `disabled` down to the members, and gives a member that left
|
|
172
|
+
* what it said for itself.
|
|
173
|
+
*
|
|
174
|
+
* A member already disabled is not written to again: the watcher hears
|
|
175
|
+
* every write to a native button's `disabled`, changed or not, and would
|
|
176
|
+
* answer it with this.
|
|
177
|
+
*/
|
|
178
|
+
private cascade;
|
|
149
179
|
/**
|
|
150
180
|
* Tells every button whether it is pressed and whether it holds the stop,
|
|
151
181
|
* and puts back the ones that left.
|
|
@@ -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 { auditName, commaList, customElement, HelixElement, hostAria, inlineStep, pressedValue, reportRuntime, requestValue, rovingStop, toolbarAround, whenHydrated, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { auditName, commaList, customElement, HelixElement, hostAria, inheritDisabled, inlineStep, pressedValue, reportRuntime, requestValue, rovingStop, toolbarAround, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { arrowTarget } from '../arrows.js';
|
|
@@ -12,11 +12,13 @@ const isGroupButton = (child) => child instanceof HTMLElement && 'focusable' in
|
|
|
12
12
|
let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixElement {
|
|
13
13
|
constructor() {
|
|
14
14
|
super(...arguments);
|
|
15
|
+
this.disabled = false;
|
|
15
16
|
this.disallowEmptySelection = false;
|
|
16
17
|
this.label = '';
|
|
17
18
|
this.value = '';
|
|
18
19
|
this.lastFocused = undefined;
|
|
19
20
|
this.told = new Map();
|
|
21
|
+
this.held = new Set();
|
|
20
22
|
this.warned = false;
|
|
21
23
|
this.handlePress = (event) => {
|
|
22
24
|
const mode = this.selectionMode;
|
|
@@ -48,6 +50,12 @@ let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixEleme
|
|
|
48
50
|
}
|
|
49
51
|
};
|
|
50
52
|
}
|
|
53
|
+
get values() {
|
|
54
|
+
return this.selectionMode ? commaList(this.value) : [];
|
|
55
|
+
}
|
|
56
|
+
set values(next) {
|
|
57
|
+
this.value = next.join(',');
|
|
58
|
+
}
|
|
51
59
|
get buttons() {
|
|
52
60
|
return this.selectionMode && this.children ? [...this.children].filter(isGroupButton) : [];
|
|
53
61
|
}
|
|
@@ -57,7 +65,33 @@ let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixEleme
|
|
|
57
65
|
pressed(button) {
|
|
58
66
|
return button.value !== '' && commaList(this.value).includes(button.value);
|
|
59
67
|
}
|
|
68
|
+
get members() {
|
|
69
|
+
return this.children
|
|
70
|
+
? [...this.children].filter((child) => child instanceof HTMLElement && 'disabled' in child)
|
|
71
|
+
: [];
|
|
72
|
+
}
|
|
73
|
+
cascade() {
|
|
74
|
+
const members = this.members;
|
|
75
|
+
for (const gone of this.held) {
|
|
76
|
+
if (!members.includes(gone)) {
|
|
77
|
+
inheritDisabled(false, [gone]);
|
|
78
|
+
this.held.delete(gone);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (this.disabled) {
|
|
82
|
+
const live = members.filter((member) => !member.disabled);
|
|
83
|
+
inheritDisabled(true, live);
|
|
84
|
+
for (const member of live) {
|
|
85
|
+
this.held.add(member);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (this.held.size > 0) {
|
|
89
|
+
inheritDisabled(false, [...this.held]);
|
|
90
|
+
this.held.clear();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
60
93
|
sync() {
|
|
94
|
+
this.cascade();
|
|
61
95
|
const buttons = this.buttons;
|
|
62
96
|
const roving = this.roving;
|
|
63
97
|
const stop = roving
|
|
@@ -86,11 +120,16 @@ let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixEleme
|
|
|
86
120
|
});
|
|
87
121
|
}
|
|
88
122
|
}
|
|
89
|
-
|
|
90
|
-
|
|
123
|
+
const reading = Boolean(this.selectionMode) || this.disabled;
|
|
124
|
+
for (const child of reading && this.children ? this.children : []) {
|
|
125
|
+
if (child.localName.includes('-') &&
|
|
126
|
+
!isGroupButton(child) &&
|
|
127
|
+
!customElements.get(child.localName)) {
|
|
91
128
|
void customElements.whenDefined(child.localName).then(() => this.sync());
|
|
92
129
|
}
|
|
93
|
-
else if (
|
|
130
|
+
else if (this.selectionMode &&
|
|
131
|
+
child.localName === 'button' &&
|
|
132
|
+
!child.hasAttribute('aria-pressed')) {
|
|
94
133
|
this.warn(child);
|
|
95
134
|
}
|
|
96
135
|
}
|
|
@@ -167,6 +206,7 @@ let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixEleme
|
|
|
167
206
|
role: radios ? 'radiogroup' : toolbar ? 'toolbar' : 'group',
|
|
168
207
|
});
|
|
169
208
|
this.internals.ariaOrientation = toolbar ? (this.orientation ?? null) : null;
|
|
209
|
+
this.internals.ariaDisabled = this.disabled ? 'true' : null;
|
|
170
210
|
this.toggleState('pressed', Boolean(this.selectionMode) && commaList(this.value).length > 0);
|
|
171
211
|
}
|
|
172
212
|
firstUpdated(changed) {
|
|
@@ -181,6 +221,9 @@ let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixEleme
|
|
|
181
221
|
return html `<slot></slot>`;
|
|
182
222
|
}
|
|
183
223
|
};
|
|
224
|
+
__decorate([
|
|
225
|
+
property({ reflect: true, type: Boolean })
|
|
226
|
+
], HelixHeadlessButtonGroup.prototype, "disabled", void 0);
|
|
184
227
|
__decorate([
|
|
185
228
|
property({ attribute: 'disallow-empty-selection', type: Boolean })
|
|
186
229
|
], HelixHeadlessButtonGroup.prototype, "disallowEmptySelection", void 0);
|
|
@@ -196,6 +239,9 @@ __decorate([
|
|
|
196
239
|
__decorate([
|
|
197
240
|
property()
|
|
198
241
|
], HelixHeadlessButtonGroup.prototype, "value", void 0);
|
|
242
|
+
__decorate([
|
|
243
|
+
property({ attribute: false })
|
|
244
|
+
], HelixHeadlessButtonGroup.prototype, "values", null);
|
|
199
245
|
HelixHeadlessButtonGroup = __decorate([
|
|
200
246
|
customElement('helix-headless-button-group')
|
|
201
247
|
], HelixHeadlessButtonGroup);
|
|
@@ -132,6 +132,7 @@ declare const HelixHeadlessCanvas_base: (new (...args: any[]) => import("@fusion
|
|
|
132
132
|
* @slot footer - Content below the board.
|
|
133
133
|
* @slot fullscreen-icon - Replaces the glyph inside the fullscreen button.
|
|
134
134
|
* @slot header - Content above the board.
|
|
135
|
+
* @slot loading - Content shown while `loading` is set, such as a progress bar while the document arrives.
|
|
135
136
|
* @slot pan-down-icon - Replaces the glyph inside the pan down button.
|
|
136
137
|
* @slot pan-end-icon - Replaces the glyph inside the button that pans toward the end of a line of text.
|
|
137
138
|
* @slot pan-start-icon - Replaces the glyph inside the button that pans toward the start of a line of text.
|
|
@@ -192,6 +193,7 @@ declare const HelixHeadlessCanvas_base: (new (...args: any[]) => import("@fusion
|
|
|
192
193
|
* @cssstate fullscreen - While the board fills the screen.
|
|
193
194
|
* @cssstate holding - An item picked up with a click follows the pointer until the next press puts it down.
|
|
194
195
|
* @cssstate idle - The user has been still for `idle-delay` milliseconds. The board's own controls stay; select on it to hide chrome of your own.
|
|
196
|
+
* @cssstate loading - While `loading` is set.
|
|
195
197
|
* @cssstate pressing - While a press on the board, its cards or its connections is under way.
|
|
196
198
|
* @cssstate sharing - The page keeps the plain wheel and one finger, with `gestures="cooperative"` or while a board with `gestures="activate"` waits to be pressed.
|
|
197
199
|
* @cssstate using - A board with `gestures="activate"` has been pressed and has the gestures.
|
|
@@ -275,6 +277,11 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
|
|
|
275
277
|
* `leads-to-label` and `{comesFrom}` is `comes-from-label`, each filled in.
|
|
276
278
|
*/
|
|
277
279
|
linkedLabel: string;
|
|
280
|
+
/**
|
|
281
|
+
* Marks the board as busy while its document arrives: the board is
|
|
282
|
+
* `aria-busy`, and the `loading` slot is shown.
|
|
283
|
+
*/
|
|
284
|
+
loading: boolean;
|
|
278
285
|
/**
|
|
279
286
|
* What screen readers hear after a key moves a card, with `{name}` for the
|
|
280
287
|
* card and `{x}` and `{y}` for where it now is, in the document's units.
|
|
@@ -57,6 +57,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
|
|
|
57
57
|
this.labelEditorLabel = 'Label for {name}';
|
|
58
58
|
this.leadsToLabel = 'leads to {cards}';
|
|
59
59
|
this.linkedLabel = '{leadsTo}; {comesFrom}';
|
|
60
|
+
this.loading = false;
|
|
60
61
|
this.movedLabel = '{name} moved to {x}, {y}';
|
|
61
62
|
this.pastedLabel = '{count, plural, one {# card pasted} other {# cards pasted}}';
|
|
62
63
|
this.readOnly = false;
|
|
@@ -2133,6 +2134,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
|
|
|
2133
2134
|
this.toggleState('empty', this.nodes.length === 0);
|
|
2134
2135
|
this.toggleState('fullscreen', this.filled);
|
|
2135
2136
|
this.toggleState('idle', this.resting);
|
|
2137
|
+
this.toggleState('loading', this.loading);
|
|
2136
2138
|
}
|
|
2137
2139
|
place(origin) {
|
|
2138
2140
|
const all = this.nodes;
|
|
@@ -2411,6 +2413,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
|
|
|
2411
2413
|
role="group"
|
|
2412
2414
|
aria-label=${this.label || this.getAttribute?.('aria-label') || this.fallbackLabel}
|
|
2413
2415
|
aria-roledescription=${(this.label || this.getAttribute?.('aria-label')) && this.roleLabel ? this.roleLabel : nothing}
|
|
2416
|
+
aria-busy=${this.loading ? 'true' : nothing}
|
|
2414
2417
|
aria-keyshortcuts="ArrowUp ArrowDown ArrowLeft ArrowRight Plus Minus"
|
|
2415
2418
|
tabindex="0"
|
|
2416
2419
|
@focusin=${this.idle.stir}
|
|
@@ -2461,6 +2464,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
|
|
|
2461
2464
|
${this.renderMarquee(origin)}
|
|
2462
2465
|
</div>
|
|
2463
2466
|
<slot name="empty"></slot>
|
|
2467
|
+
${this.loading ? html `<slot name="loading"></slot>` : nothing}
|
|
2464
2468
|
${this.renderGestures()}
|
|
2465
2469
|
</div>
|
|
2466
2470
|
${this.renderControls()} ${this.renderMinimap()}
|
|
@@ -2525,6 +2529,9 @@ __decorate([
|
|
|
2525
2529
|
words,
|
|
2526
2530
|
property({ attribute: 'linked-label' })
|
|
2527
2531
|
], HelixHeadlessCanvas.prototype, "linkedLabel", void 0);
|
|
2532
|
+
__decorate([
|
|
2533
|
+
property({ reflect: true, type: Boolean })
|
|
2534
|
+
], HelixHeadlessCanvas.prototype, "loading", void 0);
|
|
2528
2535
|
__decorate([
|
|
2529
2536
|
words,
|
|
2530
2537
|
property({ attribute: 'moved-label' })
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Placement } from '@fusion.dev/helix-core';
|
|
2
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
2
3
|
import { HelixHeadlessIconButton } from '../../icon-button/root/icon-button-root.js';
|
|
3
4
|
import '../../tooltip/index.js';
|
|
4
5
|
/**
|
|
@@ -31,7 +32,17 @@ import '../../tooltip/index.js';
|
|
|
31
32
|
* The button is named `label`, or the host's `aria-label`, and its name
|
|
32
33
|
* changes to `copied-label` or `error-label` for the moment after a press. The
|
|
33
34
|
* same words are said in a live region, so a screen reader hears the result,
|
|
34
|
-
* and the tooltip shows them.
|
|
35
|
+
* and the tooltip shows them. The tooltip does not also describe the button,
|
|
36
|
+
* since its words are the button's name.
|
|
37
|
+
*
|
|
38
|
+
* **The tooltip.** It shows the name on hover and focus and the result after a
|
|
39
|
+
* press. `tooltip="copy"` shows it only for the result, and `tooltip="none"`
|
|
40
|
+
* draws none, as Web Awesome's copy button offers. `tooltip-placement` is the
|
|
41
|
+
* side it prefers, and it moves to another side where that one does not fit.
|
|
42
|
+
*
|
|
43
|
+
* **Words on the button.** `show-label` draws the name beside the icon, and
|
|
44
|
+
* the result in its place after a press. The button is as wide as the longest
|
|
45
|
+
* of the three, so a press does not resize it.
|
|
35
46
|
*
|
|
36
47
|
* @since 0.1.0
|
|
37
48
|
* @status stable
|
|
@@ -50,6 +61,7 @@ import '../../tooltip/index.js';
|
|
|
50
61
|
* @csspart live - The live region that says `copied-label` or `error-label` after a press, and `pending-label` when the button becomes pending under focus. It is rendered from the first time it says anything.
|
|
51
62
|
* @csspart mark - The clipboard icon, and the confirmation icon that replaces it.
|
|
52
63
|
* @csspart spinner - The ring a pending button turns, an empty element the styled button draws over the icon. It is rendered only while the button is pending.
|
|
64
|
+
* @csspart text - The words beside the icon, under `show-label`. It holds all three, `label`, `copied-label` and `error-label`, with all but the current one hidden.
|
|
53
65
|
* @csspart tooltip - The tooltip bubble, forwarded from the tooltip inside the button.
|
|
54
66
|
* @csspart tooltip-arrow - The tooltip's arrow, which points at the button.
|
|
55
67
|
* @csspart tooltip-arrow-bottom - The arrow while the bubble is below the button, on the bubble's top edge. Set together with `tooltip-arrow`.
|
|
@@ -64,7 +76,6 @@ import '../../tooltip/index.js';
|
|
|
64
76
|
* @cssstate copied - The moment after a successful copy, while `copied-label` names the button.
|
|
65
77
|
* @cssstate failed - The moment after a press that put nothing on the clipboard, while `error-label` names the button.
|
|
66
78
|
*
|
|
67
|
-
* @withheld csspart text - Button's words, which this does not render: the label is the icon's name.
|
|
68
79
|
* @withheld slot end - Button's, which this does not render.
|
|
69
80
|
* @withheld slot start - Button's, which this does not render.
|
|
70
81
|
*/
|
|
@@ -106,6 +117,24 @@ export declare class HelixHeadlessCopyButton extends HelixHeadlessIconButton {
|
|
|
106
117
|
* world is called Copy. A consumer with a better word still sets it.
|
|
107
118
|
*/
|
|
108
119
|
label: string;
|
|
120
|
+
/**
|
|
121
|
+
* Draws the name as words beside the icon, and the result in their place
|
|
122
|
+
* after a press. The button stays as wide as the longest of them.
|
|
123
|
+
*/
|
|
124
|
+
showLabel: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* When the tooltip shows: `full` on hover and focus and after a press,
|
|
127
|
+
* `copy` only after a press, to show the result, and `none` never, for a
|
|
128
|
+
* button whose result shows another way, such as under `show-label`.
|
|
129
|
+
*
|
|
130
|
+
* Unset is `full`, and the attribute stays absent until you write it.
|
|
131
|
+
*/
|
|
132
|
+
tooltip?: 'copy' | 'full' | 'none';
|
|
133
|
+
/**
|
|
134
|
+
* The side the tooltip prefers. It moves to another side where this one
|
|
135
|
+
* does not fit.
|
|
136
|
+
*/
|
|
137
|
+
tooltipPlacement: Placement;
|
|
109
138
|
/**
|
|
110
139
|
* The text copied to the clipboard.
|
|
111
140
|
*
|
|
@@ -156,6 +185,9 @@ export declare class HelixHeadlessCopyButton extends HelixHeadlessIconButton {
|
|
|
156
185
|
*/
|
|
157
186
|
protected get forwardsLabel(): boolean;
|
|
158
187
|
protected willUpdate(changed: PropertyValues): void;
|
|
188
|
+
/** Whether the last render showed a result, so `tooltip="copy"` opens and closes on the change. */
|
|
189
|
+
private showedResult;
|
|
190
|
+
protected updated(changed: PropertyValues): void;
|
|
159
191
|
/** @internal A copy button never submits, so it is no form's default button. */
|
|
160
192
|
protected get submitsForm(): boolean;
|
|
161
193
|
/**
|
|
@@ -211,6 +243,14 @@ export declare class HelixHeadlessCopyButton extends HelixHeadlessIconButton {
|
|
|
211
243
|
protected renderCopiedIcon(): TemplateResult;
|
|
212
244
|
/** The mark for a press that put nothing on the clipboard, behind a seam of its own. */
|
|
213
245
|
protected renderFailedIcon(): TemplateResult;
|
|
246
|
+
/**
|
|
247
|
+
* The words beside the icon, under `show-label`, behind a seam of its own.
|
|
248
|
+
*
|
|
249
|
+
* All three are drawn and only the current one shows, so the button is as
|
|
250
|
+
* wide as the longest of them and a press does not resize it. Hidden from a
|
|
251
|
+
* screen reader, which hears the same words as the button's name.
|
|
252
|
+
*/
|
|
253
|
+
protected renderText(): TemplateResult | typeof nothing;
|
|
214
254
|
/**
|
|
215
255
|
* The bubble the control sits inside, behind a seam.
|
|
216
256
|
*
|
|
@@ -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
|
var HelixHeadlessCopyButton_1;
|
|
8
|
-
import { CopyController, customElement, HelixCopyErrorEvent, words } from '@fusion.dev/helix-core';
|
|
8
|
+
import { CopyController, customElement, HelixCopyErrorEvent, words, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { check, copy, x } from '@fusion.dev/helix-icons';
|
|
10
10
|
import { nothing } from 'lit';
|
|
11
11
|
import { property } from 'lit/decorators.js';
|
|
@@ -22,8 +22,11 @@ let HelixHeadlessCopyButton = class HelixHeadlessCopyButton extends HelixHeadles
|
|
|
22
22
|
this.feedbackDuration = 1600;
|
|
23
23
|
this.from = '';
|
|
24
24
|
this.label = 'Copy';
|
|
25
|
+
this.showLabel = false;
|
|
26
|
+
this.tooltipPlacement = 'top';
|
|
25
27
|
this.value = '';
|
|
26
28
|
this.namedBy = null;
|
|
29
|
+
this.showedResult = false;
|
|
27
30
|
this.clipboard = new CopyController(this, { after: () => this.feedbackDuration });
|
|
28
31
|
this.handleCopy = async (event) => {
|
|
29
32
|
if (this.pending) {
|
|
@@ -62,6 +65,24 @@ let HelixHeadlessCopyButton = class HelixHeadlessCopyButton extends HelixHeadles
|
|
|
62
65
|
this.toggleState('copied', this.copied);
|
|
63
66
|
this.toggleState('failed', this.failed);
|
|
64
67
|
}
|
|
68
|
+
updated(changed) {
|
|
69
|
+
super.updated(changed);
|
|
70
|
+
const result = this.copied || this.failed;
|
|
71
|
+
if (result === this.showedResult) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.showedResult = result;
|
|
75
|
+
if (this.tooltip !== 'copy') {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const tip = this.renderRoot.querySelector('[data-copy-tooltip]');
|
|
79
|
+
if (result) {
|
|
80
|
+
tip?.show();
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
tip?.hide();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
65
86
|
get submitsForm() {
|
|
66
87
|
return false;
|
|
67
88
|
}
|
|
@@ -94,7 +115,7 @@ let HelixHeadlessCopyButton = class HelixHeadlessCopyButton extends HelixHeadles
|
|
|
94
115
|
@keydown=${this.notePress}
|
|
95
116
|
@pointerdown=${this.notePress}
|
|
96
117
|
>
|
|
97
|
-
${this.renderCopiedIcon()} ${this.renderFailedIcon()} ${this.renderCopyIcon()}${this.renderSpinner()}
|
|
118
|
+
${this.renderCopiedIcon()} ${this.renderFailedIcon()} ${this.renderCopyIcon()}${this.renderSpinner()}${this.renderText()}
|
|
98
119
|
</button>`)}${this.renderLive()}`;
|
|
99
120
|
}
|
|
100
121
|
renderCopyIcon() {
|
|
@@ -112,8 +133,24 @@ let HelixHeadlessCopyButton = class HelixHeadlessCopyButton extends HelixHeadles
|
|
|
112
133
|
>${HelixHeadlessCopyButton_1.icon(x)}</slot
|
|
113
134
|
>`;
|
|
114
135
|
}
|
|
136
|
+
renderText() {
|
|
137
|
+
if (!this.showLabel) {
|
|
138
|
+
return nothing;
|
|
139
|
+
}
|
|
140
|
+
const resting = !this.copied && !this.failed;
|
|
141
|
+
return html `<span part="text" aria-hidden="true"
|
|
142
|
+
><span ?hidden=${!resting}>${this.namedBy || this.label}</span
|
|
143
|
+
><span ?hidden=${!this.copied}>${this.copiedLabel}</span
|
|
144
|
+
><span ?hidden=${!this.failed}>${this.errorLabel}</span
|
|
145
|
+
></span>`;
|
|
146
|
+
}
|
|
115
147
|
renderTooltip(control) {
|
|
116
|
-
|
|
148
|
+
if (this.tooltip === 'none') {
|
|
149
|
+
return control;
|
|
150
|
+
}
|
|
151
|
+
const content = this.tooltip === 'copy' && !this.copied && !this.failed ? '' : this.says;
|
|
152
|
+
return html `<${this.tag('tooltip')} content=${content} persist
|
|
153
|
+
data-copy-tooltip placement=${this.tooltipPlacement}
|
|
117
154
|
exportparts="arrow: tooltip-arrow, arrow-bottom: tooltip-arrow-bottom,
|
|
118
155
|
arrow-left: tooltip-arrow-left, arrow-right: tooltip-arrow-right,
|
|
119
156
|
arrow-top: tooltip-arrow-top, tooltip, tooltip-bottom, tooltip-left, tooltip-right,
|
|
@@ -140,6 +177,15 @@ __decorate([
|
|
|
140
177
|
words,
|
|
141
178
|
property()
|
|
142
179
|
], HelixHeadlessCopyButton.prototype, "label", void 0);
|
|
180
|
+
__decorate([
|
|
181
|
+
property({ attribute: 'show-label', reflect: true, type: Boolean })
|
|
182
|
+
], HelixHeadlessCopyButton.prototype, "showLabel", void 0);
|
|
183
|
+
__decorate([
|
|
184
|
+
property()
|
|
185
|
+
], HelixHeadlessCopyButton.prototype, "tooltip", void 0);
|
|
186
|
+
__decorate([
|
|
187
|
+
property({ attribute: 'tooltip-placement' })
|
|
188
|
+
], HelixHeadlessCopyButton.prototype, "tooltipPlacement", void 0);
|
|
143
189
|
__decorate([
|
|
144
190
|
property()
|
|
145
191
|
], HelixHeadlessCopyButton.prototype, "value", void 0);
|
|
@@ -44,6 +44,7 @@ declare const HelixHeadlessGraph_base: (new (...args: any[]) => import("@fusion.
|
|
|
44
44
|
* @slot footer - Content below the graph.
|
|
45
45
|
* @slot fullscreen-icon - Replaces the glyph inside the fullscreen button.
|
|
46
46
|
* @slot header - Content above the graph.
|
|
47
|
+
* @slot loading - What the panel shows while `loading` is set and the list holds no notes. Defaults to `loading-label`.
|
|
47
48
|
* @slot pan-down-icon - Replaces the glyph inside the pan down button.
|
|
48
49
|
* @slot pan-end-icon - Replaces the glyph inside the button that pans toward the end of a line of text.
|
|
49
50
|
* @slot pan-start-icon - Replaces the glyph inside the button that pans toward the start of a line of text.
|
|
@@ -80,6 +81,7 @@ declare const HelixHeadlessGraph_base: (new (...args: any[]) => import("@fusion.
|
|
|
80
81
|
* @csspart legend-swatch - The mark in a group's color, before its name.
|
|
81
82
|
* @csspart list - The list of notes, which draws only the rows in view.
|
|
82
83
|
* @csspart live - What screen readers hear: how many notes there are when a search or the legend changes it, and which way the drawing went after a key or a control moved it.
|
|
84
|
+
* @csspart loading - The box in place of the list while `loading` is set and it holds no notes, holding the `loading` slot.
|
|
83
85
|
* @csspart note - One note in the list.
|
|
84
86
|
* @csspart note-cursor - The note the keyboard is on in the list.
|
|
85
87
|
* @csspart note-linked - A note linked to or from the selected one.
|
|
@@ -103,6 +105,7 @@ declare const HelixHeadlessGraph_base: (new (...args: any[]) => import("@fusion.
|
|
|
103
105
|
* @cssstate empty - The list holds no notes: the graph has none, or a search or the groups hid them all.
|
|
104
106
|
* @cssstate fullscreen - The graph fills the screen.
|
|
105
107
|
* @cssstate idle - The user has been still long enough for the header and footer to fade.
|
|
108
|
+
* @cssstate loading - While `loading` is set.
|
|
106
109
|
* @cssstate local - The drawing shows the selected note's local graph, with `depth`.
|
|
107
110
|
* @cssstate panel-open - A graph with `no-panel` has the search and the list open over the drawing.
|
|
108
111
|
* @cssstate ready - The graph has been drawn whole, after `helix-graph-ready`.
|
|
@@ -169,6 +172,13 @@ export declare class HelixHeadlessGraph extends HelixHeadlessGraph_base {
|
|
|
169
172
|
links: readonly GraphLink[];
|
|
170
173
|
/** How a note that links to the selected one is described, with `{note}`. */
|
|
171
174
|
linksToLabel: string;
|
|
175
|
+
/**
|
|
176
|
+
* Marks the graph as busy while its notes arrive: the list is `aria-busy`,
|
|
177
|
+
* and the panel says so where it holds no notes yet.
|
|
178
|
+
*/
|
|
179
|
+
loading: boolean;
|
|
180
|
+
/** What the panel says while `loading` is set and the list holds no notes. */
|
|
181
|
+
loadingLabel: string;
|
|
172
182
|
/** What screen readers hear once the drawing has moved down, after `moved()`. */
|
|
173
183
|
movedDownLabel: string;
|
|
174
184
|
/** What screen readers hear once the drawing has moved left, after `moved()`. */
|
|
@@ -185,6 +195,18 @@ export declare class HelixHeadlessGraph extends HelixHeadlessGraph_base {
|
|
|
185
195
|
* such as at the top of a page, where the drawing takes the whole frame.
|
|
186
196
|
*/
|
|
187
197
|
noPanel: boolean;
|
|
198
|
+
/**
|
|
199
|
+
* What each note's row in the list shows in place of its name: a function
|
|
200
|
+
* given the note that returns text, an element or a Lit template.
|
|
201
|
+
*
|
|
202
|
+
* For an icon by its kind, or a date under its name, as React Aria's
|
|
203
|
+
* `ListBoxItem` takes children. The row is still named by the note's name,
|
|
204
|
+
* which typeahead and the search find it by, and described by how it stands
|
|
205
|
+
* to the selected note. Return the name with your content where it should
|
|
206
|
+
* still show. A property only, there being no way to write a function in
|
|
207
|
+
* markup.
|
|
208
|
+
*/
|
|
209
|
+
noteContent?: ((node: GraphNode) => unknown) | undefined;
|
|
188
210
|
/** The list's name, read by screen readers, and the name of the button that opens it with `no-panel`. */
|
|
189
211
|
notesLabel: string;
|
|
190
212
|
/**
|
|
@@ -27,6 +27,8 @@ let HelixHeadlessGraph = class HelixHeadlessGraph extends MixinViewport(MixinCon
|
|
|
27
27
|
this.linkedFromLabel = 'Linked from {note}';
|
|
28
28
|
this.links = [];
|
|
29
29
|
this.linksToLabel = 'Links to {note}';
|
|
30
|
+
this.loading = false;
|
|
31
|
+
this.loadingLabel = 'Loading notes';
|
|
30
32
|
this.movedDownLabel = 'Moved down';
|
|
31
33
|
this.movedLeftLabel = 'Moved left';
|
|
32
34
|
this.movedRightLabel = 'Moved right';
|
|
@@ -163,6 +165,7 @@ let HelixHeadlessGraph = class HelixHeadlessGraph extends MixinViewport(MixinCon
|
|
|
163
165
|
super.willUpdate(changed);
|
|
164
166
|
this.toggleState('fullscreen', this.filled);
|
|
165
167
|
this.toggleState('idle', this.resting);
|
|
168
|
+
this.toggleState('loading', this.loading);
|
|
166
169
|
this.toggleState('panel-open', this.noPanel && this.panelOpen);
|
|
167
170
|
this.toggleState('searching', this.query.trim() !== '');
|
|
168
171
|
this.toggleState('selected', this.active !== '');
|
|
@@ -389,14 +392,15 @@ let HelixHeadlessGraph = class HelixHeadlessGraph extends MixinViewport(MixinCon
|
|
|
389
392
|
aria-selected=${chosen ? 'true' : 'false'}
|
|
390
393
|
aria-posinset=${index + 1}
|
|
391
394
|
aria-setsize=${total}
|
|
392
|
-
aria-
|
|
395
|
+
aria-describedby=${relation ? `note-${index}-relation` : nothing}
|
|
396
|
+
aria-label=${this.noteContent ? nameOf(entry.node) : nothing}
|
|
393
397
|
@click=${() => {
|
|
394
398
|
this.cursor = index;
|
|
395
399
|
this.choose(index);
|
|
396
400
|
}}
|
|
397
401
|
>
|
|
398
|
-
<span part="note-name">${nameOf(entry.node)}</span>
|
|
399
|
-
${relation ? html `<span part="note-relation" aria-hidden="true">${relation}</span>` : nothing}
|
|
402
|
+
<span part="note-name">${this.noteContent ? this.noteContent(entry.node) : nameOf(entry.node)}</span>
|
|
403
|
+
${relation ? html `<span part="note-relation" id=${`note-${index}-relation`} aria-hidden="true">${relation}</span>` : nothing}
|
|
400
404
|
</div>`;
|
|
401
405
|
})}`;
|
|
402
406
|
}
|
|
@@ -458,7 +462,7 @@ let HelixHeadlessGraph = class HelixHeadlessGraph extends MixinViewport(MixinCon
|
|
|
458
462
|
data-scroller
|
|
459
463
|
aria-label=${this.notesLabel}
|
|
460
464
|
aria-activedescendant=${cursor}
|
|
461
|
-
aria-
|
|
465
|
+
aria-busy=${this.loading ? 'true' : nothing}
|
|
462
466
|
@keydown=${this.handleListKeydown}
|
|
463
467
|
@scroll=${() => this.virtualize.measure()}
|
|
464
468
|
>
|
|
@@ -467,7 +471,9 @@ let HelixHeadlessGraph = class HelixHeadlessGraph extends MixinViewport(MixinCon
|
|
|
467
471
|
<div part="after" role="presentation" style="block-size: ${after}px"></div>
|
|
468
472
|
</div>
|
|
469
473
|
${this.entries.length === 0
|
|
470
|
-
?
|
|
474
|
+
? this.loading
|
|
475
|
+
? html `<div part="loading"><slot name="loading">${this.loadingLabel}</slot></div>`
|
|
476
|
+
: html `<div part="empty"><slot name="empty">${this.emptyLabel}</slot></div>`
|
|
471
477
|
: nothing}
|
|
472
478
|
</div>
|
|
473
479
|
</div>
|
|
@@ -529,6 +535,13 @@ __decorate([
|
|
|
529
535
|
words,
|
|
530
536
|
property({ attribute: 'links-to-label' })
|
|
531
537
|
], HelixHeadlessGraph.prototype, "linksToLabel", void 0);
|
|
538
|
+
__decorate([
|
|
539
|
+
property({ reflect: true, type: Boolean })
|
|
540
|
+
], HelixHeadlessGraph.prototype, "loading", void 0);
|
|
541
|
+
__decorate([
|
|
542
|
+
words,
|
|
543
|
+
property({ attribute: 'loading-label' })
|
|
544
|
+
], HelixHeadlessGraph.prototype, "loadingLabel", void 0);
|
|
532
545
|
__decorate([
|
|
533
546
|
words,
|
|
534
547
|
property({ attribute: 'moved-down-label' })
|
|
@@ -551,6 +564,9 @@ __decorate([
|
|
|
551
564
|
__decorate([
|
|
552
565
|
property({ attribute: 'no-panel', reflect: true, type: Boolean })
|
|
553
566
|
], HelixHeadlessGraph.prototype, "noPanel", void 0);
|
|
567
|
+
__decorate([
|
|
568
|
+
property({ attribute: false })
|
|
569
|
+
], HelixHeadlessGraph.prototype, "noteContent", void 0);
|
|
554
570
|
__decorate([
|
|
555
571
|
words,
|
|
556
572
|
property({ attribute: 'notes-label' })
|
|
@@ -244,7 +244,8 @@ export declare class HelixHeadlessList extends HelixElement {
|
|
|
244
244
|
/**
|
|
245
245
|
* The selected rows' values, separated by commas with no spaces, such as `a,c`, in a list that selects.
|
|
246
246
|
*
|
|
247
|
-
*
|
|
247
|
+
* A press or a key writes it in row order, as Data Table does, whatever
|
|
248
|
+
* order the rows were chosen in. Set it to start with rows selected. A row's value is its `value`, or its
|
|
248
249
|
* words where it has none.
|
|
249
250
|
*/
|
|
250
251
|
value: string;
|
|
@@ -328,6 +329,10 @@ export declare class HelixHeadlessList extends HelixElement {
|
|
|
328
329
|
/**
|
|
329
330
|
* Selects what a press or a key leaves, asking first. `helix-before-change`
|
|
330
331
|
* carries the `value` it would leave, and `change` follows once it has moved.
|
|
332
|
+
*
|
|
333
|
+
* In row order, as Data Table and Table write theirs, whatever order the
|
|
334
|
+
* rows were chosen in: a press on the fourth row and then the first is
|
|
335
|
+
* `a,d`.
|
|
331
336
|
*/
|
|
332
337
|
private choose;
|
|
333
338
|
/** What `choiceValue` needs of this list for a row. */
|
|
@@ -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 { auditName, commaList, customElement, deepActiveElement, drawStatus, focusItemOf, formatWords, HelixActionEvent, HelixElement, HelixLoadMoreEvent, hostAria, inlineStep, KeyboardNavigationController, placeKey, pressedOwnControl, ReorderController, requestReorder, requestValue, rovingStop, StatusController, scrollingAncestor, scrollRoom, selectsAll, typeaheadByWords, UpgradeController, whenHydrated, words, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { auditName, commaList, customElement, deepActiveElement, drawStatus, focusItemOf, formatWords, HelixActionEvent, HelixElement, HelixLoadMoreEvent, hostAria, inlineStep, inRowOrder, KeyboardNavigationController, placeKey, pressedOwnControl, ReorderController, requestReorder, requestValue, rovingStop, StatusController, scrollingAncestor, scrollRoom, selectsAll, typeaheadByWords, UpgradeController, whenHydrated, words, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessListItem } from '../item/list-item.js';
|
|
@@ -262,7 +262,8 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
|
|
|
262
262
|
if (next === null) {
|
|
263
263
|
return;
|
|
264
264
|
}
|
|
265
|
-
|
|
265
|
+
const ordered = inRowOrder(commaList(next), this.rows.map((row) => this.valueFor(row))).join(',');
|
|
266
|
+
requestValue(this, ordered, (value) => {
|
|
266
267
|
this.value = value;
|
|
267
268
|
});
|
|
268
269
|
}
|