@fusion.dev/helix-headless 0.185.0 → 0.186.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.
Files changed (43) hide show
  1. package/custom-elements.json +2663 -31
  2. package/dist/accordion/item/accordion-item.js +1 -1
  3. package/dist/button-group/root/button-group-root.js +1 -1
  4. package/dist/canvas/root/canvas-root.js +1 -1
  5. package/dist/dialog/root/dialog-root.js +1 -1
  6. package/dist/drawer/root/drawer-root.js +1 -1
  7. package/dist/drilldown/item/drilldown-item.js +1 -1
  8. package/dist/element-events.generated.js +7 -0
  9. package/dist/graph/root/graph-root.d.ts +6 -4
  10. package/dist/graph/root/graph-root.js +3 -3
  11. package/dist/heatmap/root/heatmap-root.d.ts +15 -15
  12. package/dist/icon/all/index.js +0 -3
  13. package/dist/icon/root/icon-root.d.ts +11 -18
  14. package/dist/icon/root/icon-root.js +4 -16
  15. package/dist/icon/set.js +2 -16
  16. package/dist/index.d.ts +2 -1
  17. package/dist/index.js +2 -1
  18. package/dist/isometric-heatmap/index.d.ts +1 -0
  19. package/dist/isometric-heatmap/index.js +1 -0
  20. package/dist/isometric-heatmap/projection.d.ts +70 -0
  21. package/dist/isometric-heatmap/projection.js +49 -0
  22. package/dist/isometric-heatmap/root/isometric-heatmap-root.d.ts +118 -0
  23. package/dist/isometric-heatmap/root/isometric-heatmap-root.js +127 -0
  24. package/dist/lightbox/root/lightbox-root.js +1 -1
  25. package/dist/list/root/list-root.js +1 -1
  26. package/dist/map/root/map-root.js +1 -1
  27. package/dist/menu/item/menu-item.js +1 -1
  28. package/dist/outline/root/outline-root.js +2 -2
  29. package/dist/popover/root/popover-root.js +1 -1
  30. package/dist/table/root/table-root.js +1 -1
  31. package/dist/tabs/root/tabs-root.js +4 -5
  32. package/dist/tabs/tab/tab.js +2 -3
  33. package/dist/time-picker/root/time-picker-root.js +1 -1
  34. package/dist/toggle/root/toggle-root.js +1 -1
  35. package/dist/tour/root/tour-root.js +1 -1
  36. package/dist/tree/root/tree-root.js +1 -1
  37. package/dist/video/root/video-root.js +1 -1
  38. package/lint.json +1 -1
  39. package/package.json +6 -6
  40. package/types/jsx.d.ts +1274 -40
  41. package/types/svelte.d.ts +1 -0
  42. package/types/vue.d.ts +264 -6
  43. package/types/words.d.ts +69 -0
