@fusion.dev/helix-headless 0.31.0 → 0.33.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 +880 -177
- 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 +17 -11
- 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 +8 -0
- package/dist/code-block/root/code-block-root.js +4 -1
- 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.d.ts +36 -1
- package/dist/drilldown/item/drilldown-item.js +30 -3
- 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 +50 -5
- package/dist/table/column/table-column.js +24 -5
- 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 +15 -0
- package/dist/tour/stop/tour-stop.js +16 -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 +1556 -582
- package/types/vue.d.ts +65 -22
|
@@ -46,6 +46,17 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
46
46
|
* a `<span>` placed by percentage over it, which is how `LineChart` draws its
|
|
47
47
|
* termini and for the same reason.
|
|
48
48
|
*
|
|
49
|
+
* **Left to right on every page, the one chart here that is.** A bar or a line
|
|
50
|
+
* chart's across is the order its readings are named in, which follows the
|
|
51
|
+
* line of text and turns with it. Here it is a measure, and a measure has a
|
|
52
|
+
* direction of its own: more is to the right in every script, as a number line
|
|
53
|
+
* is. So the plot, its axes and the names at their ends sit in a `plane` part
|
|
54
|
+
* that carries `dir="ltr"`, which holds the y axis on the left and the points,
|
|
55
|
+
* rules, ticks, pointer and tooltip mark where a left-to-right page puts them,
|
|
56
|
+
* with no stylesheet asked to know. The names carry `dir="auto"`, so one written
|
|
57
|
+
* in Arabic or Hebrew still reads its own way; the summary is outside the plane
|
|
58
|
+
* and the bubble is told the page's direction, both being words.
|
|
59
|
+
*
|
|
49
60
|
* @since 0.1.0
|
|
50
61
|
* @status experimental
|
|
51
62
|
* @category charts
|
|
@@ -54,6 +65,7 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
54
65
|
*
|
|
55
66
|
* @csspart gridline - One rule across the plot, under `gridlines`.
|
|
56
67
|
* @csspart mark - The invisible point the tooltip is anchored to.
|
|
68
|
+
* @csspart plane - The plot, both axes and their names, left to right on every page. The grid they are laid out in.
|
|
57
69
|
* @csspart plot - The drawing.
|
|
58
70
|
* @csspart point - One row, as a point.
|
|
59
71
|
* @csspart point-active - A point of the row a pointer is asking about, beside `point`.
|
|
@@ -62,9 +74,17 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
62
74
|
* @csspart tooltip - The bubble, forwarded from `Tooltip`.
|
|
63
75
|
* @csspart tooltip-anchor - The `Tooltip` element itself.
|
|
64
76
|
* @csspart tooltip-arrow - The bubble's point, forwarded from `Tooltip`.
|
|
77
|
+
* @csspart tooltip-arrow-bottom - The point while the bubble is below the reading, so on its top edge, beside `tooltip-arrow`.
|
|
78
|
+
* @csspart tooltip-arrow-left - The point while the bubble is left of the reading, so on its right edge, beside `tooltip-arrow`.
|
|
79
|
+
* @csspart tooltip-arrow-right - The point while the bubble is right of the reading, so on its left edge, beside `tooltip-arrow`.
|
|
80
|
+
* @csspart tooltip-arrow-top - The point while the bubble is above the reading, so on its bottom edge, beside `tooltip-arrow`.
|
|
81
|
+
* @csspart tooltip-bottom - The bubble while it is below the reading, beside `tooltip`.
|
|
65
82
|
* @csspart tooltip-cell - One column's name and value inside the tooltip.
|
|
66
83
|
* @csspart tooltip-label - The row's own name inside the tooltip.
|
|
84
|
+
* @csspart tooltip-left - The bubble while it is left of the reading, beside `tooltip`.
|
|
67
85
|
* @csspart tooltip-name - A column's name inside the tooltip.
|
|
86
|
+
* @csspart tooltip-right - The bubble while it is right of the reading, beside `tooltip`.
|
|
87
|
+
* @csspart tooltip-top - The bubble while it is above the reading, beside `tooltip`.
|
|
68
88
|
* @csspart tooltip-value - A column's value inside the tooltip.
|
|
69
89
|
* @csspart x-axis - The levels measured across, under the plot.
|
|
70
90
|
* @csspart x-name - What is measured across.
|
|
@@ -124,20 +124,24 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
124
124
|
const field = this.field;
|
|
125
125
|
this.drawn = field.points;
|
|
126
126
|
if (field.points.length === 0) {
|
|
127
|
-
return html `<div
|
|
127
|
+
return html `<div dir="ltr" part="plane">
|
|
128
|
+
<div id="helix-chart-plot" part="plot"></div>
|
|
129
|
+
</div>`;
|
|
128
130
|
}
|
|
129
131
|
const format = formatNumbers('');
|
|
130
132
|
const along = linear(field.x, [0, WIDTH]);
|
|
131
133
|
const up = linear(field.y, [HEIGHT, 0]);
|
|
132
|
-
return html
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
return html `<div dir="ltr" part="plane">
|
|
135
|
+
${this.renderPlot(field, along, up)}
|
|
136
|
+
<div aria-hidden="true" part="x-axis">
|
|
137
|
+
${ticks(field.x).map((level) => html `<span part="x-tick" style="--chart-tick: ${along(level)}%">${format(level)}</span>`)}
|
|
138
|
+
</div>
|
|
139
|
+
<div aria-hidden="true" part="y-axis">
|
|
140
|
+
${ticks(field.y).map((level) => html `<span part="y-tick" style="--chart-tick: ${up(level)}%">${format(level)}</span>`)}
|
|
141
|
+
</div>
|
|
142
|
+
<span aria-hidden="true" dir="auto" part="x-name">${field.xName}</span>
|
|
143
|
+
<span aria-hidden="true" dir="auto" part="y-name">${field.yNames.join(', ')}</span>
|
|
135
144
|
</div>
|
|
136
|
-
<div aria-hidden="true" part="y-axis">
|
|
137
|
-
${ticks(field.y).map((level) => html `<span part="y-tick" style="--chart-tick: ${up(level)}%">${format(level)}</span>`)}
|
|
138
|
-
</div>
|
|
139
|
-
<span aria-hidden="true" part="x-name">${field.xName}</span>
|
|
140
|
-
<span aria-hidden="true" part="y-name">${field.yNames.join(', ')}</span>
|
|
141
145
|
${this.renderSummary(field)}`;
|
|
142
146
|
}
|
|
143
147
|
renderPlot(field, along, up) {
|
|
@@ -184,6 +188,8 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
184
188
|
return drawTooltip(this.sourceRows, -1, this.tag('tooltip'));
|
|
185
189
|
}
|
|
186
190
|
return drawTooltip(this.sourceRows, at, this.tag('tooltip'), {
|
|
191
|
+
dir: getComputedStyle(this).direction === 'rtl' ? 'rtl' : 'ltr',
|
|
192
|
+
fixed: true,
|
|
187
193
|
placement: 'top',
|
|
188
194
|
x: `${point.x}%`,
|
|
189
195
|
y: `${point.y}%`,
|
|
@@ -27,10 +27,11 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
|
|
|
27
27
|
if (box.scrollTop + box.clientHeight < box.scrollHeight - slack) {
|
|
28
28
|
found.push('block-end');
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
const along = Math.abs(box.scrollLeft);
|
|
31
|
+
if (along > slack) {
|
|
31
32
|
found.push('inline-start');
|
|
32
33
|
}
|
|
33
|
-
if (
|
|
34
|
+
if (along + box.clientWidth < box.scrollWidth - slack) {
|
|
34
35
|
found.push('inline-end');
|
|
35
36
|
}
|
|
36
37
|
this.more = found;
|
|
@@ -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
|
|
@@ -79,9 +88,23 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
79
88
|
*
|
|
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
|
-
* which is `start` for text in either writing direction.
|
|
91
|
+
* which is `start` for text in either writing direction. `helix-data-table`
|
|
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.
|
|
98
|
+
*
|
|
99
|
+
* **Reflected, because the heading is drawn by a stylesheet and has no other
|
|
100
|
+
* way to learn it.** Set as a property, which is how React sets it, an
|
|
101
|
+
* unreflected `align` left no attribute to select on, so the heading stayed at
|
|
102
|
+
* the start over a column of digits set to the end. It is the author's
|
|
103
|
+
* declaration and nothing moves it afterwards, so an attribute cannot come to
|
|
104
|
+
* disagree with the element, which is the reason `open` records a custom
|
|
105
|
+
* state instead. No default, so an unset column writes nothing onto its host.
|
|
83
106
|
*/
|
|
84
|
-
align
|
|
107
|
+
align?: 'center' | 'end' | 'start';
|
|
85
108
|
/**
|
|
86
109
|
* How to read the cell, where the field alone will not do.
|
|
87
110
|
*
|
|
@@ -132,14 +155,24 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
132
155
|
* Ignored without a `field`, and silently: a column with nothing to sort by
|
|
133
156
|
* has no order to offer, and refusing loudly would mean an actions column
|
|
134
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.
|
|
135
165
|
*/
|
|
136
166
|
sortable: boolean;
|
|
137
167
|
/**
|
|
138
168
|
* The track this column takes, as CSS.
|
|
139
169
|
*
|
|
140
170
|
* A single track value, so anything valid in `grid-template-columns` works:
|
|
141
|
-
* `16rem`, `auto`, `minmax(0, 2fr)`. Left unset the column
|
|
142
|
-
*
|
|
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.
|
|
143
176
|
*
|
|
144
177
|
* **The floor is `max-content`, never `0` and never `min-content`.** A zero
|
|
145
178
|
* floor lets a track shrink under its own content: at 375 the columns squeeze
|
|
@@ -183,6 +216,8 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
183
216
|
private resizing;
|
|
184
217
|
/** Watches the heading's width, which changes with the table as well as with a drag. */
|
|
185
218
|
private watcher;
|
|
219
|
+
/** Watches `hidden`, which is the platform's attribute and no property of this element's. */
|
|
220
|
+
private hiding;
|
|
186
221
|
/**
|
|
187
222
|
* The narrowest a reader can drag a column, in pixels.
|
|
188
223
|
*
|
|
@@ -195,6 +230,13 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
195
230
|
static readonly STEP = 16;
|
|
196
231
|
/** The track this column contributes, resolved. */
|
|
197
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;
|
|
198
240
|
/** Whether a reader can actually reorder by this column. */
|
|
199
241
|
get canSort(): boolean;
|
|
200
242
|
/**
|
|
@@ -214,6 +256,9 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
214
256
|
private observeHeading;
|
|
215
257
|
disconnectedCallback(): void;
|
|
216
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;
|
|
217
262
|
/**
|
|
218
263
|
* Asks for a width, in pixels, no narrower than a column can be read at.
|
|
219
264
|
*
|
|
@@ -221,7 +266,7 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
|
|
|
221
266
|
* applied only where nobody refused it.
|
|
222
267
|
*/
|
|
223
268
|
private resizeTo;
|
|
224
|
-
/** Which way a drag
|
|
269
|
+
/** Which way a drag grows the column, in this writing direction. */
|
|
225
270
|
private get forward();
|
|
226
271
|
private readonly handleResizeStart;
|
|
227
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';
|
|
@@ -29,7 +29,6 @@ export const at = (row, path) => {
|
|
|
29
29
|
let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixElement {
|
|
30
30
|
constructor() {
|
|
31
31
|
super(...arguments);
|
|
32
|
-
this.align = '';
|
|
33
32
|
this.cell = undefined;
|
|
34
33
|
this.compare = undefined;
|
|
35
34
|
this.field = '';
|
|
@@ -63,7 +62,7 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
63
62
|
};
|
|
64
63
|
this.handleResizeKey = (event) => {
|
|
65
64
|
const step = HelixHeadlessTableColumn_1.STEP * (event.shiftKey ? 4 : 1);
|
|
66
|
-
const grow =
|
|
65
|
+
const grow = inlineStep(this, event.key);
|
|
67
66
|
if (grow !== 0) {
|
|
68
67
|
event.preventDefault();
|
|
69
68
|
this.resizeTo(this.drawn + grow * step);
|
|
@@ -80,6 +79,10 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
80
79
|
get track() {
|
|
81
80
|
return this.width || 'minmax(max-content, 1fr)';
|
|
82
81
|
}
|
|
82
|
+
get shown() {
|
|
83
|
+
const hidden = this.getAttribute('hidden');
|
|
84
|
+
return hidden === null || hidden === 'until-found';
|
|
85
|
+
}
|
|
83
86
|
get canSort() {
|
|
84
87
|
return this.sortable && this.field !== '';
|
|
85
88
|
}
|
|
@@ -109,6 +112,10 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
109
112
|
});
|
|
110
113
|
this.observeHeading();
|
|
111
114
|
}
|
|
115
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
116
|
+
this.hiding = new MutationObserver(() => this.tellHolder());
|
|
117
|
+
this.hiding.observe(this, { attributeFilter: ['hidden'] });
|
|
118
|
+
}
|
|
112
119
|
}
|
|
113
120
|
observeHeading() {
|
|
114
121
|
const heading = this.partNamed('column');
|
|
@@ -119,11 +126,23 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
119
126
|
disconnectedCallback() {
|
|
120
127
|
super.disconnectedCallback();
|
|
121
128
|
this.watcher?.disconnect();
|
|
129
|
+
this.hiding?.disconnect();
|
|
130
|
+
this.hiding = undefined;
|
|
122
131
|
}
|
|
123
132
|
firstUpdated(changed) {
|
|
124
133
|
super.firstUpdated?.(changed);
|
|
125
134
|
this.observeHeading();
|
|
126
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
|
+
}
|
|
127
146
|
resizeTo(px) {
|
|
128
147
|
const next = `${Math.max(HelixHeadlessTableColumn_1.NARROWEST, Math.round(px))}px`;
|
|
129
148
|
if (next === this.width) {
|
|
@@ -172,7 +191,7 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
|
|
|
172
191
|
}
|
|
173
192
|
};
|
|
174
193
|
__decorate([
|
|
175
|
-
property()
|
|
194
|
+
property({ reflect: true })
|
|
176
195
|
], HelixHeadlessTableColumn.prototype, "align", void 0);
|
|
177
196
|
__decorate([
|
|
178
197
|
property({ attribute: false })
|
|
@@ -187,7 +206,7 @@ __decorate([
|
|
|
187
206
|
property({ type: Boolean })
|
|
188
207
|
], HelixHeadlessTableColumn.prototype, "resizable", void 0);
|
|
189
208
|
__decorate([
|
|
190
|
-
property({ type: Boolean })
|
|
209
|
+
property({ reflect: true, type: Boolean })
|
|
191
210
|
], HelixHeadlessTableColumn.prototype, "sortable", void 0);
|
|
192
211
|
__decorate([
|
|
193
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;
|