@fusion.dev/helix-headless 0.40.0 → 0.41.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.
@@ -28,7 +28,7 @@ declare const HelixHeadlessBarChart_base: typeof HelixElement & (new (...args: a
28
28
  * computed and CSS cannot.
29
29
  *
30
30
  * @since 0.1.0
31
- * @status experimental
31
+ * @status stable
32
32
  * @category charts
33
33
  * @aliases Column Chart, Categorical Chart
34
34
  * @documentation https://fusion.dev/helix/components/bar-chart
@@ -65,7 +65,7 @@ declare const HelixHeadlessBarChart_base: typeof HelixElement & (new (...args: a
65
65
  * @csspart tooltip-top - The bubble while it is above the reading, beside `tooltip`.
66
66
  * @csspart tooltip-value - A column's value inside the tooltip.
67
67
  *
68
- * @cssproperty --bar-chart-axis - The color of a single-series axis, taken from that series.
68
+ * @cssproperty --bar-chart-axis - How wide an axis column is drawn, in `ch`, from the widest number on it. Written on the axis itself, and only where the categories run along the bottom: turned sideways an axis is a row and takes a line's height instead.
69
69
  * @cssproperty --bar-chart-secondary - The color of the secondary axis when one series owns it. It resolves a `--helix-color-series-*` token, so on the headless tier alone it names something that is not there. #138.
70
70
  * @cssproperty --chart-bar-wash - The gradient a bar would take, named per bar so the
71
71
  * styled tier can point `fill` at it. Drawn whatever the treatment and used only where
@@ -105,30 +105,40 @@ export declare class HelixHeadlessBarChart extends HelixHeadlessBarChart_base {
105
105
  /**
106
106
  * Which series are drawn as a line instead of as columns, by name.
107
107
  *
108
- * Space separated, matched against the column headings the table gives, so a
109
- * chart says `lines="Margin"` rather than counting columns. Names because
110
- * they are what the table already carries and what the legend already shows:
111
- * an index is a fourth place the column order is written down and the first
112
- * one to go stale when somebody moves a column.
108
+ * Separated by whitespace or commas and matched against the column headings
109
+ * the table gives, so a chart says `lines="Margin"` rather than counting
110
+ * columns. Names because they are what the table already carries and what the
111
+ * legend already shows: an index is a fourth place the column order is
112
+ * written down and the first one to go stale when somebody moves a column.
113
113
  *
114
- * **A combination chart is one scale, and that is the honest half of it.**
115
- * Both marks are measured against the same domain, so a line here says
116
- * something comparable to the columns beside it. The usual reason to reach
117
- * for a combination chart is the other thing, a count against a percentage on
118
- * a second axis, and that is deliberately not this: two scales on one frame
119
- * let the author put any two shapes in any relation by choosing the ranges,
120
- * and the reader has no way to see it happening.
114
+ * **This says which mark a series takes and nothing about which scale it is
115
+ * measured on.** Named here alone, a line shares the columns' domain, so it
116
+ * says something comparable to the columns beside it.
121
117
  *
122
- * A line among columns still measures from zero, because the columns do and
123
- * they share the axis.
118
+ * The other half of a combination chart, a count against a percentage on a
119
+ * scale of its own, is `secondary`, which is a separate property because it
120
+ * is a separate question and because the two compose: `with-a-second-axis`
121
+ * ships naming one series in both. The argument for why a second scale is opt
122
+ * in, and why setting it labels both axes, is written there.
123
+ *
124
+ * A line among columns measures from zero, because the columns do and they
125
+ * share the axis. So does a line on the second scale, which is that scale's
126
+ * own rule rather than this one's.
124
127
  */
125
128
  lines?: string;
126
129
  /**
127
130
  * Which series are measured against a scale of their own, by name.
128
131
  *
129
- * Space separated and matched the way `lines` is, against the column headings
130
- * the table gives. Opt in: absent, every series shares one domain, which is
131
- * what makes a chart comparable and is the right default.
132
+ * Separated and matched the way `lines` is, against the column headings the
133
+ * table gives. Opt in: absent, every series shares one domain, which is what
134
+ * makes a chart comparable and is the right default.
135
+ *
136
+ * **The scale, and `lines` is the mark.** The two are separate properties
137
+ * because they answer separate questions and a series usually wants both:
138
+ * a percentage beside a count is drawn as a line *and* measured on its own
139
+ * axis, which is what `with-a-second-axis` writes out. Neither implies the
140
+ * other, so a series can be a line on the shared scale and a column can have
141
+ * a scale to itself.
132
142
  *
133
143
  * **Two scales on one frame let an author put any two shapes in any relation
134
144
  * by choosing the ranges, and a reader cannot see it happening.** That is not
@@ -4,23 +4,17 @@ 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 { CHART_PLOT, customElement, drawTooltip, extent, HelixElement, linear, linePath, MixinChartSource, seriesIndex, ticks, } from '@fusion.dev/helix-core';
7
+ import { CHART_PLOT, customElement, drawTooltip, extent, HelixElement, linear, linePath, MixinChartSource, seriesIndex, seriesNames, ticks, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing, svg } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import '../../tooltip/index.js';
11
11
  const HEIGHT = 100;
12
12
  let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource(HelixElement) {
13
13
  get scaled() {
14
- return new Set((this.secondary ?? '')
15
- .split(/\s+/)
16
- .map((name) => name.trim().toLowerCase())
17
- .filter(Boolean));
14
+ return new Set(seriesNames(this.secondary));
18
15
  }
19
16
  get lined() {
20
- return new Set((this.lines ?? '')
21
- .split(/\s+/)
22
- .map((name) => name.trim().toLowerCase())
23
- .filter(Boolean));
17
+ return new Set(seriesNames(this.lines));
24
18
  }
25
19
  get rulesValue() {
26
20
  return this.gridlines !== undefined && this.gridlines !== 'category';
@@ -223,7 +217,7 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource
223
217
  placement: sideways ? (this.pointer.mirrored ? 'left' : 'right') : 'top',
224
218
  x: sideways ? `${far}%` : `${across}%`,
225
219
  y: sideways ? `${across}%` : `${far}%`,
226
- });
220
+ }, (cell) => this.seriesOf(cell));
227
221
  }
228
222
  };
229
223
  __decorate([
@@ -17,7 +17,7 @@ declare const HelixHeadlessDonutChart_base: typeof HelixElement & (new (...args:
17
17
  * dropped. Those rows are skipped and the total is of what is left.
18
18
  *
19
19
  * @since 0.1.0
20
- * @status experimental
20
+ * @status stable
21
21
  * @category charts
22
22
  * @aliases Pie Chart, Ring Chart, Share Chart
23
23
  * @documentation https://fusion.dev/helix/components/donut-chart
@@ -84,6 +84,14 @@ export declare class HelixHeadlessDonutChart extends HelixHeadlessDonutChart_bas
84
84
  * `getComputedStyle`, which is client-only: a server would draw a different
85
85
  * ring than the client. A plot's proportions are markup for the same reason
86
86
  * `curve` is.
87
+ *
88
+ * **And so it does not reflect**, which is the same argument read forward. No
89
+ * selector on either tier asks about it and none can want to: everything the
90
+ * thickness decides is arithmetic done here and published as
91
+ * `--donut-chart-stroke`, which is a number a rule can do sums with where the
92
+ * word is not. Reflected, it wrote a value onto every host a script had set
93
+ * it on for nothing to read. `sweep` beside it is the converse and reflects,
94
+ * because three rules select on it.
87
95
  */
88
96
  hole?: 'large' | 'none' | 'small';
89
97
  /**
@@ -165,11 +165,11 @@ let HelixHeadlessDonutChart = class HelixHeadlessDonutChart extends MixinChartSo
165
165
  : 'top',
166
166
  x: `${x}%`,
167
167
  y: `${y}%`,
168
- });
168
+ }, () => seriesIndex(at));
169
169
  }
170
170
  };
171
171
  __decorate([
172
- property({ reflect: true })
172
+ property()
173
173
  ], HelixHeadlessDonutChart.prototype, "hole", void 0);
174
174
  __decorate([
175
175
  property({ reflect: true })
@@ -11,7 +11,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
11
11
  * `entries` picks which way to read that table. `series` is one entry per data
12
12
  * column, named by the header row, which is a line or a bar chart.
13
13
  * `categories` is one entry per body row, which is a donut: its slices are the
14
- * rows and it has no axis to write their names along.
14
+ * rows and it has no axis to write their names along. `measures` drops the
15
+ * first data column, which is a scatter.
15
16
  *
16
17
  * **The table is resolved on the client and there is no server pass.**
17
18
  *
@@ -32,8 +33,21 @@ export declare class HelixHeadlessLegend extends HelixElement {
32
33
  *
33
34
  * Absent is `series`, one entry per data column. `categories` reads one entry
34
35
  * per body row instead, for a donut, whose slices are the rows.
36
+ *
37
+ * **`measures` is `series` without the first column, and it is for a
38
+ * scatter.** That chart reads its first numeric column as the measure
39
+ * *across*, so its first plotted series is the table's second and everything
40
+ * a legend beside it named was one color out: the across column wearing the
41
+ * color of the first series drawn, and each real series wearing the next
42
+ * one's. The across gets no entry rather than a shifted one, because it is an
43
+ * axis and a scatter already writes its name at the end of the scale under
44
+ * the plot.
45
+ *
46
+ * A legend cannot ask the chart which of these it is, `for` naming the table
47
+ * they share and not each other, so the consumer says it. That is the same
48
+ * shape `categories` already has.
35
49
  */
36
- entries?: 'categories' | 'series';
50
+ entries?: 'categories' | 'measures' | 'series';
37
51
  /**
38
52
  * The id of the table to take the names from.
39
53
  *
@@ -20,9 +20,10 @@ let HelixHeadlessLegend = class HelixHeadlessLegend extends HelixElement {
20
20
  }
21
21
  names() {
22
22
  const series = this.source.series;
23
- return this.entries === 'categories'
24
- ? (series[0]?.points.map((point) => point.label) ?? [])
25
- : series.map((one) => one.name);
23
+ if (this.entries === 'categories') {
24
+ return series[0]?.points.map((point) => point.label) ?? [];
25
+ }
26
+ return (this.entries === 'measures' ? series.slice(1) : series).map((one) => one.name);
26
27
  }
27
28
  render() {
28
29
  return html `<ul part="list" role="list">
@@ -36,7 +36,7 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
36
36
  * A reader who wants the numbers gets the numbers, not a described picture.
37
37
  *
38
38
  * @since 0.1.0
39
- * @status experimental
39
+ * @status stable
40
40
  * @category charts
41
41
  * @aliases Time Series, Trend Chart, Multi-line Chart
42
42
  * @documentation https://fusion.dev/helix/components/line-chart
@@ -68,6 +68,9 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
68
68
  * @csspart tooltip-right - The bubble while it is right of the reading, beside `tooltip`.
69
69
  * @csspart tooltip-top - The bubble while it is above the reading, beside `tooltip`.
70
70
  * @csspart tooltip-value - A column's value inside the tooltip.
71
+ *
72
+ * @cssproperty --chart-terminus-x - Where a series' last reading sits horizontally, as a percentage. Written by the component.
73
+ * @cssproperty --chart-terminus-y - Where a series' last reading sits vertically, as a percentage. Written by the component.
71
74
  */
72
75
  export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base {
73
76
  /**
@@ -141,9 +144,20 @@ export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base
141
144
  * the question a sparkline's single mark answers too.
142
145
  *
143
146
  * `none` lets the lines stop on their own, which suits a chart read for its
144
- * shape rather than for where it finished. The shapes come from
147
+ * shape rather than for where it finished. `square` is the same mark with its
148
+ * corners, for a drawing whose neighbors are square, the columns of a table
149
+ * beside it for instance. `ring` lets the ground through, for a chart drawn
150
+ * over something busy. `triangle` points along the axis and reads as "and
151
+ * onward" rather than as a second claim about the data.
152
+ *
153
+ * The shapes come from
145
154
  * `helix/styled/src/shared/chart/terminus.css`, the same sheet `Sparkline` takes, so
146
- * the set is identical wherever one appears.
155
+ * the set is identical wherever one appears. **Which is why every value is
156
+ * named here.** `Sparkline` shipped `square` implemented, drawn, asserted and
157
+ * undocumented until the cohort before this one; this family reads the same
158
+ * four out of the same sheet and had left two of them unwritten, so the
159
+ * finding arrived twice. A shared vocabulary wants naming at each door into
160
+ * it, because a reader arrives at one door and not at the set.
147
161
  *
148
162
  * `ring` is the one that asks something of the drawing. It leaves a hole and a
149
163
  * line ends at the reading, which is the hole's center, so the `<svg>` is
@@ -170,7 +170,7 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
170
170
  placement: 'top',
171
171
  x: `${at * slot + slot / 2}%`,
172
172
  y: `${tops.length > 0 ? Math.min(...tops) : 0}%`,
173
- });
173
+ }, (cell) => this.seriesOf(cell));
174
174
  }
175
175
  };
176
176
  __decorate([
@@ -58,7 +58,7 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
58
58
  * and the bubble is told the page's direction, both being words.
59
59
  *
60
60
  * @since 0.1.0
61
- * @status experimental
61
+ * @status stable
62
62
  * @category charts
63
63
  * @aliases Scatter Plot, XY Chart, Correlation Chart, Dot Plot
64
64
  * @documentation https://fusion.dev/helix/components/scatter-chart
@@ -121,6 +121,22 @@ export declare class HelixHeadlessScatterChart extends HelixHeadlessScatterChart
121
121
  private nearest;
122
122
  connectedCallback(): void;
123
123
  disconnectedCallback(): void;
124
+ /**
125
+ * The palette slot a cell of a row is drawn in, which here is shifted by one.
126
+ *
127
+ * **A scatter's first plotted series is the table's *second* numeric
128
+ * column**, the first having been split off as the measure across. So the
129
+ * mixin's answer, which is right for a chart whose columns are its series in
130
+ * order, is one too high on every column here and names a color for the
131
+ * across, which is drawn in none. Left at that, the bubble painted the across
132
+ * column in series one, the color the points themselves are drawn in, and
133
+ * gave the series actually plotted series two.
134
+ *
135
+ * The across gets no dot at all rather than a shifted one. It is an axis and
136
+ * not a series: it has a scale under the plot with its name at the end of it,
137
+ * which is where a reader is told what it is.
138
+ */
139
+ seriesOf(cell: number): number | undefined;
124
140
  /** Whether the levels across are ruled. */
125
141
  protected get rulesX(): boolean;
126
142
  /** Whether the levels up are ruled. */
@@ -89,6 +89,10 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
89
89
  this.removeEventListener('pointermove', this.handleMove);
90
90
  this.removeEventListener('pointerleave', this.handleLeave);
91
91
  }
92
+ seriesOf(cell) {
93
+ const depth = this.plottedColumns.indexOf(cell);
94
+ return depth < 1 ? undefined : seriesIndex(depth - 1);
95
+ }
92
96
  get rulesX() {
93
97
  return this.gridlines !== undefined && this.gridlines !== 'y';
94
98
  }
@@ -97,8 +101,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
97
101
  }
98
102
  get field() {
99
103
  const rows = this.sourceRows;
100
- const width = Math.max(0, ...rows.map((row) => row.cells.length));
101
- const columns = Array.from({ length: width }, (_, column) => column).filter((column) => rows.some((row) => row.cells[column]?.value !== undefined));
104
+ const columns = this.plottedColumns;
102
105
  const [across, ...ups] = columns;
103
106
  const name = (column) => column === undefined ? '' : (rows.find((row) => row.cells[column])?.cells[column]?.name ?? '');
104
107
  const pairs = ups.map((column) => rows.flatMap((row, index) => {
@@ -193,7 +196,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
193
196
  placement: 'top',
194
197
  x: `${point.x}%`,
195
198
  y: `${point.y}%`,
196
- });
199
+ }, (cell) => this.seriesOf(cell));
197
200
  }
198
201
  };
199
202
  __decorate([
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix-headless",
3
3
  "description": "Headless component tier. Structure, accessibility, state, and form participation. No styling.",
4
- "version": "0.40.0",
4
+ "version": "0.41.1",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -46,14 +46,14 @@
46
46
  },
47
47
  "bugs": "https://github.com/project-fusion/fusion/issues",
48
48
  "dependencies": {
49
- "@fusion.dev/helix-core": "0.40.0",
50
- "@fusion.dev/helix-icons": "0.40.0",
49
+ "@fusion.dev/helix-core": "0.41.1",
50
+ "@fusion.dev/helix-icons": "0.41.1",
51
51
  "uqr": "^0.1.3"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@custom-elements-manifest/analyzer": "^0.11.0",
55
- "@fusion.dev/helix-cem": "0.40.0",
56
- "@fusion.dev/helix-testing": "0.40.0",
55
+ "@fusion.dev/helix-cem": "0.41.1",
56
+ "@fusion.dev/helix-testing": "0.41.1",
57
57
  "@fusion.dev/scripts": "0.0.0-dev",
58
58
  "@happy-dom/global-registrator": "^20.0.0",
59
59
  "@lit-labs/ssr": "^4.1.0",