@@ -0,0 +1,127 @@
1
+ import { __decorate } from "tslib";
2
+ import { CHART_PLOT, commaList, customElement, drawTooltip, MIRROR_RULE, spokenReading, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
3
+ import { html, nothing, svg } from 'lit';
4
+ import { property } from 'lit/decorators.js';
5
+ import '../../tooltip/index.js';
6
+ import { fits, toneOf } from '../../heatmap/root/buckets.js';
7
+ import { HelixHeadlessHeatmap } from '../../heatmap/root/heatmap-root.js';
8
+ import { ACROSS, heightsOf, highestOf, reliefOf } from '../projection.js';
9
+ let HelixHeadlessIsometricHeatmap = class HelixHeadlessIsometricHeatmap extends HelixHeadlessHeatmap {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.flat = false;
13
+ this.relief = 2;
14
+ this.shown = undefined;
15
+ }
16
+ static { this.words = 'helix-isometric-heatmap'; }
17
+ static { this.markRules = [MIRROR_RULE]; }
18
+ get room() {
19
+ const width = this.width;
20
+ if (width === undefined) {
21
+ return this.points.length;
22
+ }
23
+ const pitch = this.cellPx + this.gapPx;
24
+ const across = width / ACROSS - this.rowCount * pitch - this.gapPx;
25
+ return fits(this.points.length, Math.max(across, Number.MIN_VALUE), this.cellPx, this.gapPx, this.rowCount);
26
+ }
27
+ drawnRelief() {
28
+ const tallest = this.flat ? 0 : Math.max(0, this.relief || 0);
29
+ const highest = highestOf(this.points.map((point) => point.value));
30
+ const heights = heightsOf(this.drawn.map((point) => point.value), highest, tallest);
31
+ return reliefOf(heights, this.rowCount, this.cellPx / (this.cellPx + this.gapPx));
32
+ }
33
+ render() {
34
+ const bounds = writtenNumbers(this.thresholds);
35
+ const palette = writtenList(this.tones);
36
+ const cells = this.drawn;
37
+ const readable = cells.length > 0;
38
+ const grid = readable && this.selectionMode !== undefined;
39
+ const keys = this.selectionMode ? this.keysOf(cells) : [];
40
+ const chosen = new Set(this.selectionMode ? commaList(this.value) : []);
41
+ const relief = this.drawnRelief();
42
+ this.shown = relief;
43
+ const at = this.pointer.at;
44
+ const prisms = relief.prisms.map((prism) => this.renderPrism(prism.index, prism.top, prism.left, prism.right, at === prism.index, chosen.has(keys[prism.index] ?? ''), grid, toneOf(cells[prism.index] ?? { value: undefined }, bounds, palette)));
45
+ const { box } = relief;
46
+ const drawing = readable
47
+ ? html `<svg
48
+ aria-hidden=${grid ? nothing : 'true'}
49
+ data-mirror
50
+ part="drawing"
51
+ role=${grid ? 'none' : nothing}
52
+ viewBox="${box.x} ${box.y} ${box.width} ${box.height}"
53
+ xmlns="http://www.w3.org/2000/svg"
54
+ >${grid ? this.renderPrismRows(prisms) : prisms}</svg>`
55
+ : nothing;
56
+ return html `<div
57
+ aria-activedescendant=${grid && at >= 0 ? `cell-${at}` : nothing}
58
+ aria-describedby=${readable ? 'helix-chart-summary' : nothing}
59
+ aria-label=${this.named || this.stripLabel}
60
+ aria-multiselectable=${grid && this.selectionMode === 'multiple' ? 'true' : nothing}
61
+ part="strip plot"
62
+ id=${CHART_PLOT}
63
+ role=${grid ? 'grid' : readable ? 'application' : 'img'}
64
+ style="--isometric-heatmap-span: ${Math.ceil(cells.length / this.rowCount) + Math.min(this.rowCount, cells.length)}"
65
+ tabindex=${readable ? '0' : nothing}
66
+ @click=${this.onClick}
67
+ @keydown=${this.onStripKeydown}
68
+ @pointerover=${this.onPointerOver}
69
+ @pointerleave=${this.onPointerLeave}
70
+ @pointerup=${this.onPointerUp}
71
+ >${drawing}${this.renderTooltip(grid)}</div>
72
+ ${cells.length === 0 ? this.renderStatus() : nothing}
73
+ <div part="footer">
74
+ <span part="start"><slot name="start"></slot></span>
75
+ <span part="summary"><slot name="summary"></slot></span>
76
+ <span part="end"><slot name="end"></slot></span>
77
+ </div>${readable ? this.renderOverview(cells) : nothing}${this.status.spoken
78
+ ? html `<span part="selection" role="status">${this.status.said}</span>`
79
+ : nothing}${this.renderTable()}`;
80
+ }
81
+ renderPrism(index, top, left, right, active, picked, grid, tone) {
82
+ const row = grid ? this.sourceRows[this.points.length - this.drawn.length + index] : undefined;
83
+ const name = row ? spokenReading(row) : '';
84
+ return svg `<g
85
+ aria-label=${grid && name ? name : nothing}
86
+ aria-selected=${grid ? (picked ? 'true' : 'false') : nothing}
87
+ data-index=${index}
88
+ data-tone=${tone ?? nothing}
89
+ id=${grid ? `cell-${index}` : nothing}
90
+ part="cell${active ? ' cell-active' : ''}${picked ? ' cell-selected' : ''}"
91
+ role=${grid ? 'gridcell' : nothing}
92
+ style=${tone === undefined ? nothing : `--heatmap-tone: var(--heatmap-tone-${tone})`}
93
+ ><path d=${left} part="left-face"></path><path d=${right} part="right-face"></path><path d=${top} part="top-face"></path></g>`;
94
+ }
95
+ renderPrismRows(prisms) {
96
+ const size = this.rowCount === 1 ? prisms.length : this.rowCount;
97
+ const rows = [];
98
+ for (let start = 0; start < prisms.length; start += size) {
99
+ rows.push(svg `<g part="row" role="row">${prisms.slice(start, start + size)}</g>`);
100
+ }
101
+ return rows;
102
+ }
103
+ renderTooltip(grid = false) {
104
+ const at = this.pointer.at;
105
+ const prism = this.shown?.prisms[at];
106
+ const box = this.shown?.box;
107
+ const reading = grid ? undefined : this.pointer;
108
+ if (at < 0 || !prism || !box || box.width <= 0 || box.height <= 0) {
109
+ return drawTooltip(this.sourceRows, -1, this.tag('tooltip'), undefined, undefined, reading);
110
+ }
111
+ return drawTooltip(this.sourceRows, this.points.length - this.drawn.length + at, this.tag('tooltip'), {
112
+ placement: 'top',
113
+ x: `${((prism.peak.x - box.x) / box.width) * 100}%`,
114
+ y: `${((prism.peak.y - box.y) / box.height) * 100}%`,
115
+ }, undefined, reading);
116
+ }
117
+ };
118
+ __decorate([
119
+ property({ type: Boolean })
120
+ ], HelixHeadlessIsometricHeatmap.prototype, "flat", void 0);
121
+ __decorate([
122
+ property({ type: Number })
123
+ ], HelixHeadlessIsometricHeatmap.prototype, "relief", void 0);
124
+ HelixHeadlessIsometricHeatmap = __decorate([
125
+ customElement('helix-headless-isometric-heatmap')
126
+ ], HelixHeadlessIsometricHeatmap);
127
+ export { HelixHeadlessIsometricHeatmap };
@@ -356,7 +356,7 @@ let HelixHeadlessLightbox = class HelixHeadlessLightbox extends MixinControllerA
356
356
  return;
