@fusion.dev/helix-headless 0.32.0 → 0.33.1
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 +876 -164
- package/dist/area-chart/root/area-chart-root.d.ts +8 -0
- package/dist/area-chart/root/area-chart-root.js +1 -0
- package/dist/bar-chart/root/bar-chart-root.d.ts +8 -0
- package/dist/bar-chart/root/bar-chart-root.js +2 -1
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +1 -1
- package/dist/carousel/root/carousel-root.d.ts +12 -0
- package/dist/carousel/root/carousel-root.js +11 -7
- package/dist/chat/composer/chat-composer.d.ts +4 -0
- package/dist/chat/root/chat-root.d.ts +17 -0
- package/dist/chat/root/chat-root.js +12 -1
- package/dist/code-block/root/code-block-root.d.ts +25 -3
- package/dist/code-block/root/code-block-root.js +16 -5
- package/dist/color-picker/root/color-picker-root.js +2 -1
- package/dist/copy-button/root/copy-button-root.d.ts +8 -0
- package/dist/copy-button/root/copy-button-root.js +4 -1
- package/dist/data-table/root/data-table-root.d.ts +22 -3
- package/dist/data-table/root/data-table-root.js +25 -16
- package/dist/date-input/root/date-input-root.d.ts +34 -1
- package/dist/date-input/root/date-input-root.js +27 -1
- package/dist/date-picker/root/date-picker-root.js +6 -8
- package/dist/donut-chart/root/donut-chart-root.d.ts +21 -5
- package/dist/donut-chart/root/donut-chart-root.js +18 -6
- package/dist/drilldown/item/drilldown-item.js +1 -1
- package/dist/drilldown/root/drilldown-root.js +5 -4
- package/dist/heatmap/root/heatmap-root.d.ts +11 -2
- package/dist/icon/root/icon-root.d.ts +8 -0
- package/dist/icon/root/icon-root.js +5 -0
- package/dist/line-chart/root/line-chart-root.d.ts +9 -1
- package/dist/line-chart/root/line-chart-root.js +1 -0
- package/dist/menu/item/menu-item.js +1 -1
- package/dist/menu/root/menu-root.js +5 -4
- package/dist/object-inspector/root/object-inspector-root.d.ts +8 -0
- package/dist/object-inspector/root/object-inspector-root.js +20 -15
- package/dist/pagination/root/pagination-root.js +1 -1
- package/dist/pin-input/root/pin-input-root.d.ts +7 -1
- package/dist/pin-input/root/pin-input-root.js +5 -7
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +20 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +15 -9
- package/dist/scroll-area/root/scroll-area-root.js +3 -2
- package/dist/sparkline/root/sparkline-root.js +1 -0
- package/dist/splitter/root/splitter-root.d.ts +11 -0
- package/dist/splitter/root/splitter-root.js +16 -16
- package/dist/table/cell/table-cell.d.ts +2 -0
- package/dist/table/column/table-column.d.ts +40 -6
- package/dist/table/column/table-column.js +23 -3
- package/dist/table/root/table-root.d.ts +76 -11
- package/dist/table/root/table-root.js +90 -3
- package/dist/table/row/table-row.d.ts +14 -0
- package/dist/table/row/table-row.js +16 -0
- package/dist/toolbar/root/toolbar-root.js +6 -5
- package/dist/tooltip/root/tooltip-root.d.ts +20 -0
- package/dist/tooltip/root/tooltip-root.js +21 -3
- package/dist/tour/root/tour-root.js +1 -1
- package/dist/tour/stop/tour-stop.d.ts +10 -0
- package/dist/tour/stop/tour-stop.js +9 -2
- package/dist/tree/root/tree-root.js +4 -3
- package/dist/video/root/video-root.js +7 -0
- package/package.json +5 -5
- package/types/jsx.d.ts +1506 -596
- package/types/vue.d.ts +55 -23
|
@@ -60,6 +60,7 @@ let HelixHeadlessSparkline = class HelixHeadlessSparkline extends HelixElement {
|
|
|
60
60
|
return html `<svg
|
|
61
61
|
aria-hidden=${this.label === '' ? 'true' : nothing}
|
|
62
62
|
aria-label=${this.label === '' ? nothing : this.label}
|
|
63
|
+
data-mirror
|
|
63
64
|
part="svg"
|
|
64
65
|
preserveAspectRatio="none"
|
|
65
66
|
role=${this.label === '' ? nothing : 'img'}
|
|
@@ -332,6 +332,17 @@ export declare class HelixHeadlessSplitter extends HelixElement {
|
|
|
332
332
|
* only place in a splitter where a second axis means anything.
|
|
333
333
|
*/
|
|
334
334
|
private readonly handleKeydown;
|
|
335
|
+
/**
|
|
336
|
+
* Which way a key moves the divider, as a sign on `position`, or `0` for a key
|
|
337
|
+
* that is not along its axis.
|
|
338
|
+
*
|
|
339
|
+
* **The arrow says where the divider goes on screen**, the way the window
|
|
340
|
+
* splitter pattern words it: left moves a side-by-side divider to the left.
|
|
341
|
+
* `position` is the start pane's share, and the start pane is on the right of
|
|
342
|
+
* a right-to-left page, so there the left arrow grows it. It used to shrink
|
|
343
|
+
* it on every page, which on a right-to-left one sent the divider right.
|
|
344
|
+
*/
|
|
345
|
+
private travel;
|
|
335
346
|
/** Puts the divider back where the markup put it. */
|
|
336
347
|
private reset;
|
|
337
348
|
private readonly handleDoubleClick;
|
|
@@ -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 HelixHeadlessSplitter_1;
|
|
8
|
-
import { capturePointer, closestInstance, customElement, HelixBeforeCollapseEvent, HelixBeforeResizeEvent, HelixElement, requestChange, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { capturePointer, closestInstance, customElement, HelixBeforeCollapseEvent, HelixBeforeResizeEvent, HelixElement, inlineStep, requestChange, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { html } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
const STACK_BELOW = 512;
|
|
@@ -68,14 +68,10 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
|
|
|
68
68
|
this.settle(this.reached);
|
|
69
69
|
};
|
|
70
70
|
this.handleKeydown = (event) => {
|
|
71
|
-
const
|
|
72
|
-
const forward = this.vertical ? 'ArrowDown' : 'ArrowRight';
|
|
71
|
+
const toward = this.travel(event.key);
|
|
73
72
|
let next;
|
|
74
|
-
if (
|
|
75
|
-
next = this.position
|
|
76
|
-
}
|
|
77
|
-
else if (event.key === forward) {
|
|
78
|
-
next = this.position + this.step;
|
|
73
|
+
if (toward !== 0) {
|
|
74
|
+
next = this.position + toward * this.step;
|
|
79
75
|
}
|
|
80
76
|
else if (event.key === 'Home') {
|
|
81
77
|
next = this.minPercent;
|
|
@@ -171,15 +167,13 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
|
|
|
171
167
|
return;
|
|
172
168
|
}
|
|
173
169
|
const inner = crossing.by;
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (event.key === mineBack || event.key === mineForward) {
|
|
179
|
-
this.moveTo(this.position + (event.key === mineBack ? -this.step : this.step), true);
|
|
170
|
+
const mine = this.travel(event.key);
|
|
171
|
+
const theirs = inner.travel(event.key);
|
|
172
|
+
if (mine !== 0) {
|
|
173
|
+
this.moveTo(this.position + mine * this.step, true);
|
|
180
174
|
}
|
|
181
|
-
else if (
|
|
182
|
-
inner.moveTo(inner.position +
|
|
175
|
+
else if (theirs !== 0) {
|
|
176
|
+
inner.moveTo(inner.position + theirs * inner.step, true);
|
|
183
177
|
}
|
|
184
178
|
else {
|
|
185
179
|
return;
|
|
@@ -332,6 +326,12 @@ let HelixHeadlessSplitter = HelixHeadlessSplitter_1 = class HelixHeadlessSplitte
|
|
|
332
326
|
});
|
|
333
327
|
}
|
|
334
328
|
}
|
|
329
|
+
travel(key) {
|
|
330
|
+
if (!this.vertical) {
|
|
331
|
+
return inlineStep(this, key);
|
|
332
|
+
}
|
|
333
|
+
return key === 'ArrowDown' ? 1 : key === 'ArrowUp' ? -1 : 0;
|
|
334
|
+
}
|
|
335
335
|
reset() {
|
|
336
336
|
const home = this.clamp(this.defaultPosition);
|
|
337
337
|
this.move(home);
|
|
@@ -18,6 +18,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
18
18
|
* @documentation https://helix.fusion.dev/components/table
|
|
19
19
|
*
|
|
20
20
|
* @slot - The cell's content.
|
|
21
|
+
*
|
|
22
|
+
* @cssproperty --table-cell-align - The edge the column this cell sits under is set to, `start`, `center` or `end`, and unset under a column that sets none. Written by the table around it, since the cell is the consumer's markup and nothing is written onto it; read by the sheet that draws the cell, where `justify-content` and `text-align` both take it as it comes and both follow the writing direction.
|
|
21
23
|
*/
|
|
22
24
|
export declare class HelixHeadlessTableCell extends HelixElement {
|
|
23
25
|
/**
|
|
@@ -47,6 +47,15 @@ export declare const at: (row: Readonly<Record<string, unknown>>, path: string)
|
|
|
47
47
|
* item of the table, so it lines up with the cells under it rather than sitting
|
|
48
48
|
* in a wrapper that has to be kept the same width.
|
|
49
49
|
*
|
|
50
|
+
* **`hidden` takes the column out of the grid**, its heading and its track
|
|
51
|
+
* both, so the columns after it keep their own widths and every row keeps its
|
|
52
|
+
* cells under their headings. `hidden="until-found"` keeps its track, the
|
|
53
|
+
* heading being left drawn, as every Helix element leaves one with that value.
|
|
54
|
+
* `helix-data-table` draws the cells, so it leaves out the ones under a hidden
|
|
55
|
+
* column. A `helix-table`'s cells are markup the consumer wrote, so hide them
|
|
56
|
+
* with the column, as removing a column means removing its cells: a row with a
|
|
57
|
+
* cell more than the table has tracks wraps into the next.
|
|
58
|
+
*
|
|
50
59
|
* **A heading that does something holds a control that does it.** The host is
|
|
51
60
|
* the column header, and a header is not focusable, so a sortable heading is a
|
|
52
61
|
* `<button>` inside it: the pattern for a sortable table, and the only way a
|
|
@@ -80,9 +89,12 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
80
89
|
* `end` is what a column of numbers wants, so digits of the same magnitude sit
|
|
81
90
|
* above each other. Left unset the cell inherits the table's own alignment,
|
|
82
91
|
* which is `start` for text in either writing direction. `helix-data-table`
|
|
83
|
-
* aligns the cells it draws
|
|
84
|
-
* wrote,
|
|
85
|
-
*
|
|
92
|
+
* aligns the cells it draws. A `helix-table`'s cells are markup the consumer
|
|
93
|
+
* wrote, so the table writes nothing onto them: it publishes the edge to each
|
|
94
|
+
* cell under this column as `--table-cell-align`, which `@fusion.dev/helix`
|
|
95
|
+
* reads. The heading is this element's own, and `@fusion.dev/helix` sets it to
|
|
96
|
+
* the same edge in either table. `end` is the inline end, so in a
|
|
97
|
+
* right-to-left table it is the left.
|
|
86
98
|
*
|
|
87
99
|
* **Reflected, because the heading is drawn by a stylesheet and has no other
|
|
88
100
|
* way to learn it.** Set as a property, which is how React sets it, an
|
|
@@ -143,14 +155,24 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
143
155
|
* Ignored without a `field`, and silently: a column with nothing to sort by
|
|
144
156
|
* has no order to offer, and refusing loudly would mean an actions column
|
|
145
157
|
* carrying `sortable` breaks a table rather than doing nothing.
|
|
158
|
+
*
|
|
159
|
+
* **Reflected, because a stylesheet selects on it.** `@fusion.dev/helix`
|
|
160
|
+
* gives a data table's sortable headings a pointer through
|
|
161
|
+
* `::slotted(helix-table-column[sortable])`, and set as a property, which is
|
|
162
|
+
* how React sets it, an unreflected `sortable` left no attribute to match.
|
|
163
|
+
* `false` reflects as no attribute at all, so an unset column writes nothing
|
|
164
|
+
* onto its host.
|
|
146
165
|
*/
|
|
147
166
|
sortable: boolean;
|
|
148
167
|
/**
|
|
149
168
|
* The track this column takes, as CSS.
|
|
150
169
|
*
|
|
151
170
|
* A single track value, so anything valid in `grid-template-columns` works:
|
|
152
|
-
* `16rem`, `auto`, `minmax(0, 2fr)`. Left unset the column
|
|
153
|
-
*
|
|
171
|
+
* `16rem`, `auto`, `minmax(0, 2fr)`. Left unset the column takes the track
|
|
172
|
+
* in its place in a `helix-table`'s `columns`, where that table sets one, and
|
|
173
|
+
* otherwise shares what is left over equally, as `minmax(max-content, 1fr)`.
|
|
174
|
+
* Set here, it wins over that list, which is what lets a reader resize a
|
|
175
|
+
* column in a table that set one.
|
|
154
176
|
*
|
|
155
177
|
* **The floor is `max-content`, never `0` and never `min-content`.** A zero
|
|
156
178
|
* floor lets a track shrink under its own content: at 375 the columns squeeze
|
|
@@ -194,6 +216,8 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
194
216
|
private resizing;
|
|
195
217
|
/** Watches the heading's width, which changes with the table as well as with a drag. */
|
|
196
218
|
private watcher;
|
|
219
|
+
/** Watches `hidden`, which is the platform's attribute and no property of this element's. */
|
|
220
|
+
private hiding;
|
|
197
221
|
/**
|
|
198
222
|
* The narrowest a reader can drag a column, in pixels.
|
|
199
223
|
*
|
|
@@ -206,6 +230,13 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
206
230
|
static readonly STEP = 16;
|
|
207
231
|
/** The track this column contributes, resolved. */
|
|
208
232
|
get track(): string;
|
|
233
|
+
/**
|
|
234
|
+
* @internal Whether this column takes a track, read by the table that holds
|
|
235
|
+
* it. Not a consumer's to read: `hidden` is the setting. Read off the
|
|
236
|
+
* attribute the way `HelixElement` hides a host, so the table drops a track
|
|
237
|
+
* exactly when the heading stops being drawn.
|
|
238
|
+
*/
|
|
239
|
+
get shown(): boolean;
|
|
209
240
|
/** Whether a reader can actually reorder by this column. */
|
|
210
241
|
get canSort(): boolean;
|
|
211
242
|
/**
|
|
@@ -225,6 +256,9 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
225
256
|
private observeHeading;
|
|
226
257
|
disconnectedCallback(): void;
|
|
227
258
|
protected firstUpdated(changed: PropertyValues): void;
|
|
259
|
+
protected updated(changed: PropertyValues): void;
|
|
260
|
+
/** Asks whatever holds this column to render, since it reads the column when it does. */
|
|
261
|
+
private tellHolder;
|
|
228
262
|
/**
|
|
229
263
|
* Asks for a width, in pixels, no narrower than a column can be read at.
|
|
230
264
|
*
|
|
@@ -232,7 +266,7 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
232
266
|
* applied only where nobody refused it.
|
|
233
267
|
*/
|
|
234
268
|
private resizeTo;
|
|
235
|
-
/** Which way a drag
|
|
269
|
+
/** Which way a drag grows the column, in this writing direction. */
|
|
236
270
|
private get forward();
|
|
237
271
|
private readonly handleResizeStart;
|
|
238
272
|
private readonly handleResizeMove;
|
|
@@ -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 HelixHeadlessTableColumn_1;
|
|
8
|
-
import { customElement, HelixBeforeResizeEvent, HelixElement, hostAria, requestChange, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { customElement, HelixBeforeResizeEvent, HelixElement, hostAria, inlineStep, requestChange, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { dotsThreeVertical } from '@fusion.dev/helix-icons';
|
|
10
10
|
import { html, nothing } from 'lit';
|
|
11
11
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -62,7 +62,7 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
62
62
|
};
|
|
63
63
|
this.handleResizeKey = (event) => {
|
|
64
64
|
const step = HelixHeadlessTableColumn_1.STEP * (event.shiftKey ? 4 : 1);
|
|
65
|
-
const grow =
|
|
65
|
+
const grow = inlineStep(this, event.key);
|
|
66
66
|
if (grow !== 0) {
|
|
67
67
|
event.preventDefault();
|
|
68
68
|
this.resizeTo(this.drawn + grow * step);
|
|
@@ -79,6 +79,10 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
79
79
|
get track() {
|
|
80
80
|
return this.width || 'minmax(max-content, 1fr)';
|
|
81
81
|
}
|
|
82
|
+
get shown() {
|
|
83
|
+
const hidden = this.getAttribute('hidden');
|
|
84
|
+
return hidden === null || hidden === 'until-found';
|
|
85
|
+
}
|
|
82
86
|
get canSort() {
|
|
83
87
|
return this.sortable && this.field !== '';
|
|
84
88
|
}
|
|
@@ -108,6 +112,10 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
108
112
|
});
|
|
109
113
|
this.observeHeading();
|
|
110
114
|
}
|
|
115
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
116
|
+
this.hiding = new MutationObserver(() => this.tellHolder());
|
|
117
|
+
this.hiding.observe(this, { attributeFilter: ['hidden'] });
|
|
118
|
+
}
|
|
111
119
|
}
|
|
112
120
|
observeHeading() {
|
|
113
121
|
const heading = this.partNamed('column');
|
|
@@ -118,11 +126,23 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
118
126
|
disconnectedCallback() {
|
|
119
127
|
super.disconnectedCallback();
|
|
120
128
|
this.watcher?.disconnect();
|
|
129
|
+
this.hiding?.disconnect();
|
|
130
|
+
this.hiding = undefined;
|
|
121
131
|
}
|
|
122
132
|
firstUpdated(changed) {
|
|
123
133
|
super.firstUpdated?.(changed);
|
|
124
134
|
this.observeHeading();
|
|
125
135
|
}
|
|
136
|
+
updated(changed) {
|
|
137
|
+
super.updated(changed);
|
|
138
|
+
if (changed.has('align') || changed.has('width')) {
|
|
139
|
+
this.tellHolder();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
tellHolder() {
|
|
143
|
+
;
|
|
144
|
+
this.parentElement?.requestUpdate?.();
|
|
145
|
+
}
|
|
126
146
|
resizeTo(px) {
|
|
127
147
|
const next = `${Math.max(HelixHeadlessTableColumn_1.NARROWEST, Math.round(px))}px`;
|
|
128
148
|
if (next === this.width) {
|
|
@@ -186,7 +206,7 @@ __decorate([
|
|
|
186
206
|
property({ type: Boolean })
|
|
187
207
|
], HelixHeadlessTableColumn.prototype, "resizable", void 0);
|
|
188
208
|
__decorate([
|
|
189
|
-
property({ type: Boolean })
|
|
209
|
+
property({ reflect: true, type: Boolean })
|
|
190
210
|
], HelixHeadlessTableColumn.prototype, "sortable", void 0);
|
|
191
211
|
__decorate([
|
|
192
212
|
property()
|
|
@@ -39,15 +39,24 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
|
|
|
39
39
|
*/
|
|
40
40
|
export declare class HelixHeadlessTable extends HelixHeadlessTable_base {
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* The column widths as one track list, written once on the table.
|
|
43
43
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* the
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* and
|
|
44
|
+
* With `helix-table-column` children, each track sizes the column in its
|
|
45
|
+
* place, a hidden column counted, so hiding one takes its track with it and
|
|
46
|
+
* the rest keep theirs. The columns decide how many tracks there are and this
|
|
47
|
+
* list only how wide: a track past the last column is dropped, and a column
|
|
48
|
+
* past the last track shares what is left. With no columns declared it is
|
|
49
|
+
* the whole track list. Tracks count as the grid counts them, so
|
|
50
|
+
* `minmax(0, 1fr)` is one and `repeat(2, 8rem)` is two, and one the grid
|
|
51
|
+
* would refuse leaves its column at the default rather than taking the table
|
|
52
|
+
* down to one column.
|
|
53
|
+
*
|
|
54
|
+
* **A column's own `width` wins over its track here.** The width is written
|
|
55
|
+
* on the column it sizes, which is the more particular statement, and it is
|
|
56
|
+
* where a resize lands: a reader dragging a column's edge writes `width`, so
|
|
57
|
+
* were this list to win, the drag would move the separator and leave the
|
|
58
|
+
* track where the list put it. This is the table's default for its columns,
|
|
59
|
+
* and each column may say otherwise.
|
|
51
60
|
*/
|
|
52
61
|
columns: string;
|
|
53
62
|
/**
|
|
@@ -60,12 +69,29 @@ export declare class HelixHeadlessTable extends HelixHeadlessTable_base {
|
|
|
60
69
|
* The track list, from the columns if there are any.
|
|
61
70
|
*
|
|
62
71
|
* Read from the DOM rather than kept, so adding or removing a column needs
|
|
63
|
-
* nothing else to be told.
|
|
64
|
-
*
|
|
65
|
-
*
|
|
72
|
+
* nothing else to be told. A hidden column takes no track: left in, the
|
|
73
|
+
* header row had a heading fewer than the grid had tracks, the first cell
|
|
74
|
+
* filled the gap, and every row after it began a column late. Falls back to
|
|
75
|
+
* the `columns` string for a table that declares no columns, and to a single
|
|
76
|
+
* track for one that declares neither.
|
|
66
77
|
*/
|
|
67
78
|
private get template();
|
|
68
79
|
private readonly handleSlotChange;
|
|
80
|
+
/**
|
|
81
|
+
* Watches the light DOM for rows and columns arriving, leaving and moving.
|
|
82
|
+
*
|
|
83
|
+
* **A manually assigned slot does not announce them**, the same gap `Chat`
|
|
84
|
+
* and `Carousel` watch for. Under `slotAssignment: 'manual'` only `assign`
|
|
85
|
+
* changes an assignment, so a row appended after the first render reached no
|
|
86
|
+
* slot and drew nowhere, and a column moved to another place lost its
|
|
87
|
+
* assignment on the way out and never got it back: measured in Chromium, both
|
|
88
|
+
* `assignedSlot` null a render later. A table whose definition loaded before
|
|
89
|
+
* its markup was parsed drew no columns at all, having rendered before any
|
|
90
|
+
* arrived.
|
|
91
|
+
*/
|
|
92
|
+
private watcher;
|
|
93
|
+
connectedCallback(): void;
|
|
94
|
+
disconnectedCallback(): void;
|
|
69
95
|
/**
|
|
70
96
|
* Nothing is assigned by name, so the columns can be put in a row.
|
|
71
97
|
*
|
|
@@ -88,6 +114,45 @@ export declare class HelixHeadlessTable extends HelixHeadlessTable_base {
|
|
|
88
114
|
/** The rows: every child that is not a column, which is what the body slot is assigned. */
|
|
89
115
|
protected get slotted(): Element[];
|
|
90
116
|
private assign;
|
|
117
|
+
/**
|
|
118
|
+
* The rules handing each column's `align` to the cells under it. One sheet for
|
|
119
|
+
* every row this table holds, rewritten in place, so a column changing its
|
|
120
|
+
* edge reaches every row in one write.
|
|
121
|
+
*/
|
|
122
|
+
private alignment;
|
|
123
|
+
/** What `alignment` was last written with, so a render that changed no edge writes nothing. */
|
|
124
|
+
private aligned;
|
|
125
|
+
/**
|
|
126
|
+
* Tells every row which edge each of its cells lines up against.
|
|
127
|
+
*
|
|
128
|
+
* **A rule in each row's shadow root, keyed on position and written by this
|
|
129
|
+
* table.** The cells are the consumer's markup, so nothing may be written onto
|
|
130
|
+
* them, and each of the other ways fails somewhere a table goes:
|
|
131
|
+
*
|
|
132
|
+
* - This element's own sheet cannot reach them. `::slotted()` matches what is
|
|
133
|
+
* assigned here, which is the rows, and never a row's children.
|
|
134
|
+
* - A property per column published here, `--table-align-2: end`, still needs
|
|
135
|
+
* a rule that knows which column a cell is in, and a fixed ladder of
|
|
136
|
+
* `:nth-child` rules in a static sheet is a ceiling on the column count.
|
|
137
|
+
* - A custom state set on each cell by script is right only until a cell
|
|
138
|
+
* moves, and a cell moving inside a row changes no child list this element
|
|
139
|
+
* watches.
|
|
140
|
+
*
|
|
141
|
+
* `:nth-child` is matched by the browser against wherever a cell is now, so a
|
|
142
|
+
* cell that moves takes its new column's edge with no script at all; a column
|
|
143
|
+
* that moves rewrites the rules on the render the watcher asks for; and a
|
|
144
|
+
* column hidden along with its cells keeps its place in both counts, since
|
|
145
|
+
* `:nth-child` counts a hidden sibling the way `tableColumns` counts a hidden
|
|
146
|
+
* column. The row is where they go because only the shadow root holding a
|
|
147
|
+
* slot can style what is assigned to it.
|
|
148
|
+
*
|
|
149
|
+
* **A custom property and nothing else**, which is how this tier publishes a
|
|
150
|
+
* fact: the edge is the author's declaration, and what lining up means, a
|
|
151
|
+
* `justify-content` or a `text-align`, belongs to whoever draws the cell.
|
|
152
|
+
* `initial` on every cell first, so a table nested in an aligned cell does not
|
|
153
|
+
* take the outer column's edge for columns of its own that set none.
|
|
154
|
+
*/
|
|
155
|
+
private alignCells;
|
|
91
156
|
protected updated(changed: PropertyValues): void;
|
|
92
157
|
protected render(): TemplateResult;
|
|
93
158
|
}
|
|
@@ -7,6 +7,56 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { customElement, HelixElement, MixinCollection } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
const EDGES = new Set(['center', 'end', 'start']);
|
|
11
|
+
const tracksOf = (list, wanted) => {
|
|
12
|
+
const words = [];
|
|
13
|
+
let depth = 0;
|
|
14
|
+
let word = '';
|
|
15
|
+
for (const char of list.trim()) {
|
|
16
|
+
if (char === '(' || char === '[') {
|
|
17
|
+
depth += 1;
|
|
18
|
+
}
|
|
19
|
+
else if (char === ')' || char === ']') {
|
|
20
|
+
depth -= 1;
|
|
21
|
+
}
|
|
22
|
+
if (depth === 0 && /\s/.test(char)) {
|
|
23
|
+
if (word) {
|
|
24
|
+
words.push(word);
|
|
25
|
+
}
|
|
26
|
+
word = '';
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
word += char;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (word) {
|
|
33
|
+
words.push(word);
|
|
34
|
+
}
|
|
35
|
+
const valid = (track) => typeof CSS === 'undefined' || CSS.supports('grid-template-columns', track);
|
|
36
|
+
const tracks = [];
|
|
37
|
+
let names = '';
|
|
38
|
+
for (const one of words) {
|
|
39
|
+
if (tracks.length >= wanted) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
if (one.startsWith('[')) {
|
|
43
|
+
names += `${one} `;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const repeat = /^repeat\(\s*(\d+)\s*,(.*)\)$/is.exec(one);
|
|
47
|
+
if (repeat) {
|
|
48
|
+
const inner = tracksOf(repeat[2] ?? '', wanted);
|
|
49
|
+
for (let time = 0; time < Number(repeat[1]) && tracks.length < wanted; time += 1) {
|
|
50
|
+
tracks.push(...inner.map((track, index) => (time === 0 && index === 0 ? names + track : track)));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (!/^repeat\(/i.test(one)) {
|
|
54
|
+
tracks.push(valid(names + one) ? names + one : '');
|
|
55
|
+
}
|
|
56
|
+
names = '';
|
|
57
|
+
}
|
|
58
|
+
return tracks.slice(0, wanted);
|
|
59
|
+
};
|
|
10
60
|
let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixElement) {
|
|
11
61
|
constructor() {
|
|
12
62
|
super(...arguments);
|
|
@@ -15,16 +65,32 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
|
|
|
15
65
|
this.handleSlotChange = () => {
|
|
16
66
|
this.requestUpdate();
|
|
17
67
|
};
|
|
68
|
+
this.watcher = undefined;
|
|
69
|
+
this.alignment = undefined;
|
|
70
|
+
this.aligned = '';
|
|
18
71
|
}
|
|
19
72
|
get tableColumns() {
|
|
20
73
|
return this.knownChildren.filter((child) => 'isTableColumn' in child && child.isTableColumn === true);
|
|
21
74
|
}
|
|
22
75
|
get template() {
|
|
23
76
|
const declared = this.tableColumns;
|
|
24
|
-
if (declared.length
|
|
25
|
-
return
|
|
77
|
+
if (declared.length === 0) {
|
|
78
|
+
return this.columns;
|
|
26
79
|
}
|
|
27
|
-
|
|
80
|
+
const listed = tracksOf(this.columns, declared.length);
|
|
81
|
+
return declared
|
|
82
|
+
.flatMap((column, index) => column.shown ? [column.width ? column.track : listed[index] || column.track] : [])
|
|
83
|
+
.join(' ');
|
|
84
|
+
}
|
|
85
|
+
connectedCallback() {
|
|
86
|
+
super.connectedCallback();
|
|
87
|
+
this.watcher = new MutationObserver(() => this.requestUpdate());
|
|
88
|
+
this.watcher.observe(this, { childList: true });
|
|
89
|
+
}
|
|
90
|
+
disconnectedCallback() {
|
|
91
|
+
super.disconnectedCallback();
|
|
92
|
+
this.watcher?.disconnect();
|
|
93
|
+
this.watcher = undefined;
|
|
28
94
|
}
|
|
29
95
|
static { this.shadowRootOptions = {
|
|
30
96
|
...HelixElement.shadowRootOptions,
|
|
@@ -49,9 +115,30 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
|
|
|
49
115
|
head.assign(...this.tableColumns);
|
|
50
116
|
body.assign(...this.slotted);
|
|
51
117
|
}
|
|
118
|
+
alignCells() {
|
|
119
|
+
if (typeof CSSStyleSheet === 'undefined' || !('replaceSync' in CSSStyleSheet.prototype)) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const rules = this.tableColumns.flatMap((column, index) => column.align && EDGES.has(column.align)
|
|
123
|
+
? [`::slotted(:nth-child(${index + 1})) { --table-cell-align: ${column.align}; }`]
|
|
124
|
+
: []);
|
|
125
|
+
const text = ['::slotted(*) { --table-cell-align: initial; }', ...rules].join('\n');
|
|
126
|
+
this.alignment ??= new CSSStyleSheet();
|
|
127
|
+
if (text !== this.aligned) {
|
|
128
|
+
this.alignment.replaceSync(text);
|
|
129
|
+
this.aligned = text;
|
|
130
|
+
}
|
|
131
|
+
for (const row of this.slotted) {
|
|
132
|
+
if ('isTableRow' in row) {
|
|
133
|
+
;
|
|
134
|
+
row.alignCells(this.alignment);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
52
138
|
updated(changed) {
|
|
53
139
|
super.updated(changed);
|
|
54
140
|
this.assign();
|
|
141
|
+
this.alignCells();
|
|
55
142
|
}
|
|
56
143
|
render() {
|
|
57
144
|
const template = this.template;
|
|
@@ -17,6 +17,20 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
17
17
|
* @slot - The row's cells.
|
|
18
18
|
*/
|
|
19
19
|
export declare class HelixHeadlessTableRow extends HelixElement {
|
|
20
|
+
/**
|
|
21
|
+
* @internal Read by the table to find its rows among its children, the way it
|
|
22
|
+
* finds its columns. Not a consumer's to read or set.
|
|
23
|
+
*/
|
|
24
|
+
readonly isTableRow = true;
|
|
25
|
+
/** The table's rules this row holds, so the next ones replace them rather than pile up. */
|
|
26
|
+
private columnRules;
|
|
27
|
+
/**
|
|
28
|
+
* @internal Takes the rules the table wrote to line each cell up under its
|
|
29
|
+
* heading, called by that table. Not a consumer's to call: the rules are the
|
|
30
|
+
* table's, and they say which column a cell is in by counting, which only the
|
|
31
|
+
* table that holds the columns can do.
|
|
32
|
+
*/
|
|
33
|
+
alignCells(rules: CSSStyleSheet): void;
|
|
20
34
|
protected willUpdate(changed: PropertyValues): void;
|
|
21
35
|
protected render(): TemplateResult;
|
|
22
36
|
}
|
|
@@ -7,6 +7,22 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
this.isTableRow = true;
|
|
13
|
+
this.columnRules = undefined;
|
|
14
|
+
}
|
|
15
|
+
alignCells(rules) {
|
|
16
|
+
const root = this.renderRoot;
|
|
17
|
+
if (rules === this.columnRules || !(root instanceof ShadowRoot)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
root.adoptedStyleSheets = [
|
|
21
|
+
...root.adoptedStyleSheets.filter((sheet) => sheet !== this.columnRules),
|
|
22
|
+
rules,
|
|
23
|
+
];
|
|
24
|
+
this.columnRules = rules;
|
|
25
|
+
}
|
|
10
26
|
willUpdate(changed) {
|
|
11
27
|
super.willUpdate(changed);
|
|
12
28
|
hostAria(this.internals, { role: '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 { customElement, HelixElement } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, inlineStep } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
const KEYS = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End']);
|
|
@@ -41,21 +41,22 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
this.handleKeydown = (event) => {
|
|
44
|
-
const forward = this.axis === 'horizontal' ? 'ArrowRight' : 'ArrowDown';
|
|
45
|
-
const back = this.axis === 'horizontal' ? 'ArrowLeft' : 'ArrowUp';
|
|
46
44
|
if (!KEYS.has(event.key) || claimed(event)) {
|
|
47
45
|
return;
|
|
48
46
|
}
|
|
47
|
+
const along = inlineStep(this, event.key);
|
|
48
|
+
const forward = this.axis === 'horizontal' ? along === 1 : event.key === 'ArrowDown';
|
|
49
|
+
const back = this.axis === 'horizontal' ? along === -1 : event.key === 'ArrowUp';
|
|
49
50
|
const controls = this.controls;
|
|
50
51
|
const current = controls.findIndex((entry) => entry.contains(event.target));
|
|
51
52
|
if (current === -1) {
|
|
52
53
|
return;
|
|
53
54
|
}
|
|
54
55
|
let next = current;
|
|
55
|
-
if (
|
|
56
|
+
if (forward) {
|
|
56
57
|
next = (current + 1) % controls.length;
|
|
57
58
|
}
|
|
58
|
-
else if (
|
|
59
|
+
else if (back) {
|
|
59
60
|
next = (current - 1 + controls.length) % controls.length;
|
|
60
61
|
}
|
|
61
62
|
else if (event.key === 'Home') {
|
|
@@ -52,9 +52,21 @@ declare const HelixHeadlessTooltip_base: (new (...args: any[]) => import("@fusio
|
|
|
52
52
|
* @event {Event} toggle - Says the state moved, carrying `newState` and `oldState`.
|
|
53
53
|
*
|
|
54
54
|
* @csspart arrow - The point, resting against the trigger.
|
|
55
|
+
* @csspart arrow-bottom - The point while the bubble is below its trigger, so on the bubble's top edge, beside `arrow`.
|
|
56
|
+
* @csspart arrow-left - The point while the bubble is left of its trigger, so on the bubble's right edge, beside `arrow`.
|
|
57
|
+
* @csspart arrow-right - The point while the bubble is right of its trigger, so on the bubble's left edge, beside `arrow`.
|
|
58
|
+
* @csspart arrow-top - The point while the bubble is above its trigger, so on the bubble's bottom edge, beside `arrow`.
|
|
55
59
|
* @csspart tooltip - The bubble.
|
|
60
|
+
* @csspart tooltip-bottom - The bubble while it is below its trigger, beside `tooltip`.
|
|
61
|
+
* @csspart tooltip-left - The bubble while it is left of its trigger, beside `tooltip`.
|
|
62
|
+
* @csspart tooltip-right - The bubble while it is right of its trigger, beside `tooltip`.
|
|
63
|
+
* @csspart tooltip-top - The bubble while it is above its trigger, beside `tooltip`.
|
|
56
64
|
*
|
|
57
65
|
* @cssstate open - While the tooltip shows.
|
|
66
|
+
* @cssstate placed-bottom - While the bubble sits below its trigger.
|
|
67
|
+
* @cssstate placed-left - While the bubble sits to the left of its trigger.
|
|
68
|
+
* @cssstate placed-right - While the bubble sits to the right of its trigger.
|
|
69
|
+
* @cssstate placed-top - While the bubble sits above its trigger.
|
|
58
70
|
*/
|
|
59
71
|
export declare class HelixHeadlessTooltip extends HelixHeadlessTooltip_base {
|
|
60
72
|
/**
|
|
@@ -150,6 +162,14 @@ export declare class HelixHeadlessTooltip extends HelixHeadlessTooltip_base {
|
|
|
150
162
|
* `FloatingController` for what happens if it is applied to the rest.
|
|
151
163
|
*/
|
|
152
164
|
within: string;
|
|
165
|
+
/**
|
|
166
|
+
* The side of its trigger the bubble last landed on, which is not always
|
|
167
|
+
* `placement`: a bubble with no room there is moved.
|
|
168
|
+
*
|
|
169
|
+
* Undefined until the first placement, which the server never makes, so a
|
|
170
|
+
* part name it adds is never markup the server did not send.
|
|
171
|
+
*/
|
|
172
|
+
private side?;
|
|
153
173
|
private timer;
|
|
154
174
|
/**
|
|
155
175
|
* What is currently keeping the bubble up.
|