@fusion.dev/helix-headless 0.180.1 → 0.181.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 +194 -5
- package/dist/bar-chart/root/bar-chart-root.d.ts +2 -1
- package/dist/bar-chart/root/bar-chart-root.js +10 -6
- package/dist/bar-chart/stack.d.ts +9 -0
- package/dist/bar-chart/stack.js +5 -0
- package/dist/heatmap/rectangle.d.ts +24 -0
- package/dist/heatmap/rectangle.js +18 -0
- package/dist/heatmap/root/heatmap-root.d.ts +38 -1
- package/dist/heatmap/root/heatmap-root.js +39 -1
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +48 -2
- package/types/vue.d.ts +9 -1
package/custom-elements.json
CHANGED
|
@@ -6973,9 +6973,13 @@
|
|
|
6973
6973
|
"name": "band"
|
|
6974
6974
|
},
|
|
6975
6975
|
{
|
|
6976
|
-
"description": "One column.",
|
|
6976
|
+
"description": "One column. Under `stacked`, one segment of a category's column.",
|
|
6977
6977
|
"name": "bar"
|
|
6978
6978
|
},
|
|
6979
|
+
{
|
|
6980
|
+
"description": "Under `stacked`, the segment at a column's far end: the last positive segment above zero and the last negative one below it. Its `data-end` is `positive` or `negative`. A blank or a zero segment is never the end. Set together with `bar`.",
|
|
6981
|
+
"name": "bar-end"
|
|
6982
|
+
},
|
|
6979
6983
|
{
|
|
6980
6984
|
"description": "The far stop of a bar's gradient, where one is used.",
|
|
6981
6985
|
"name": "bar-wash-end"
|
|
@@ -7364,7 +7368,7 @@
|
|
|
7364
7368
|
{
|
|
7365
7369
|
"name": "bar",
|
|
7366
7370
|
"type": {
|
|
7367
|
-
"text": "(\n value: number,\n index: number,\n depth: number,\n tone: number,\n scale: (value: number) => number,\n from?: number,\n ) => TemplateResult"
|
|
7371
|
+
"text": "(\n value: number,\n index: number,\n depth: number,\n tone: number,\n scale: (value: number) => number,\n from?: number,\n end?: StackEnd,\n ) => TemplateResult"
|
|
7368
7372
|
}
|
|
7369
7373
|
}
|
|
7370
7374
|
],
|
|
@@ -8510,6 +8514,24 @@
|
|
|
8510
8514
|
],
|
|
8511
8515
|
"description": "Each column's span in one category, in the order given: a positive reading\nstacks up from zero on the positives before it, and a negative one down\nfrom zero on the negatives before it, so neither hides the other. A blank\nhas no span."
|
|
8512
8516
|
},
|
|
8517
|
+
{
|
|
8518
|
+
"kind": "function",
|
|
8519
|
+
"name": "stackFarEnds",
|
|
8520
|
+
"return": {
|
|
8521
|
+
"type": {
|
|
8522
|
+
"text": "(StackEnd | undefined)[]"
|
|
8523
|
+
}
|
|
8524
|
+
},
|
|
8525
|
+
"parameters": [
|
|
8526
|
+
{
|
|
8527
|
+
"name": "values",
|
|
8528
|
+
"type": {
|
|
8529
|
+
"text": "readonly (number | undefined)[]"
|
|
8530
|
+
}
|
|
8531
|
+
}
|
|
8532
|
+
],
|
|
8533
|
+
"description": "The segments at a stack's two far ends, in the order given: the last\npositive reading is the end of the stack above zero, and the last negative\nreading is the end of the stack below it. A blank or a zero has no length,\nso it is never an end. Every other segment is `undefined`."
|
|
8534
|
+
},
|
|
8513
8535
|
{
|
|
8514
8536
|
"kind": "function",
|
|
8515
8537
|
"name": "stackEnds",
|
|
@@ -8568,6 +8590,14 @@
|
|
|
8568
8590
|
"module": "src/bar-chart/stack.ts"
|
|
8569
8591
|
}
|
|
8570
8592
|
},
|
|
8593
|
+
{
|
|
8594
|
+
"kind": "js",
|
|
8595
|
+
"name": "stackFarEnds",
|
|
8596
|
+
"declaration": {
|
|
8597
|
+
"name": "stackFarEnds",
|
|
8598
|
+
"module": "src/bar-chart/stack.ts"
|
|
8599
|
+
}
|
|
8600
|
+
},
|
|
8571
8601
|
{
|
|
8572
8602
|
"kind": "js",
|
|
8573
8603
|
"name": "stackEnds",
|
|
@@ -79063,6 +79093,90 @@
|
|
|
79063
79093
|
}
|
|
79064
79094
|
]
|
|
79065
79095
|
},
|
|
79096
|
+
{
|
|
79097
|
+
"kind": "javascript-module",
|
|
79098
|
+
"path": "src/heatmap/rectangle.ts",
|
|
79099
|
+
"declarations": [
|
|
79100
|
+
{
|
|
79101
|
+
"kind": "function",
|
|
79102
|
+
"name": "rectangleOf",
|
|
79103
|
+
"return": {
|
|
79104
|
+
"type": {
|
|
79105
|
+
"text": "number[]"
|
|
79106
|
+
}
|
|
79107
|
+
},
|
|
79108
|
+
"parameters": [
|
|
79109
|
+
{
|
|
79110
|
+
"name": "count",
|
|
79111
|
+
"type": {
|
|
79112
|
+
"text": "number"
|
|
79113
|
+
}
|
|
79114
|
+
},
|
|
79115
|
+
{
|
|
79116
|
+
"name": "rows",
|
|
79117
|
+
"type": {
|
|
79118
|
+
"text": "number"
|
|
79119
|
+
}
|
|
79120
|
+
},
|
|
79121
|
+
{
|
|
79122
|
+
"name": "from",
|
|
79123
|
+
"type": {
|
|
79124
|
+
"text": "number"
|
|
79125
|
+
}
|
|
79126
|
+
},
|
|
79127
|
+
{
|
|
79128
|
+
"name": "to",
|
|
79129
|
+
"type": {
|
|
79130
|
+
"text": "number"
|
|
79131
|
+
}
|
|
79132
|
+
}
|
|
79133
|
+
],
|
|
79134
|
+
"description": "The cells between `from` and `to` by row and by column, in the order the\ncells are drawn: every cell whose column lies between theirs and whose row\nlies between theirs. A place past the end of a short last column holds no\ncell and is skipped. With one row, it is the run of cells from one to the\nother."
|
|
79135
|
+
},
|
|
79136
|
+
{
|
|
79137
|
+
"kind": "function",
|
|
79138
|
+
"name": "inSequence",
|
|
79139
|
+
"return": {
|
|
79140
|
+
"type": {
|
|
79141
|
+
"text": "string[]"
|
|
79142
|
+
}
|
|
79143
|
+
},
|
|
79144
|
+
"parameters": [
|
|
79145
|
+
{
|
|
79146
|
+
"name": "picked",
|
|
79147
|
+
"type": {
|
|
79148
|
+
"text": "readonly string[]"
|
|
79149
|
+
}
|
|
79150
|
+
},
|
|
79151
|
+
{
|
|
79152
|
+
"name": "order",
|
|
79153
|
+
"type": {
|
|
79154
|
+
"text": "readonly string[]"
|
|
79155
|
+
}
|
|
79156
|
+
}
|
|
79157
|
+
],
|
|
79158
|
+
"description": "`picked` without repeats, in the order `order` gives: the selected cells in\nthe order the table lists them. A value `order` does not hold keeps its\nplace after the rest, so a selected day the strip no longer draws stays\nselected."
|
|
79159
|
+
}
|
|
79160
|
+
],
|
|
79161
|
+
"exports": [
|
|
79162
|
+
{
|
|
79163
|
+
"kind": "js",
|
|
79164
|
+
"name": "rectangleOf",
|
|
79165
|
+
"declaration": {
|
|
79166
|
+
"name": "rectangleOf",
|
|
79167
|
+
"module": "src/heatmap/rectangle.ts"
|
|
79168
|
+
}
|
|
79169
|
+
},
|
|
79170
|
+
{
|
|
79171
|
+
"kind": "js",
|
|
79172
|
+
"name": "inSequence",
|
|
79173
|
+
"declaration": {
|
|
79174
|
+
"name": "inSequence",
|
|
79175
|
+
"module": "src/heatmap/rectangle.ts"
|
|
79176
|
+
}
|
|
79177
|
+
}
|
|
79178
|
+
]
|
|
79179
|
+
},
|
|
79066
79180
|
{
|
|
79067
79181
|
"kind": "javascript-module",
|
|
79068
79182
|
"path": "src/heatmap/root/buckets.ts",
|
|
@@ -79227,7 +79341,7 @@
|
|
|
79227
79341
|
"declarations": [
|
|
79228
79342
|
{
|
|
79229
79343
|
"kind": "class",
|
|
79230
|
-
"description": "A grid of cells, each colored by a tone. `rows=\"1\"` makes a status strip, and\n`rows=\"7\"` makes a contribution graph. GitHub's contribution graph uses five\ndiscrete levels, which a set of tones covers.\n\nColor in a heatmap is per cell. In every other Helix chart, color is per\nseries, so ninety differently colored cells would need ninety series.\n\n**The data is a real `<table>` named by `for`**, as in every Helix chart, and\nthe table is the accessible representation. Hide it with\n`data-hidden-visually`, and screen readers still read it.\n\nA cell takes its tone from its own `data-tone`, or from `thresholds` and\n`tones` applied to its value. `data-tone` wins, so when you already know a\nday was degraded, you can set the tone directly.\n\n**The headless tier does not resolve tone names.** A tone named `success`\nwrites `--heatmap-tone: var(--heatmap-tone-success)`, and the styled tier or\nyour own stylesheet defines that property. The headless tier does not use\n`var(--helix-color-*)`.\n\n**The strip is read by key.** It takes focus once it has cells. The up and\ndown arrows move a cell, the left and right arrows move a column, which is a\nweek with `rows=\"7\"`, and Home and End go to the first and the last. The\ntooltip follows, the `live` part says the cell's row in words, and Escape\nputs the tooltip away. PageUp and PageDown move a month, to the same day,\nwhere each row's header carries its date as a `<time datetime>`, and four\ncolumns otherwise, which is four weeks with `rows=\"7\"`.\n\n**The strip describes itself.** The `overview` part says the busiest\nreading and the total of the readings drawn, \"Busiest: 11 Jun, 12; Total\n84\", and the strip is described by it, as every chart is by its summary.\nHide it visually. The `summary` slot is still yours, for words of your own.\n\n**`selection-mode` lets a reader select cells**: `single` one at a time and\n`multiple` any number. Space, Enter or a press selects the cell the keys or\nthe pointer rest on, or lets it go, and under `multiple` Shift with an arrow,\nHome, End, PageUp or PageDown takes in every cell from the last one pressed\nto where the key went. `value` holds the selected days, separated by\ncommas: each by its row's `<time datetime>`, such as `2026-06-11`, or by\nits row's name where the row carries no date. A change asks with\n`helix-before-change` and tells with `change`, and the `selection` part says\nhow many are selected, in `selection-label`.\n\n**Under `selection-mode` the strip is a grid**, so the selection is state a\nreader is told rather than words alone: each column of the strip is a `row`,\na week with `rows=\"7\"`, and each cell a `gridcell` named by its row in the\ntable and carrying `aria-selected`. The strip says\n`aria-multiselectable` under `multiple` and points at the cell the keys rest\non with `aria-activedescendant`, so a screen reader reads that cell, and the\n`live` part stays quiet. Without `selection-mode` nothing is selectable, and\nthe strip is an application with the readout, as every chart's plot is.\n\n**Readings are sent as every chart sends them.** `helix-reading-change`\nsays each move of the reading, by pointer, tap or key, and\n`helix-reading-press` a reading clicked, tapped, or pressed with Enter or\nSpace, each with the row of the table in `index`.\n\n**Nothing to draw.** A table with no readings shows `empty-text`, \"No\nreadings\", under the strip, and `loading` shows `loading-text` there until\nreadings arrive. The `empty` and `loading` slots take markup in place of\neither, as on every chart.\n\n**Keyboard.** The strip is one tab stop once it has cells.\n\n| Key | What it does |\n|---|---|\n| Tab | Moves focus to the strip and shows the first cell. |\n| Down, Up | Moves to the next or the previous cell. |\n| Right, Left | Moves a column on or back, a week with `rows=\"7\"`. On a right-to-left page, Left moves on. |\n| Home, End | Moves to the first or the last cell. |\n| Page Down, Page Up | Moves a month on or back where the rows carry dates, and four columns otherwise. |\n| Enter, Space | Presses the cell, which sends `helix-reading-press`, and selects it or lets it go under `selection-mode`. |\n| Shift with an arrow, Home, End, Page Up or Page Down | Selects every cell from the last one pressed to where the key went, under `selection-mode=\"multiple\"`. |\n| Escape | Puts the cell's tooltip away. |",
|
|
79344
|
+
"description": "A grid of cells, each colored by a tone. `rows=\"1\"` makes a status strip, and\n`rows=\"7\"` makes a contribution graph. GitHub's contribution graph uses five\ndiscrete levels, which a set of tones covers.\n\nColor in a heatmap is per cell. In every other Helix chart, color is per\nseries, so ninety differently colored cells would need ninety series.\n\n**The data is a real `<table>` named by `for`**, as in every Helix chart, and\nthe table is the accessible representation. Hide it with\n`data-hidden-visually`, and screen readers still read it.\n\nA cell takes its tone from its own `data-tone`, or from `thresholds` and\n`tones` applied to its value. `data-tone` wins, so when you already know a\nday was degraded, you can set the tone directly.\n\n**The headless tier does not resolve tone names.** A tone named `success`\nwrites `--heatmap-tone: var(--heatmap-tone-success)`, and the styled tier or\nyour own stylesheet defines that property. The headless tier does not use\n`var(--helix-color-*)`.\n\n**The strip is read by key.** It takes focus once it has cells. The up and\ndown arrows move a cell, the left and right arrows move a column, which is a\nweek with `rows=\"7\"`, and Home and End go to the first and the last. The\ntooltip follows, the `live` part says the cell's row in words, and Escape\nputs the tooltip away. PageUp and PageDown move a month, to the same day,\nwhere each row's header carries its date as a `<time datetime>`, and four\ncolumns otherwise, which is four weeks with `rows=\"7\"`.\n\n**The strip describes itself.** The `overview` part says the busiest\nreading and the total of the readings drawn, \"Busiest: 11 Jun, 12; Total\n84\", and the strip is described by it, as every chart is by its summary.\nHide it visually. The `summary` slot is still yours, for words of your own.\n\n**`selection-mode` lets a reader select cells**: `single` one at a time and\n`multiple` any number. Space, Enter or a press selects the cell the keys or\nthe pointer rest on, or lets it go, and under `multiple` Shift with an arrow,\nHome, End, PageUp or PageDown takes in every cell from the last one pressed\nto where the key went. `value` holds the selected days, separated by\ncommas: each by its row's `<time datetime>`, such as `2026-06-11`, or by\nits row's name where the row carries no date. A change asks with\n`helix-before-change` and tells with `change`, and the `selection` part says\nhow many are selected, in `selection-label`.\n\n**`selection-shape=\"rectangle\"` selects a rectangle of cells** under\n`multiple`, as a spreadsheet selects a range: the cells between two corners\nby row and by column, such as the same weekdays across three weeks with\n`rows=\"7\"`. Shift with a key that moves grows or shrinks it from the cell\nlast pressed, Shift with a click takes it to the cell clicked, and a click\nwith Ctrl or Command selects one cell or lets it go and starts the next\nrectangle there. The rectangle is the same cells on a right-to-left page,\nwhere the columns run from the right, a short last column adds only the\ncells it has, and `value` lists the selected days in the table's order.\n\n**Under `selection-mode` the strip is a grid**, so the selection is state a\nreader is told rather than words alone: each column of the strip is a `row`,\na week with `rows=\"7\"`, and each cell a `gridcell` named by its row in the\ntable and carrying `aria-selected`. The strip says\n`aria-multiselectable` under `multiple` and points at the cell the keys rest\non with `aria-activedescendant`, so a screen reader reads that cell, and the\n`live` part stays quiet. Without `selection-mode` nothing is selectable, and\nthe strip is an application with the readout, as every chart's plot is.\n\n**Readings are sent as every chart sends them.** `helix-reading-change`\nsays each move of the reading, by pointer, tap or key, and\n`helix-reading-press` a reading clicked, tapped, or pressed with Enter or\nSpace, each with the row of the table in `index`.\n\n**Nothing to draw.** A table with no readings shows `empty-text`, \"No\nreadings\", under the strip, and `loading` shows `loading-text` there until\nreadings arrive. The `empty` and `loading` slots take markup in place of\neither, as on every chart.\n\n**Keyboard.** The strip is one tab stop once it has cells.\n\n| Key | What it does |\n|---|---|\n| Tab | Moves focus to the strip and shows the first cell. |\n| Down, Up | Moves to the next or the previous cell. |\n| Right, Left | Moves a column on or back, a week with `rows=\"7\"`. On a right-to-left page, Left moves on. |\n| Home, End | Moves to the first or the last cell. |\n| Page Down, Page Up | Moves a month on or back where the rows carry dates, and four columns otherwise. |\n| Enter, Space | Presses the cell, which sends `helix-reading-press`, and selects it or lets it go under `selection-mode`. |\n| Shift with an arrow, Home, End, Page Up or Page Down | Selects every cell from the last one pressed to where the key went, under `selection-mode=\"multiple\"`. |\n| Shift with an arrow, Home, End, Page Up or Page Down, with `selection-shape=\"rectangle\"` | Grows or shrinks the rectangle from the last cell pressed to where the key went, in rows and columns, under `selection-mode=\"multiple\"`. |\n| Escape | Puts the cell's tooltip away. |",
|
|
79231
79345
|
"name": "HelixHeadlessHeatmap",
|
|
79232
79346
|
"cssProperties": [
|
|
79233
79347
|
{
|
|
@@ -79549,6 +79663,16 @@
|
|
|
79549
79663
|
"description": "How many cells a reader can select: `single` or `multiple`.\n\nAbsent selects nothing, and a press or Space does what it did.",
|
|
79550
79664
|
"attribute": "selection-mode"
|
|
79551
79665
|
},
|
|
79666
|
+
{
|
|
79667
|
+
"kind": "field",
|
|
79668
|
+
"name": "selectionShape",
|
|
79669
|
+
"type": {
|
|
79670
|
+
"text": "'linear' | 'rectangle'"
|
|
79671
|
+
},
|
|
79672
|
+
"default": "'linear'",
|
|
79673
|
+
"description": "What Shift takes in under `selection-mode=\"multiple\"`: `linear`, every\ncell between two in the table's order, or `rectangle`, the cells between\ntwo corners by row and by column, as a spreadsheet selects a range.",
|
|
79674
|
+
"attribute": "selection-shape"
|
|
79675
|
+
},
|
|
79552
79676
|
{
|
|
79553
79677
|
"kind": "field",
|
|
79554
79678
|
"name": "stripLabel",
|
|
@@ -79670,6 +79794,36 @@
|
|
|
79670
79794
|
"default": "-1",
|
|
79671
79795
|
"description": "Where a range taken in with Shift starts: the cell last pressed, or none."
|
|
79672
79796
|
},
|
|
79797
|
+
{
|
|
79798
|
+
"kind": "field",
|
|
79799
|
+
"name": "left",
|
|
79800
|
+
"type": {
|
|
79801
|
+
"text": "number"
|
|
79802
|
+
},
|
|
79803
|
+
"privacy": "private",
|
|
79804
|
+
"default": "-1",
|
|
79805
|
+
"description": "The cell the keys rested on before the key now being handled moved them."
|
|
79806
|
+
},
|
|
79807
|
+
{
|
|
79808
|
+
"kind": "field",
|
|
79809
|
+
"name": "base",
|
|
79810
|
+
"type": {
|
|
79811
|
+
"text": "string[] | undefined"
|
|
79812
|
+
},
|
|
79813
|
+
"privacy": "private",
|
|
79814
|
+
"default": "undefined",
|
|
79815
|
+
"description": "What a rectangle is added to: the selection when it was started, less its\nanchor, kept while `value` is still the rectangle last written."
|
|
79816
|
+
},
|
|
79817
|
+
{
|
|
79818
|
+
"kind": "field",
|
|
79819
|
+
"name": "shaped",
|
|
79820
|
+
"type": {
|
|
79821
|
+
"text": "string | undefined"
|
|
79822
|
+
},
|
|
79823
|
+
"privacy": "private",
|
|
79824
|
+
"default": "undefined",
|
|
79825
|
+
"description": "The `value` the last rectangle wrote."
|
|
79826
|
+
},
|
|
79673
79827
|
{
|
|
79674
79828
|
"kind": "field",
|
|
79675
79829
|
"name": "status",
|
|
@@ -79735,6 +79889,32 @@
|
|
|
79735
79889
|
],
|
|
79736
79890
|
"description": "Selects the drawn cell at `index`, or lets it go, as `selection-mode` says."
|
|
79737
79891
|
},
|
|
79892
|
+
{
|
|
79893
|
+
"kind": "method",
|
|
79894
|
+
"name": "stretch",
|
|
79895
|
+
"privacy": "private",
|
|
79896
|
+
"return": {
|
|
79897
|
+
"type": {
|
|
79898
|
+
"text": "void"
|
|
79899
|
+
}
|
|
79900
|
+
},
|
|
79901
|
+
"parameters": [
|
|
79902
|
+
{
|
|
79903
|
+
"name": "to",
|
|
79904
|
+
"type": {
|
|
79905
|
+
"text": "number"
|
|
79906
|
+
}
|
|
79907
|
+
}
|
|
79908
|
+
],
|
|
79909
|
+
"description": "Selects the rectangle from the anchor to the drawn cell at `to`, beside\nwhat was selected before it started, under `selection-shape=\"rectangle\"`.\nWithout an anchor it starts where the keys were."
|
|
79910
|
+
},
|
|
79911
|
+
{
|
|
79912
|
+
"kind": "field",
|
|
79913
|
+
"name": "onStripKeydown",
|
|
79914
|
+
"privacy": "private",
|
|
79915
|
+
"readonly": true,
|
|
79916
|
+
"description": "Notes where the keys rest before the pointer controller moves them."
|
|
79917
|
+
},
|
|
79738
79918
|
{
|
|
79739
79919
|
"kind": "field",
|
|
79740
79920
|
"name": "onKeydown",
|
|
@@ -79747,7 +79927,7 @@
|
|
|
79747
79927
|
"name": "onClick",
|
|
79748
79928
|
"privacy": "private",
|
|
79749
79929
|
"readonly": true,
|
|
79750
|
-
"description": "A press on a cell selects it, under `selection-mode`."
|
|
79930
|
+
"description": "A press on a cell selects it, under `selection-mode`, and Shift takes the\nrectangle to it under `selection-shape=\"rectangle\"`."
|
|
79751
79931
|
},
|
|
79752
79932
|
{
|
|
79753
79933
|
"kind": "field",
|
|
@@ -80753,6 +80933,15 @@
|
|
|
80753
80933
|
"description": "How many cells a reader can select: `single` or `multiple`.\n\nAbsent selects nothing, and a press or Space does what it did.",
|
|
80754
80934
|
"fieldName": "selectionMode"
|
|
80755
80935
|
},
|
|
80936
|
+
{
|
|
80937
|
+
"name": "selection-shape",
|
|
80938
|
+
"type": {
|
|
80939
|
+
"text": "'linear' | 'rectangle'"
|
|
80940
|
+
},
|
|
80941
|
+
"default": "'linear'",
|
|
80942
|
+
"description": "What Shift takes in under `selection-mode=\"multiple\"`: `linear`, every\ncell between two in the table's order, or `rectangle`, the cells between\ntwo corners by row and by column, as a spreadsheet selects a range.",
|
|
80943
|
+
"fieldName": "selectionShape"
|
|
80944
|
+
},
|
|
80756
80945
|
{
|
|
80757
80946
|
"name": "strip-label",
|
|
80758
80947
|
"type": {
|
|
@@ -199886,6 +200075,6 @@
|
|
|
199886
200075
|
],
|
|
199887
200076
|
"helix": {
|
|
199888
200077
|
"package": "@fusion.dev/helix-headless",
|
|
199889
|
-
"version": "0.
|
|
200078
|
+
"version": "0.181.1"
|
|
199890
200079
|
}
|
|
199891
200080
|
}
|
|
@@ -72,7 +72,8 @@ declare const HelixHeadlessBarChart_base: typeof HelixElement & (new (...args: a
|
|
|
72
72
|
*
|
|
73
73
|
* @csspart axis - The numbers of one scale: the primary under `value-axis`, and both when `secondary` splits the chart into two scales.
|
|
74
74
|
* @csspart band - The category band under the pointer.
|
|
75
|
-
* @csspart bar - One column.
|
|
75
|
+
* @csspart bar - One column. Under `stacked`, one segment of a category's column.
|
|
76
|
+
* @csspart bar-end - Under `stacked`, the segment at a column's far end: the last positive segment above zero and the last negative one below it. Its `data-end` is `positive` or `negative`. A blank or a zero segment is never the end. Set together with `bar`.
|
|
76
77
|
* @csspart bar-wash-end - The far stop of a bar's gradient, where one is used.
|
|
77
78
|
* @csspart bar-wash-start - The stop of a bar's gradient at its base.
|
|
78
79
|
* @csspart baseline - The line the columns stand on.
|
|
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { byRow, CHART_PLOT, customElement, drawTooltip, extent, formatNumbers, formatWords, HelixElement, HelixReadingChangeEvent, HelixReadingPressEvent, linear, linePath, MixinChartSource, MixinChartStatus, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, seriesKey, seriesNames, ticks, unbroken, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing, svg } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
-
import { stackEnds, stackedReadings, stackSpans } from '../stack.js';
|
|
10
|
+
import { stackEnds, stackedReadings, stackFarEnds, stackSpans } from '../stack.js';
|
|
11
11
|
import '../../tooltip/index.js';
|
|
12
12
|
let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartStatus(MixinChartSource(HelixElement)) {
|
|
13
13
|
constructor() {
|
|
@@ -112,7 +112,7 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartStatus
|
|
|
112
112
|
const stride = (slot * 0.72) / Math.max(abreast, 1);
|
|
113
113
|
const gap = abreast > 1 ? stride * 0.08 : 0;
|
|
114
114
|
const thickness = stride - gap;
|
|
115
|
-
const bar = (value, index, depth, tone, scale, from) => {
|
|
115
|
+
const bar = (value, index, depth, tone, scale, from, end) => {
|
|
116
116
|
const at = scale(value);
|
|
117
117
|
const base = from === undefined ? floor : scale(from);
|
|
118
118
|
const along = Math.min(base, at);
|
|
@@ -120,19 +120,21 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartStatus
|
|
|
120
120
|
const across = index * slot + slot * 0.14 + depth * stride + gap / 2;
|
|
121
121
|
return sideways
|
|
122
122
|
? svg `<rect
|
|
123
|
+
data-end=${end ?? nothing}
|
|
123
124
|
data-series=${seriesIndex(tone)}
|
|
124
125
|
height=${thickness}
|
|
125
126
|
style="--chart-series: var(--chart-series-${seriesIndex(tone)}); --chart-bar-wash: url(#helix-bar-wash-${seriesIndex(tone)})"
|
|
126
|
-
part="bar"
|
|
127
|
+
part="bar${end ? ' bar-end' : ''}"
|
|
127
128
|
width=${size}
|
|
128
129
|
x=${along}
|
|
129
130
|
y=${across}
|
|
130
131
|
/>`
|
|
131
132
|
: svg `<rect
|
|
133
|
+
data-end=${end ?? nothing}
|
|
132
134
|
data-series=${seriesIndex(tone)}
|
|
133
135
|
height=${size}
|
|
134
136
|
style="--chart-series: var(--chart-series-${seriesIndex(tone)}); --chart-bar-wash: url(#helix-bar-wash-${seriesIndex(tone)})"
|
|
135
|
-
part="bar"
|
|
137
|
+
part="bar${end ? ' bar-end' : ''}"
|
|
136
138
|
width=${thickness}
|
|
137
139
|
x=${across}
|
|
138
140
|
y=${along}
|
|
@@ -196,10 +198,12 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartStatus
|
|
|
196
198
|
const scales = [...new Set(columns.map(({ one }) => against(one)))];
|
|
197
199
|
return scales.flatMap((scale) => {
|
|
198
200
|
const mine = columns.filter(({ one }) => against(one) === scale);
|
|
199
|
-
const
|
|
201
|
+
const values = mine.map(({ slots }) => slots[index]?.value);
|
|
202
|
+
const spans = stackSpans(values);
|
|
203
|
+
const ends = stackFarEnds(values);
|
|
200
204
|
return mine.flatMap(({ tone }, place) => {
|
|
201
205
|
const span = spans[place];
|
|
202
|
-
return span === undefined ? [] : [bar(span[1], index, 0, tone, scale, span[0])];
|
|
206
|
+
return span === undefined ? [] : [bar(span[1], index, 0, tone, scale, span[0], ends[place])];
|
|
203
207
|
});
|
|
204
208
|
});
|
|
205
209
|
}
|
|
@@ -8,6 +8,15 @@ export type Span = readonly [from: number, to: number];
|
|
|
8
8
|
* has no span.
|
|
9
9
|
*/
|
|
10
10
|
export declare const stackSpans: (values: readonly (number | undefined)[]) => (Span | undefined)[];
|
|
11
|
+
/** Which way a stack's end segment grows from zero. */
|
|
12
|
+
export type StackEnd = 'positive' | 'negative';
|
|
13
|
+
/**
|
|
14
|
+
* The segments at a stack's two far ends, in the order given: the last
|
|
15
|
+
* positive reading is the end of the stack above zero, and the last negative
|
|
16
|
+
* reading is the end of the stack below it. A blank or a zero has no length,
|
|
17
|
+
* so it is never an end. Every other segment is `undefined`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const stackFarEnds: (values: readonly (number | undefined)[]) => (StackEnd | undefined)[];
|
|
11
20
|
/**
|
|
12
21
|
* Every end a stack reaches across the categories, which is what its scale
|
|
13
22
|
* has to hold: the top of each stack of positives and the foot of each stack
|
package/dist/bar-chart/stack.js
CHANGED
|
@@ -17,6 +17,11 @@ export const stackSpans = (values) => {
|
|
|
17
17
|
return [from, to];
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
export const stackFarEnds = (values) => {
|
|
21
|
+
const up = values.findLastIndex((value) => value !== undefined && value > 0);
|
|
22
|
+
const down = values.findLastIndex((value) => value !== undefined && value < 0);
|
|
23
|
+
return values.map((_, at) => (at === up ? 'positive' : at === down ? 'negative' : undefined));
|
|
24
|
+
};
|
|
20
25
|
export const stackEnds = (categories) => categories.flatMap((values) => stackSpans(values).flatMap((span) => (span === undefined ? [] : [span[1]])));
|
|
21
26
|
export const stackedReadings = (group, count, lined) => {
|
|
22
27
|
const slots = group.filter((one) => !lined(one)).map((one) => byRow(one, count));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arithmetic of a rectangle of cells on a heatmap's strip.
|
|
3
|
+
*
|
|
4
|
+
* Pure and beside the family's entry, so a spec holds it without a page. The
|
|
5
|
+
* strip fills `rows` cells down each column and then across, so cell `i` is in
|
|
6
|
+
* column `floor(i / rows)` and row `i % rows`, on every page: a right-to-left
|
|
7
|
+
* page turns the drawing about, and a rectangle between two cells takes in the
|
|
8
|
+
* same cells whichever way the columns run.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The cells between `from` and `to` by row and by column, in the order the
|
|
12
|
+
* cells are drawn: every cell whose column lies between theirs and whose row
|
|
13
|
+
* lies between theirs. A place past the end of a short last column holds no
|
|
14
|
+
* cell and is skipped. With one row, it is the run of cells from one to the
|
|
15
|
+
* other.
|
|
16
|
+
*/
|
|
17
|
+
export declare const rectangleOf: (count: number, rows: number, from: number, to: number) => number[];
|
|
18
|
+
/**
|
|
19
|
+
* `picked` without repeats, in the order `order` gives: the selected cells in
|
|
20
|
+
* the order the table lists them. A value `order` does not hold keeps its
|
|
21
|
+
* place after the rest, so a selected day the strip no longer draws stays
|
|
22
|
+
* selected.
|
|
23
|
+
*/
|
|
24
|
+
export declare const inSequence: (picked: readonly string[], order: readonly string[]) => string[];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const within = (value, a, b) => (value - a) * (value - b) <= 0;
|
|
2
|
+
export const rectangleOf = (count, rows, from, to) => {
|
|
3
|
+
const taken = [];
|
|
4
|
+
for (let at = 0; at < count; at += 1) {
|
|
5
|
+
if (within(Math.floor(at / rows), Math.floor(from / rows), Math.floor(to / rows)) &&
|
|
6
|
+
within(at % rows, from % rows, to % rows)) {
|
|
7
|
+
taken.push(at);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return taken;
|
|
11
|
+
};
|
|
12
|
+
export const inSequence = (picked, order) => {
|
|
13
|
+
const at = (key) => {
|
|
14
|
+
const place = order.indexOf(key);
|
|
15
|
+
return place < 0 ? order.length : place;
|
|
16
|
+
};
|
|
17
|
+
return [...new Set(picked)].sort((a, b) => at(a) - at(b));
|
|
18
|
+
};
|
|
@@ -50,6 +50,16 @@ declare const HelixHeadlessHeatmap_base: typeof HelixElement & (new (...args: an
|
|
|
50
50
|
* `helix-before-change` and tells with `change`, and the `selection` part says
|
|
51
51
|
* how many are selected, in `selection-label`.
|
|
52
52
|
*
|
|
53
|
+
* **`selection-shape="rectangle"` selects a rectangle of cells** under
|
|
54
|
+
* `multiple`, as a spreadsheet selects a range: the cells between two corners
|
|
55
|
+
* by row and by column, such as the same weekdays across three weeks with
|
|
56
|
+
* `rows="7"`. Shift with a key that moves grows or shrinks it from the cell
|
|
57
|
+
* last pressed, Shift with a click takes it to the cell clicked, and a click
|
|
58
|
+
* with Ctrl or Command selects one cell or lets it go and starts the next
|
|
59
|
+
* rectangle there. The rectangle is the same cells on a right-to-left page,
|
|
60
|
+
* where the columns run from the right, a short last column adds only the
|
|
61
|
+
* cells it has, and `value` lists the selected days in the table's order.
|
|
62
|
+
*
|
|
53
63
|
* **Under `selection-mode` the strip is a grid**, so the selection is state a
|
|
54
64
|
* reader is told rather than words alone: each column of the strip is a `row`,
|
|
55
65
|
* a week with `rows="7"`, and each cell a `gridcell` named by its row in the
|
|
@@ -80,6 +90,7 @@ declare const HelixHeadlessHeatmap_base: typeof HelixElement & (new (...args: an
|
|
|
80
90
|
* | Page Down, Page Up | Moves a month on or back where the rows carry dates, and four columns otherwise. |
|
|
81
91
|
* | Enter, Space | Presses the cell, which sends `helix-reading-press`, and selects it or lets it go under `selection-mode`. |
|
|
82
92
|
* | Shift with an arrow, Home, End, Page Up or Page Down | Selects every cell from the last one pressed to where the key went, under `selection-mode="multiple"`. |
|
|
93
|
+
* | Shift with an arrow, Home, End, Page Up or Page Down, with `selection-shape="rectangle"` | Grows or shrinks the rectangle from the last cell pressed to where the key went, in rows and columns, under `selection-mode="multiple"`. |
|
|
83
94
|
* | Escape | Puts the cell's tooltip away. |
|
|
84
95
|
*
|
|
85
96
|
* @since 0.1.0
|
|
@@ -227,6 +238,12 @@ export declare class HelixHeadlessHeatmap extends HelixHeadlessHeatmap_base {
|
|
|
227
238
|
* Absent selects nothing, and a press or Space does what it did.
|
|
228
239
|
*/
|
|
229
240
|
selectionMode?: 'multiple' | 'single';
|
|
241
|
+
/**
|
|
242
|
+
* What Shift takes in under `selection-mode="multiple"`: `linear`, every
|
|
243
|
+
* cell between two in the table's order, or `rectangle`, the cells between
|
|
244
|
+
* two corners by row and by column, as a spreadsheet selects a range.
|
|
245
|
+
*/
|
|
246
|
+
selectionShape: 'linear' | 'rectangle';
|
|
230
247
|
/**
|
|
231
248
|
* The strip's name where the chart has none: no `aria-label`, `label`, or
|
|
232
249
|
* table caption.
|
|
@@ -318,6 +335,15 @@ export declare class HelixHeadlessHeatmap extends HelixHeadlessHeatmap_base {
|
|
|
318
335
|
private announced;
|
|
319
336
|
/** Where a range taken in with Shift starts: the cell last pressed, or none. */
|
|
320
337
|
private anchor;
|
|
338
|
+
/** The cell the keys rested on before the key now being handled moved them. */
|
|
339
|
+
private left;
|
|
340
|
+
/**
|
|
341
|
+
* What a rectangle is added to: the selection when it was started, less its
|
|
342
|
+
* anchor, kept while `value` is still the rectangle last written.
|
|
343
|
+
*/
|
|
344
|
+
private base;
|
|
345
|
+
/** The `value` the last rectangle wrote. */
|
|
346
|
+
private shaped;
|
|
321
347
|
/** The region a change of selection is said in, rendered from the first change. */
|
|
322
348
|
private readonly status;
|
|
323
349
|
/**
|
|
@@ -334,13 +360,24 @@ export declare class HelixHeadlessHeatmap extends HelixHeadlessHeatmap_base {
|
|
|
334
360
|
private choose;
|
|
335
361
|
/** Selects the drawn cell at `index`, or lets it go, as `selection-mode` says. */
|
|
336
362
|
private press;
|
|
363
|
+
/**
|
|
364
|
+
* Selects the rectangle from the anchor to the drawn cell at `to`, beside
|
|
365
|
+
* what was selected before it started, under `selection-shape="rectangle"`.
|
|
366
|
+
* Without an anchor it starts where the keys were.
|
|
367
|
+
*/
|
|
368
|
+
private stretch;
|
|
369
|
+
/** Notes where the keys rest before the pointer controller moves them. */
|
|
370
|
+
private readonly onStripKeydown;
|
|
337
371
|
/**
|
|
338
372
|
* Space and Enter select the cell the keys rest on, and Shift with a key
|
|
339
373
|
* that moved them takes in the range from the anchor. After the pointer
|
|
340
374
|
* controller, which has already moved `at` for an arrow.
|
|
341
375
|
*/
|
|
342
376
|
private readonly onKeydown;
|
|
343
|
-
/**
|
|
377
|
+
/**
|
|
378
|
+
* A press on a cell selects it, under `selection-mode`, and Shift takes the
|
|
379
|
+
* rectangle to it under `selection-shape="rectangle"`.
|
|
380
|
+
*/
|
|
344
381
|
private readonly onClick;
|
|
345
382
|
/**
|
|
346
383
|
* Every row in the table, oldest first, as the table is written, with its
|
|
@@ -8,6 +8,7 @@ import { AriaForwardController, byRow, CHART_PLOT, commaList, customElement, dra
|
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
10
|
import '../../tooltip/index.js';
|
|
11
|
+
import { inSequence, rectangleOf } from '../rectangle.js';
|
|
11
12
|
import { fits, monthPage, overviewOf, toneOf } from './buckets.js';
|
|
12
13
|
let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartStatus(MixinChartSource(HelixElement)) {
|
|
13
14
|
constructor() {
|
|
@@ -19,6 +20,7 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartStatus(M
|
|
|
19
20
|
this.rows = 1;
|
|
20
21
|
this.selectedLabel = 'selected';
|
|
21
22
|
this.selectionLabel = '{count, plural, one {# selected} other {# selected}}';
|
|
23
|
+
this.selectionShape = 'linear';
|
|
22
24
|
this.stripLabel = 'Heatmap';
|
|
23
25
|
this.thresholds = '';
|
|
24
26
|
this.tones = '';
|
|
@@ -32,7 +34,13 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartStatus(M
|
|
|
32
34
|
this.observer = undefined;
|
|
33
35
|
this.announced = undefined;
|
|
34
36
|
this.anchor = -1;
|
|
37
|
+
this.left = -1;
|
|
38
|
+
this.base = undefined;
|
|
39
|
+
this.shaped = undefined;
|
|
35
40
|
this.status = new StatusController(this);
|
|
41
|
+
this.onStripKeydown = () => {
|
|
42
|
+
this.left = this.pointer.at;
|
|
43
|
+
};
|
|
36
44
|
this.onKeydown = (event) => {
|
|
37
45
|
const at = this.pointer.at;
|
|
38
46
|
if (!this.selectionMode || at < 0 || event.altKey || event.ctrlKey || event.metaKey) {
|
|
@@ -47,6 +55,10 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartStatus(M
|
|
|
47
55
|
if (!event.shiftKey || !moves || this.selectionMode !== 'multiple') {
|
|
48
56
|
return;
|
|
49
57
|
}
|
|
58
|
+
if (this.selectionShape === 'rectangle') {
|
|
59
|
+
this.stretch(at);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
50
62
|
const keys = this.keysOf(this.drawn);
|
|
51
63
|
const added = rangeAdd(commaList(this.value), keys, this.anchor < 0 ? at : this.anchor, at);
|
|
52
64
|
if (added) {
|
|
@@ -56,7 +68,14 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartStatus(M
|
|
|
56
68
|
this.onClick = (event) => {
|
|
57
69
|
const cell = event.target?.closest?.('[part~="cell"]');
|
|
58
70
|
const index = Number(cell?.getAttribute('data-index') ?? -1);
|
|
59
|
-
if (cell
|
|
71
|
+
if (!cell || !Number.isInteger(index) || index < 0) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const rectangle = this.selectionMode === 'multiple' && this.selectionShape === 'rectangle';
|
|
75
|
+
if (rectangle && event.shiftKey && this.anchor >= 0) {
|
|
76
|
+
this.stretch(index);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
60
79
|
this.press(index);
|
|
61
80
|
}
|
|
62
81
|
};
|
|
@@ -112,8 +131,23 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartStatus(M
|
|
|
112
131
|
return;
|
|
113
132
|
}
|
|
114
133
|
this.anchor = index;
|
|
134
|
+
this.base = undefined;
|
|
115
135
|
this.choose(pressedValue(mode, this.value, key));
|
|
116
136
|
}
|
|
137
|
+
stretch(to) {
|
|
138
|
+
const keys = this.keysOf(this.drawn);
|
|
139
|
+
if (this.anchor < 0) {
|
|
140
|
+
this.anchor = this.left < 0 ? to : this.left;
|
|
141
|
+
}
|
|
142
|
+
if (this.base === undefined || this.value !== this.shaped) {
|
|
143
|
+
const corner = keys[this.anchor];
|
|
144
|
+
this.base = commaList(this.value).filter((one) => one !== corner);
|
|
145
|
+
}
|
|
146
|
+
const taken = rectangleOf(keys.length, this.rowCount, this.anchor, to).map((at) => keys[at] ?? '');
|
|
147
|
+
const all = this.keysOf(this.points);
|
|
148
|
+
this.choose(inSequence([...this.base, ...taken].filter(Boolean), all).join(', '));
|
|
149
|
+
this.shaped = this.value;
|
|
150
|
+
}
|
|
117
151
|
get points() {
|
|
118
152
|
const series = this.series[0];
|
|
119
153
|
if (!series) {
|
|
@@ -250,6 +284,7 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartStatus(M
|
|
|
250
284
|
style="--heatmap-rows: ${this.rowCount}"
|
|
251
285
|
tabindex=${readable ? '0' : nothing}
|
|
252
286
|
@click=${this.onClick}
|
|
287
|
+
@keydown=${this.onStripKeydown}
|
|
253
288
|
@pointerover=${this.onPointerOver}
|
|
254
289
|
@pointerleave=${this.onPointerLeave}
|
|
255
290
|
@pointerup=${this.onPointerUp}
|
|
@@ -348,6 +383,9 @@ __decorate([
|
|
|
348
383
|
__decorate([
|
|
349
384
|
property({ attribute: 'selection-mode' })
|
|
350
385
|
], HelixHeadlessHeatmap.prototype, "selectionMode", void 0);
|
|
386
|
+
__decorate([
|
|
387
|
+
property({ attribute: 'selection-shape' })
|
|
388
|
+
], HelixHeadlessHeatmap.prototype, "selectionShape", void 0);
|
|
351
389
|
__decorate([
|
|
352
390
|
words,
|
|
353
391
|
property({ attribute: 'strip-label' })
|