357
357
  }
358
358
  if (this.open && !dialog.open) {
359
- auditName(this, () => null, 'Give it a `label`, such as "Project photos".', () => this.label !== '');
359
+ auditName(this, () => null, 'lightbox', () => this.label !== '');
360
360
  dialog.showModal();
361
361
  dialog.focus({ preventScroll: true });
362
362
  this.idle.stir();
@@ -366,7 +366,7 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
366
366
  this.sync();
367
367
  }
368
368
  if (this.interactive) {
369
- auditName(this, () => null, 'Give it a `label`, or an `aria-label` that says what the rows are.', () => this.label !== '');
369
+ auditName(this, () => null, 'list', () => this.label !== '');
370
370
  }
371
371
  if (this.childrenKnown) {
372
372
  this.toggleState('empty', this.rows.length === 0);
@@ -346,7 +346,7 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
346
346
  firstUpdated(changed) {
347
347
  super.firstUpdated(changed);
348
348
  this.finishHydration();
349
- auditName(this, () => null, 'Give it a `label` that says what the map shows, such as "Stores in Edinburgh".', () => this.label !== '');
349
+ auditName(this, () => null, 'map', () => this.label !== '');
350
350
  }
351
351
  updated(changed) {
352
352
  super.updated(changed);
@@ -116,7 +116,7 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
116
116
  : [],
117
117
  });
118
118
  if (this.partNamed('item')) {
119
- auditName(this, () => this.partNamed('item') ?? undefined, 'Give the row words in its default slot, or a label on the icon it holds.');
119
+ auditName(this, () => this.partNamed('item') ?? undefined, 'row');
120
120
  }
121
121
  }
122
122
  renderDescription() {
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { customElement, elementById, HelixActivateEvent, HelixElement, IndicatorController, plainClick, reflectElements, scrollItemIntoView, scrollingAncestor, words, } from '@fusion.dev/helix-core';
2
+ import { customElement, elementById, HelixActivateEvent, HelixElement, IndicatorController, plainClick, reflectElements, scrollingAncestor, scrollWithin, words, } from '@fusion.dev/helix-core';
3
3
  import { html, nothing } from 'lit';
4
4
  import { property } from 'lit/decorators.js';
5
5
  import { levelOf, nest } from '../levels.js';
@@ -151,7 +151,7 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
151
151
  const sections = this.scroller;
152
152
  const node = scrollingAncestor(link, { axis: 'y', overflowing: true, stop: this.page });
153
153
  if (node && node !== sections && !node.contains(sections)) {
154
- scrollItemIntoView(link, { scroller: node });
154
+ scrollWithin(link, node);
155
155
  }
156
156
  }
157
157
  get atEnd() {
@@ -216,7 +216,7 @@ let HelixHeadlessPopover = class HelixHeadlessPopover extends MixinControllerOpe
216
216
  this.tellTrigger();
217
217
  this.nameByHeading();
218
218
  if (changed.has('open') && this.open) {
219
- auditName(this, () => null, 'Give it a `label`, or a heading in the panel.', () => this.label !== '' || this.namedByHeading || headingIn(this.slotted) != null);
219
+ auditName(this, () => null, 'popover', () => this.label !== '' || this.namedByHeading || headingIn(this.slotted) != null);
220
220
  }
221
221
  if (this.settled) {
222
222
  this.hideAround();
@@ -786,7 +786,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
786
786
  this.markSorted();
787
787
  this.markSelected();
788
788
  this.nameByHeading();
789
- auditName(this, () => null, 'Give it a `label`, or put a heading in its `heading` slot, that says what the rows are.', () => this.label !== '' || this.headings.length > 0);
789
+ auditName(this, () => null, 'table', () => this.label !== '' || this.headings.length > 0);
790
790
  if (this.childrenKnown) {
791
791
  this.gridKeys.mark();
792
792
  this.gridKeys.place();
@@ -1,9 +1,8 @@
1
1
  import { __decorate } from "tslib";
2
- import { AriaForwardController, customElement, deepActiveElement, HelixActivateEvent, HelixElement, IndicatorController, isRtl, KeyboardNavigationController, MIRROR_RULE, MixinControllerActive, scrollItemIntoView, whenHydrated, words, } from '@fusion.dev/helix-core';
2
+ import { AriaForwardController, customElement, deepActiveElement, glyphPath, HelixActivateEvent, HelixElement, IndicatorController, isRtl, KeyboardNavigationController, MIRROR_RULE, MixinControllerActive, scrollWithin, whenHydrated, words, } from '@fusion.dev/helix-core';
3
3
  import { caretDown, caretLeft, caretRight, caretUp } from '@fusion.dev/helix-icons';
4
4
  import { html, nothing } from 'lit';
5
5
  import { property, state } from 'lit/decorators.js';
6
- import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
7
6
  import { HelixHeadlessTabPanel } from '../panel/tab-panel.js';
8
7
  import { HelixHeadlessTab } from '../tab/tab.js';
9
8
  let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(HelixElement) {
@@ -192,7 +191,7 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
192
191
  const strip = this.partNamed('tabs');
193
192
  const tab = this.tabs.find((one) => one.selected);
194
193
  if (strip && tab) {
195
- scrollItemIntoView(tab, { padding: this.scrollControls ? 40 : 0, scroller: strip });
194
+ scrollWithin(tab, strip, { padding: this.scrollControls ? 40 : 0 });
196
195
  }
197
196
  }
198
197
  updated(changed) {
@@ -223,8 +222,8 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
223
222
  const icon = down ? (toward > 0 ? caretDown : caretUp) : toward > 0 ? caretRight : caretLeft;
224
223
  const mirror = down ? nothing : '';
225
224
  return toward > 0
226
- ? html `<slot name="scroll-end-icon"><svg part="scroll-end-mark" data-mirror=${mirror} aria-hidden="true" fill="currentColor" viewBox=${icon.viewBox}>${unsafeSVG(icon.content)}</svg></slot>`
227
- : html `<slot name="scroll-start-icon"><svg part="scroll-start-mark" data-mirror=${mirror} aria-hidden="true" fill="currentColor" viewBox=${icon.viewBox}>${unsafeSVG(icon.content)}</svg></slot>`;
225
+ ? html `<slot name="scroll-end-icon"><svg part="scroll-end-mark" data-mirror=${mirror} aria-hidden="true" fill="currentColor" viewBox=${icon.viewBox}><path d=${glyphPath(icon)}></path></svg></slot>`
226
+ : html `<slot name="scroll-start-icon"><svg part="scroll-start-mark" data-mirror=${mirror} aria-hidden="true" fill="currentColor" viewBox=${icon.viewBox}><path d=${glyphPath(icon)}></path></svg></slot>`;
228
227
  }
229
228
  render() {
230
229
  return html `<div
@@ -1,9 +1,8 @@
1
1
  import { __decorate } from "tslib";
2
- import { customElement, HelixElement, MixinDismissible, MixinSelectableItem, plainClick, reflectElements, words, } from '@fusion.dev/helix-core';
2
+ import { customElement, glyphPath, HelixElement, MixinDismissible, MixinSelectableItem, plainClick, reflectElements, words, } from '@fusion.dev/helix-core';
3
3
  import { x } from '@fusion.dev/helix-icons';
4
4
  import { html, nothing } from 'lit';
5
5
  import { property } from 'lit/decorators.js';
6
- import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
7
6
  let HelixHeadlessTab = class HelixHeadlessTab extends MixinDismissible(MixinSelectableItem(HelixElement)) {
8
7
  constructor() {
9
8
  super(...arguments);
@@ -49,7 +48,7 @@ let HelixHeadlessTab = class HelixHeadlessTab extends MixinDismissible(MixinSele
49
48
  }
50
49
  return html `<span part="dismiss" aria-hidden="true" title=${this.dismissLabel} @click=${this.handleDismissPress}
51
50
  ><slot name="dismiss-icon"
52
- ><svg part="dismiss-mark" fill="currentColor" viewBox=${x.viewBox} aria-hidden="true">${unsafeSVG(x.content)}</svg></slot
51
+ ><svg part="dismiss-mark" fill="currentColor" viewBox=${x.viewBox} aria-hidden="true"><path d=${glyphPath(x)}></path></svg></slot
53
52
  ></span
54
53
  >`;
55
54
  }
@@ -375,7 +375,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
375
375
  }
376
376
  firstUpdated(changed) {
377
377
  super.firstUpdated(changed);
378
- auditName(this, () => null, 'Give it a `label`, a label in the `label` slot, or an `aria-label` that says what the time is for.', () => this.listName !== '');
378
+ auditName(this, () => null, 'time-picker', () => this.listName !== '');
379
379
  const list = this.partNamed('list');
380
380
  if (list) {
381
381
  auditName(list, () => null, '', () => true);
@@ -34,7 +34,7 @@ let HelixHeadlessToggle = class HelixHeadlessToggle extends MixinSelectableItem(
34
34
  firstUpdated(changed) {
35
35
  super.firstUpdated(changed);
36
36
  this.finishHydration();
37
- auditName(this, () => this.partNamed('item'), 'Give it words in its default slot, an `aria-label`, or a label on the icon it holds.');
37
+ auditName(this, () => this.partNamed('item'), 'toggle');
38
38
  }
39
39
  click() {
40
40
  if (!this.clicks.click()) {
@@ -233,7 +233,7 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
233
233
  this.settle();
234
234
  this.light();
235
235
  if (changed.has('open') && this.open) {
236
- auditName(this, () => null, 'Give it a `label`, such as "Getting started".', () => this.label !== '');
236
+ auditName(this, () => null, 'tour', () => this.label !== '');
237
237
  }
238
238
  this.follow(changed);
239
239
  this.wait();
@@ -468,7 +468,7 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
468
468
  firstUpdated(changed) {
469
469
  super.firstUpdated(changed);
470
470
  this.syncItems();
471
- auditName(this, () => null, 'Give it a `label` that says what it holds, such as "Files".', () => this.hasAttribute('label') || this.label !== 'Tree');
471
+ auditName(this, () => null, 'tree', () => this.hasAttribute('label') || this.label !== 'Tree');
472
472
  }
473
473
  updated(changed) {
474
474
  super.updated(changed);
@@ -459,7 +459,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
459
459
  firstUpdated(changed) {
460
460
  super.firstUpdated?.(changed);
461
461
  this.finishHydration();
462
- auditName(this, () => null, 'Give it a `label` that says what the video shows, such as "Product tour".', () => this.label !== '');
462
+ auditName(this, () => null, 'video', () => this.label !== '');
463
463
  const video = this.video;
464
464
  if (video) {
465
465
  if (this.defaultMuted || this.silent) {