@fusion.dev/helix-headless 0.105.0 → 0.106.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.
Files changed (162) hide show
  1. package/custom-elements.json +7324 -3890
  2. package/dist/accordion/item/accordion-item.d.ts +17 -16
  3. package/dist/accordion/root/accordion-root.d.ts +13 -17
  4. package/dist/announcement/root/announcement-root.d.ts +24 -31
  5. package/dist/app-header/root/app-header-root.d.ts +14 -14
  6. package/dist/area-chart/root/area-chart-root.d.ts +29 -48
  7. package/dist/avatar/group/avatar-group.d.ts +6 -8
  8. package/dist/avatar/root/avatar-root.d.ts +11 -11
  9. package/dist/badge/root/badge-root.d.ts +14 -15
  10. package/dist/bar-chart/root/bar-chart-root.d.ts +40 -44
  11. package/dist/blockquote/root/blockquote-root.d.ts +5 -7
  12. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +25 -33
  13. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +12 -11
  14. package/dist/button/root/button-root.d.ts +16 -17
  15. package/dist/button-group/root/button-group-root.d.ts +9 -10
  16. package/dist/callout/root/callout-root.d.ts +10 -15
  17. package/dist/canvas/edge/canvas-edge.d.ts +21 -21
  18. package/dist/canvas/node/canvas-node.d.ts +43 -45
  19. package/dist/canvas/root/canvas-root.d.ts +100 -99
  20. package/dist/card/root/card-root.d.ts +10 -12
  21. package/dist/carousel/root/carousel-root.d.ts +32 -33
  22. package/dist/chat/composer/chat-composer.d.ts +24 -26
  23. package/dist/chat/message/chat-message.d.ts +30 -33
  24. package/dist/chat/root/chat-root.d.ts +63 -80
  25. package/dist/checkbox/root/checkbox-root.d.ts +30 -32
  26. package/dist/checkbox-group/root/checkbox-group-root.d.ts +25 -25
  27. package/dist/code/root/code-root.d.ts +6 -10
  28. package/dist/code-block/root/code-block-root.d.ts +35 -48
  29. package/dist/color-input/root/color-input-root.d.ts +52 -56
  30. package/dist/color-picker/root/color-picker-root.d.ts +49 -49
  31. package/dist/combobox/root/combobox-root.d.ts +52 -53
  32. package/dist/command/root/command-root.d.ts +35 -40
  33. package/dist/copy-button/root/copy-button-root.d.ts +24 -26
  34. package/dist/data-table/root/data-table-root.d.ts +106 -107
  35. package/dist/date-input/root/date-input-root.d.ts +54 -53
  36. package/dist/date-picker/root/date-picker-root.d.ts +25 -21
  37. package/dist/description-list/item/description-list-item.d.ts +7 -7
  38. package/dist/description-list/root/description-list-root.d.ts +10 -15
  39. package/dist/dialog/root/dialog-root.d.ts +22 -19
  40. package/dist/divider/root/divider-root.d.ts +12 -13
  41. package/dist/donut-chart/root/donut-chart-root.d.ts +19 -20
  42. package/dist/drawer/root/drawer-root.d.ts +19 -18
  43. package/dist/drilldown/item/drilldown-item.d.ts +28 -28
  44. package/dist/drilldown/root/drilldown-root.d.ts +22 -28
  45. package/dist/element-events.generated.js +7 -0
  46. package/dist/empty/root/empty-root.d.ts +16 -19
  47. package/dist/file-input/root/file-input-root.d.ts +32 -32
  48. package/dist/filter-input/chip/filter-chip.d.ts +36 -39
  49. package/dist/filter-input/field/filter-field.d.ts +25 -31
  50. package/dist/filter-input/menu/filter-menu.d.ts +50 -47
  51. package/dist/filter-input/operator/filter-operator.d.ts +15 -20
  52. package/dist/filter-input/root/filter-input-root.d.ts +80 -98
  53. package/dist/format-date/root/format-date-root.d.ts +19 -27
  54. package/dist/heatmap/root/heatmap-root.d.ts +40 -41
  55. package/dist/icon/root/icon-root.d.ts +21 -23
  56. package/dist/icon-button/root/icon-button-root.d.ts +12 -14
  57. package/dist/image/root/image-root.d.ts +30 -30
  58. package/dist/input/root/input-root.d.ts +36 -35
  59. package/dist/kbd/root/kbd-root.d.ts +13 -15
  60. package/dist/legend/root/legend-root.d.ts +18 -16
  61. package/dist/lightbox/item/lightbox-item.d.ts +13 -15
  62. package/dist/lightbox/root/lightbox-root.d.ts +40 -41
  63. package/dist/line-chart/root/line-chart-root.d.ts +20 -29
  64. package/dist/list/item/list-item.d.ts +17 -22
  65. package/dist/list/root/list-root.d.ts +6 -7
  66. package/dist/listbox/root/listbox-root.d.ts +42 -41
  67. package/dist/loader/root/loader-root.d.ts +16 -20
  68. package/dist/map/area/map-area.d.ts +6 -0
  69. package/dist/map/area/map-area.js +3 -0
  70. package/dist/map/buildings/map-buildings.d.ts +45 -0
  71. package/dist/map/buildings/map-buildings.js +37 -0
  72. package/dist/map/contours/map-contours.d.ts +61 -0
  73. package/dist/map/contours/map-contours.js +54 -0
  74. package/dist/map/index.d.ts +7 -0
  75. package/dist/map/index.js +5 -0
  76. package/dist/map/landcover/map-landcover.d.ts +47 -0
  77. package/dist/map/landcover/map-landcover.js +37 -0
  78. package/dist/map/marker/map-marker.d.ts +11 -4
  79. package/dist/map/marker/map-marker.js +13 -1
  80. package/dist/map/points/map-points.d.ts +7 -1
  81. package/dist/map/points/map-points.js +3 -0
  82. package/dist/map/raster/map-raster.d.ts +84 -0
  83. package/dist/map/raster/map-raster.js +96 -0
  84. package/dist/map/root/map-root.d.ts +169 -7
  85. package/dist/map/root/map-root.js +352 -4
  86. package/dist/map/route/map-route.d.ts +6 -0
  87. package/dist/map/route/map-route.js +3 -0
  88. package/dist/map/terrain/map-terrain.d.ts +68 -0
  89. package/dist/map/terrain/map-terrain.js +58 -0
  90. package/dist/megamenu/root/megamenu-root.d.ts +27 -25
  91. package/dist/menu/item/menu-item.d.ts +30 -31
  92. package/dist/menu/root/menu-root.d.ts +25 -29
  93. package/dist/meter/root/meter-root.d.ts +22 -21
  94. package/dist/navigation/root/navigation-root.d.ts +13 -16
  95. package/dist/notifications/group/notification-group.d.ts +27 -28
  96. package/dist/notifications/notification/notification.d.ts +35 -42
  97. package/dist/notifications/root/notifications-root.d.ts +22 -24
  98. package/dist/number-input/root/number-input-root.d.ts +46 -50
  99. package/dist/object-inspector/root/object-inspector-root.d.ts +46 -58
  100. package/dist/option/group/option-group.d.ts +11 -11
  101. package/dist/option/root/option-root.d.ts +28 -33
  102. package/dist/outline/root/outline-root.d.ts +18 -17
  103. package/dist/pagination/root/pagination-root.d.ts +37 -39
  104. package/dist/pagination/size/pagination-size.d.ts +37 -43
  105. package/dist/pagination/summary/pagination-summary.d.ts +12 -14
  106. package/dist/pin-input/root/pin-input-root.d.ts +32 -38
  107. package/dist/popover/root/popover-root.d.ts +16 -21
  108. package/dist/progress/root/progress-root.d.ts +16 -14
  109. package/dist/qr-code/root/qr-code-root.d.ts +22 -25
  110. package/dist/quote/root/quote-root.d.ts +5 -6
  111. package/dist/radio/group/radio-group.d.ts +26 -28
  112. package/dist/radio/root/radio-root.d.ts +24 -28
  113. package/dist/rating/root/rating-root.d.ts +27 -30
  114. package/dist/scatter-chart/root/scatter-chart-root.d.ts +43 -55
  115. package/dist/scroll-area/root/scroll-area-root.d.ts +15 -21
  116. package/dist/select/root/select-root.d.ts +41 -44
  117. package/dist/skeleton/root/skeleton-root.d.ts +7 -8
  118. package/dist/skip-link/root/skip-link-root.d.ts +21 -28
  119. package/dist/slider/root/slider-root.d.ts +36 -39
  120. package/dist/sparkline/root/sparkline-root.d.ts +22 -28
  121. package/dist/speed-dial/item/speed-dial-item.d.ts +21 -21
  122. package/dist/speed-dial/root/speed-dial-root.d.ts +25 -27
  123. package/dist/splitter/root/splitter-root.d.ts +37 -41
  124. package/dist/stat/group/stat-group.d.ts +4 -4
  125. package/dist/stat/root/stat-root.d.ts +8 -9
  126. package/dist/steps/root/steps-root.d.ts +11 -14
  127. package/dist/steps/step/step.d.ts +22 -29
  128. package/dist/switch/root/switch-root.d.ts +20 -24
  129. package/dist/table/cell/table-cell.d.ts +18 -8
  130. package/dist/table/cell/table-cell.js +5 -1
  131. package/dist/table/column/table-column.d.ts +62 -55
  132. package/dist/table/root/table-root.d.ts +16 -17
  133. package/dist/table/row/table-row.d.ts +3 -3
  134. package/dist/tabs/panel/tab-panel.d.ts +3 -3
  135. package/dist/tabs/root/tabs-root.d.ts +19 -17
  136. package/dist/tabs/tab/tab.d.ts +6 -6
  137. package/dist/tag/root/tag-root.d.ts +11 -12
  138. package/dist/textarea/root/textarea-root.d.ts +29 -32
  139. package/dist/time-input/root/time-input-root.d.ts +70 -69
  140. package/dist/time-picker/root/time-picker-root.d.ts +58 -66
  141. package/dist/timeline/item/timeline-item.d.ts +18 -24
  142. package/dist/timeline/root/timeline-root.d.ts +13 -21
  143. package/dist/toast/item/toast-item.d.ts +21 -22
  144. package/dist/toast/root/toast-root.d.ts +18 -23
  145. package/dist/toggle/group/toggle-group.d.ts +23 -25
  146. package/dist/toggle/root/toggle-root.d.ts +8 -8
  147. package/dist/toolbar/root/toolbar-root.d.ts +7 -10
  148. package/dist/tooltip/root/tooltip-root.d.ts +41 -47
  149. package/dist/tour/root/tour-root.d.ts +24 -26
  150. package/dist/tour/stop/tour-stop.d.ts +39 -48
  151. package/dist/tree/item/tree-item.d.ts +23 -25
  152. package/dist/tree/root/tree-root.d.ts +13 -12
  153. package/dist/trend/root/trend-root.d.ts +18 -19
  154. package/dist/video/root/video-root.d.ts +108 -101
  155. package/dist/video-playlist/item/video-playlist-item.d.ts +23 -28
  156. package/dist/video-playlist/menu/video-playlist-menu.d.ts +17 -21
  157. package/dist/video-playlist/root/video-playlist-root.d.ts +21 -25
  158. package/dist/virtual-list/root/virtual-list-root.d.ts +27 -26
  159. package/package.json +5 -5
  160. package/types/jsx.d.ts +10363 -9520
  161. package/types/svelte.d.ts +5 -0
  162. package/types/vue.d.ts +1440 -1032
@@ -4,15 +4,67 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixActivateEvent, HelixElement, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapZoomEvent, hostAria, KeyboardNavigationController, MixinViewport, } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixActivateEvent, HelixElement, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, hostAria, KeyboardNavigationController, MixinViewport, } from '@fusion.dev/helix-core';
8
+ import { buildings, cloudRain, dotsNine, leaf, mountains, path, polygon, stack, target, } from '@fusion.dev/helix-icons';
8
9
  import { html, nothing } from 'lit';
9
10
  import { property, state } from 'lit/decorators.js';
11
+ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
12
+ const MAP_TYPES = ['standard', 'hybrid', 'satellite'];
13
+ const iconOf = (layer) => {
14
+ switch (layer?.layerKind) {
15
+ case 'route':
16
+ return path;
17
+ case 'area':
18
+ return polygon;
19
+ case 'points':
20
+ return dotsNine;
21
+ case 'buildings':
22
+ return buildings;
23
+ case 'terrain':
24
+ return mountains;
25
+ case 'contours':
26
+ return target;
27
+ case 'landcover':
28
+ return leaf;
29
+ case 'raster':
30
+ return cloudRain;
31
+ default:
32
+ return stack;
33
+ }
34
+ };
35
+ const ROTATE_STEP = 15;
36
+ const TILT_STEP = 10;
37
+ const TILTED = 50;
10
38
  let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement) {
11
39
  constructor() {
12
40
  super(...arguments);
41
+ this.bearing = 0;
13
42
  this.cluster = false;
43
+ this.faceNorthLabel = 'Face north';
44
+ this.hybridLabel = 'Hybrid';
14
45
  this.label = '';
15
- this.layersLabel = 'Routes, areas, and points';
46
+ this.layersLabel = 'Map layers';
47
+ this.mapPreviews = {};
48
+ this.mapTypeLabel = 'Map type';
49
+ this.pitch = 0;
50
+ this.rotateLeftLabel = 'Rotate left';
51
+ this.rotateRightLabel = 'Rotate right';
52
+ this.satelliteLabel = 'Satellite';
53
+ this.standardLabel = 'Standard';
54
+ this.tiltLabel = 'Show in 3D';
55
+ this.layersOpen = false;
56
+ this.handleOutside = (event) => {
57
+ if (!event.composedPath().includes(this)) {
58
+ this.layersOpen = false;
59
+ }
60
+ };
61
+ this.handleMenuKeydown = (event) => {
62
+ event.stopPropagation();
63
+ if (event.key === 'Escape' && this.layersOpen) {
64
+ this.layersOpen = false;
65
+ this.renderRoot.querySelector('[part="layers-toggle"]')?.focus();
66
+ }
67
+ };
16
68
  this.handlePartChange = (event) => {
17
69
  if (event.detail.kind !== 'place') {
18
70
  this.requestUpdate();
@@ -70,6 +122,40 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
70
122
  get layers() {
71
123
  return this.knownChildren.filter((child) => child.isMapLayer === true);
72
124
  }
125
+ get imagery() {
126
+ return this.layers.filter((layer) => layer.layerKind === 'raster' && layer.ground === true);
127
+ }
128
+ nameOf(type) {
129
+ return type === 'hybrid'
130
+ ? this.hybridLabel
131
+ : type === 'satellite'
132
+ ? this.satelliteLabel
133
+ : this.standardLabel;
134
+ }
135
+ showLayers(layers, shown) {
136
+ for (const layer of layers) {
137
+ layer.hidden = !shown;
138
+ }
139
+ this.requestUpdate();
140
+ }
141
+ get layerEntries() {
142
+ const entries = [];
143
+ const groups = new Map();
144
+ const imagery = this.imagery;
145
+ for (const layer of this.layers.filter((one) => !imagery.includes(one))) {
146
+ const had = layer.group ? groups.get(layer.group) : undefined;
147
+ if (had) {
148
+ had.push(layer);
149
+ continue;
150
+ }
151
+ const entry = [layer];
152
+ entries.push(entry);
153
+ if (layer.group) {
154
+ groups.set(layer.group, entry);
155
+ }
156
+ }
157
+ return entries;
158
+ }
73
159
  get markers() {
74
160
  return this.knownChildren.filter((child) => child.isMapMarker === true);
75
161
  }
@@ -92,9 +178,13 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
92
178
  this.addEventListener('focusin', this.handleFocusIn);
93
179
  this.addEventListener('keydown', this.handleMarkerKeydown);
94
180
  this.addEventListener('keyup', this.handleMarkerKeyup);
181
+ this.hiding = new MutationObserver(() => this.requestUpdate());
182
+ this.hiding.observe(this, { attributeFilter: ['hidden'], attributes: true, subtree: true });
95
183
  }
96
184
  disconnectedCallback() {
97
185
  super.disconnectedCallback();
186
+ this.hiding?.disconnect();
187
+ document.removeEventListener('pointerdown', this.handleOutside);
98
188
  this.removeEventListener(HelixMapPartChangeEvent.eventName, this.handlePartChange);
99
189
  this.removeEventListener('click', this.handleClick);
100
190
  this.removeEventListener('focusin', this.handleFocusIn);
@@ -103,6 +193,23 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
103
193
  }
104
194
  updated(changed) {
105
195
  super.updated(changed);
196
+ const photographed = this.mapType !== undefined;
197
+ for (const layer of this.imagery) {
198
+ if (layer.hidden === photographed) {
199
+ layer.hidden = !photographed;
200
+ }
201
+ }
202
+ if (changed.has('mapType')) {
203
+ this.dispatchEvent(new HelixMapPartChangeEvent({ kind: 'layer' }));
204
+ }
205
+ if (changed.has('layersOpen')) {
206
+ if (this.layersOpen) {
207
+ document.addEventListener('pointerdown', this.handleOutside);
208
+ }
209
+ else {
210
+ document.removeEventListener('pointerdown', this.handleOutside);
211
+ }
212
+ }
106
213
  const markers = this.markers;
107
214
  const on = markers[Math.min(this.stop, markers.length - 1)];
108
215
  const stop = on?.gatheredBy ?? on;
@@ -113,6 +220,208 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
113
220
  this.dispatchEvent(new HelixMapPartChangeEvent({ kind: 'place' }));
114
221
  }
115
222
  }
223
+ rotate(by) {
224
+ this.dispatchEvent(new HelixMapRotateEvent({ by }));
225
+ }
226
+ faceNorth() {
227
+ this.dispatchEvent(new HelixMapRotateEvent({ to: 0 }));
228
+ }
229
+ tilt(by) {
230
+ this.dispatchEvent(new HelixMapTiltEvent({ by }));
231
+ }
232
+ tiltTo(to) {
233
+ this.dispatchEvent(new HelixMapTiltEvent({ to }));
234
+ }
235
+ renderLayersMenu() {
236
+ const layers = this.layers;
237
+ if (!this.drawsControls('layers') || layers.length === 0) {
238
+ return nothing;
239
+ }
240
+ const entries = this.layerEntries;
241
+ return html `<button
242
+ part="layers-toggle"
243
+ aria-controls="layers-menu"
244
+ aria-expanded=${this.layersOpen ? 'true' : 'false'}
245
+ aria-label=${this.layersLabel}
246
+ type="button"
247
+ @click=${() => {
248
+ this.layersOpen = !this.layersOpen;
249
+ if (this.layersOpen) {
250
+ this.dispatchEvent(new HelixMapPartChangeEvent({ kind: 'menu' }));
251
+ }
252
+ }}
253
+ @keydown=${this.handleMenuKeydown}
254
+ >
255
+ <svg aria-hidden="true" fill="currentColor" height="16" viewBox=${stack.viewBox} width="16">
256
+ ${unsafeSVG(stack.content)}
257
+ </svg>
258
+ </button>
259
+ <div
260
+ part="layers-menu"
261
+ id="layers-menu"
262
+ role="group"
263
+ aria-label=${this.layersLabel}
264
+ ?hidden=${!this.layersOpen}
265
+ @keydown=${this.handleMenuKeydown}
266
+ >
267
+ ${this.imagery.length > 0 ? this.renderMapTypes() : nothing}
268
+ ${entries.length > 0
269
+ ? html `<div part="layer-choices">
270
+ ${entries.map((entry) => {
271
+ const shown = entry.some((layer) => !layer.hidden);
272
+ return html `<button
273
+ part="layer-choice"
274
+ aria-pressed=${shown ? 'true' : 'false'}
275
+ type="button"
276
+ @click=${() => this.showLayers(entry, !shown)}
277
+ >
278
+ <svg part="layer-icon" aria-hidden="true" fill="currentColor" viewBox=${iconOf(entry[0]).viewBox}>
279
+ ${unsafeSVG(iconOf(entry[0]).content)}
280
+ </svg>
281
+ <span part="layer-name">${entry[0]?.label ?? ''}</span>
282
+ </button>`;
283
+ })}
284
+ </div>`
285
+ : nothing}
286
+ </div>`;
287
+ }
288
+ renderMapTypes() {
289
+ const chosen = this.mapType ?? 'standard';
290
+ return html `<div part="map-types" role="radiogroup" aria-label=${this.mapTypeLabel}>
291
+ ${MAP_TYPES.map((type) => {
292
+ const preview = this.mapPreviews[type];
293
+ return html `<label part="map-type">
294
+ <input
295
+ type="radio"
296
+ name="map-type"
297
+ .checked=${chosen === type}
298
+ @change=${() => {
299
+ this.mapType = type === 'standard' ? undefined : type;
300
+ }}
301
+ />
302
+ ${preview
303
+ ? html `<img part="map-type-preview" alt="" src=${preview} />`
304
+ : html `<span part="map-type-preview"></span>`}
305
+ <span part="map-type-name">${this.nameOf(type)}</span>
306
+ </label>`;
307
+ })}
308
+ </div>`;
309
+ }
310
+ renderCompass(pan, rotate) {
311
+ return html `<div part="compass">
312
+ ${rotate
313
+ ? html `<button part="rotate-left" aria-label=${this.rotateLeftLabel} type="button" @click=${() => this.rotate(-ROTATE_STEP)}>
314
+ ↺
315
+ </button>`
316
+ : nothing}
317
+ ${pan
318
+ ? html `<button part="pan-up" aria-label=${this.panLabel('up')} type="button" @click=${() => this.pan('up')}>
319
+ ${this.panGlyph('up')}
320
+ </button>`
321
+ : nothing}
322
+ ${rotate
323
+ ? html `<button part="rotate-right" aria-label=${this.rotateRightLabel} type="button" @click=${() => this.rotate(ROTATE_STEP)}>
324
+ ↻
325
+ </button>`
326
+ : nothing}
327
+ ${pan
328
+ ? html `<button part="pan-start" aria-label=${this.panLabel('start')} type="button" @click=${() => this.pan('start')}>
329
+ ${this.panGlyph('start')}
330
+ </button>`
331
+ : nothing}
332
+ <button part="face-north" aria-label=${this.faceNorthLabel} type="button" style=${`--map-needle-turn: ${-this.bearing}deg`} @click=${() => this.faceNorth()}>
333
+ <svg part="needle" aria-hidden="true" viewBox="0 0 16 16">
334
+ <path data-end="north" d="M8 1.5 10.5 8h-5Z" />
335
+ <path data-end="south" d="M8 14.5 5.5 8h5Z" />
336
+ </svg>
337
+ </button>
338
+ ${pan
339
+ ? html `<button part="pan-end" aria-label=${this.panLabel('end')} type="button" @click=${() => this.pan('end')}>
340
+ ${this.panGlyph('end')}
341
+ </button>`
342
+ : nothing}
343
+ ${pan
344
+ ? html `<button part="pan-down" aria-label=${this.panLabel('down')} type="button" @click=${() => this.pan('down')}>
345
+ ${this.panGlyph('down')}
346
+ </button>`
347
+ : nothing}
348
+ </div>`;
349
+ }
350
+ renderControls() {
351
+ const pan = this.drawsControls('pan');
352
+ const zoom = this.drawsControls('zoom');
353
+ const rotate = this.drawsControls('rotate');
354
+ const tilt = this.drawsControls('tilt');
355
+ const fullscreen = this.drawsControls('fullscreen');
356
+ const menu = this.renderLayersMenu();
357
+ if (!pan && !zoom && !rotate && !tilt && !fullscreen && menu === nothing) {
358
+ return nothing;
359
+ }
360
+ return html `<div part="controls" role="group" aria-label=${this.controlsLabel ?? this.restingControlsLabel}>
361
+ ${fullscreen
362
+ ? html `<button
363
+ part="fullscreen"
364
+ aria-label=${this.fullscreenLabel}
365
+ aria-pressed=${this.filled ? 'true' : 'false'}
366
+ type="button"
367
+ @click=${this.toggleFullscreen}
368
+ >
369
+ ⤢
370
+ </button>`
371
+ : nothing}
372
+ ${menu}
373
+ ${tilt
374
+ ? html `<button
375
+ part="tilt"
376
+ aria-label=${this.tiltLabel}
377
+ aria-pressed=${this.pitch > 0 ? 'true' : 'false'}
378
+ type="button"
379
+ @click=${() => this.tiltTo(this.pitch > 0 ? 0 : TILTED)}
380
+ >
381
+ 3D
382
+ </button>`
383
+ : nothing}
384
+ ${zoom
385
+ ? html `<button part="zoom-in" aria-label=${this.zoomInLabel} type="button" @click=${() => this.zoom(1)}>
386
+ +
387
+ </button>
388
+ <button part="zoom-out" aria-label=${this.zoomOutLabel} type="button" @click=${() => this.zoom(-1)}>
389
+ −
390
+ </button>`
391
+ : nothing}
392
+ ${this.drawsCompass ? this.renderCompass(pan, rotate) : nothing}
393
+ </div>`;
394
+ }
395
+ get restingControls() {
396
+ return 'zoom compass fullscreen';
397
+ }
398
+ get drawsCompass() {
399
+ return ['compass', 'pan', 'rotate'].some((group) => this.drawsControls(group));
400
+ }
401
+ get keyShortcuts() {
402
+ const keys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Plus', 'Minus'];
403
+ if (this.drawsCompass) {
404
+ keys.push('Shift+ArrowLeft', 'Shift+ArrowRight');
405
+ }
406
+ if (this.drawsControls('tilt')) {
407
+ keys.push('Shift+ArrowUp', 'Shift+ArrowDown');
408
+ }
409
+ return keys.join(' ');
410
+ }
411
+ handleMoreKeys(event) {
412
+ if (!event.shiftKey) {
413
+ return false;
414
+ }
415
+ if (this.drawsCompass && (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {
416
+ this.rotate(event.key === 'ArrowLeft' ? -ROTATE_STEP : ROTATE_STEP);
417
+ return true;
418
+ }
419
+ if (this.drawsControls('tilt') && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {
420
+ this.tilt(event.key === 'ArrowUp' ? TILT_STEP : -TILT_STEP);
421
+ return true;
422
+ }
423
+ return false;
424
+ }
116
425
  panEvent(detail) {
117
426
  return new HelixMapPanEvent(detail);
118
427
  }
@@ -129,7 +438,7 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
129
438
  this.toggleState('idle', this.resting);
130
439
  }
131
440
  renderLayers() {
132
- const layers = this.layers;
441
+ const layers = this.layers.filter((layer) => !layer.hidden);
133
442
  if (layers.length === 0) {
134
443
  return nothing;
135
444
  }
@@ -142,7 +451,7 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
142
451
  part="region"
143
452
  role="group"
144
453
  aria-label=${this.label || 'Map'}
145
- aria-keyshortcuts="ArrowUp ArrowDown ArrowLeft ArrowRight Plus Minus"
454
+ aria-keyshortcuts=${this.keyShortcuts}
146
455
  tabindex="0"
147
456
  @focusin=${this.idle.stir}
148
457
  @keydown=${this.handleKeydown}
@@ -166,15 +475,54 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
166
475
  </div>`;
167
476
  }
168
477
  };
478
+ __decorate([
479
+ property({ type: Number })
480
+ ], HelixHeadlessMap.prototype, "bearing", void 0);
169
481
  __decorate([
170
482
  property({ type: Boolean })
171
483
  ], HelixHeadlessMap.prototype, "cluster", void 0);
484
+ __decorate([
485
+ property({ attribute: 'face-north-label' })
486
+ ], HelixHeadlessMap.prototype, "faceNorthLabel", void 0);
487
+ __decorate([
488
+ property({ attribute: 'hybrid-label' })
489
+ ], HelixHeadlessMap.prototype, "hybridLabel", void 0);
172
490
  __decorate([
173
491
  property()
174
492
  ], HelixHeadlessMap.prototype, "label", void 0);
175
493
  __decorate([
176
494
  property({ attribute: 'layers-label' })
177
495
  ], HelixHeadlessMap.prototype, "layersLabel", void 0);
496
+ __decorate([
497
+ state()
498
+ ], HelixHeadlessMap.prototype, "mapPreviews", void 0);
499
+ __decorate([
500
+ property({ attribute: 'map-type', reflect: true })
501
+ ], HelixHeadlessMap.prototype, "mapType", void 0);
502
+ __decorate([
503
+ property({ attribute: 'map-type-label' })
504
+ ], HelixHeadlessMap.prototype, "mapTypeLabel", void 0);
505
+ __decorate([
506
+ property({ type: Number })
507
+ ], HelixHeadlessMap.prototype, "pitch", void 0);
508
+ __decorate([
509
+ property({ attribute: 'rotate-left-label' })
510
+ ], HelixHeadlessMap.prototype, "rotateLeftLabel", void 0);
511
+ __decorate([
512
+ property({ attribute: 'rotate-right-label' })
513
+ ], HelixHeadlessMap.prototype, "rotateRightLabel", void 0);
514
+ __decorate([
515
+ property({ attribute: 'satellite-label' })
516
+ ], HelixHeadlessMap.prototype, "satelliteLabel", void 0);
517
+ __decorate([
518
+ property({ attribute: 'standard-label' })
519
+ ], HelixHeadlessMap.prototype, "standardLabel", void 0);
520
+ __decorate([
521
+ property({ attribute: 'tilt-label' })
522
+ ], HelixHeadlessMap.prototype, "tiltLabel", void 0);
523
+ __decorate([
524
+ state()
525
+ ], HelixHeadlessMap.prototype, "layersOpen", void 0);
178
526
  __decorate([
179
527
  state()
180
528
  ], HelixHeadlessMap.prototype, "stop", void 0);
@@ -39,6 +39,12 @@ export declare class HelixHeadlessMapRoute extends HelixElement {
39
39
  * in the frame's list.
40
40
  */
41
41
  description?: string;
42
+ /**
43
+ * A name this layer shares with other layers, such as a route and its
44
+ * dotted legs. The layers menu shows layers in the same group as one entry,
45
+ * named by the first of them, and its checkbox shows or hides them all.
46
+ */
47
+ group?: string;
42
48
  /** Marks this as a layer for the frame and the connector, whatever its tag. */
43
49
  readonly isMapLayer = true;
44
50
  /** @internal Which kind of layer, which is how the connector draws it. */
@@ -34,6 +34,9 @@ let HelixHeadlessMapRoute = class HelixHeadlessMapRoute extends HelixElement {
34
34
  __decorate([
35
35
  property()
36
36
  ], HelixHeadlessMapRoute.prototype, "description", void 0);
37
+ __decorate([
38
+ property()
39
+ ], HelixHeadlessMapRoute.prototype, "group", void 0);
37
40
  __decorate([
38
41
  property()
39
42
  ], HelixHeadlessMapRoute.prototype, "label", void 0);
@@ -0,0 +1,68 @@
1
+ import { HelixElement } from '@fusion.dev/helix-core';
2
+ import { nothing, type PropertyValues } from 'lit';
3
+ /** How an elevation tile stores its heights in its colors. */
4
+ export type MapTerrainEncoding = 'mapbox' | 'terrarium';
5
+ /**
6
+ * @summary Hills and mountains on a map, shaded and raised in 3D.
7
+ *
8
+ * @description
9
+ * `connectMap` shades the land by its slopes, from elevation tiles, so hills
10
+ * and valleys show on a flat map. Set `raised` to raise the ground to its real
11
+ * height as well, and tilt the map to see it. Routes, areas, and buildings lie
12
+ * on the raised ground.
13
+ *
14
+ * Set `src` to an elevation tile URL with `{z}`, `{x}`, and `{y}` in it, and
15
+ * `encoding` to how its tiles store heights: `terrarium`, the default, or
16
+ * `mapbox`. Set `max-zoom` to the deepest zoom the provider has tiles for.
17
+ * Put the provider's credit in `attribution`.
18
+ *
19
+ * MapLibre draws the terrain. Leaflet draws maps flat, so a Leaflet map shows
20
+ * none. The frame lists the layer by its `label` for screen readers.
21
+ *
22
+ * @since 0.105.0
23
+ * @status experimental
24
+ * @category media
25
+ * @aliases Terrain, Hillshade, Elevation, Relief
26
+ * @documentation https://fusion.dev/helix/components/map
27
+ *
28
+ * @event {HelixMapPartChangeEvent} helix-map-part-change - The tiles, how the ground is raised, or the layer's name or colors changed. Used by `connectMap`; pages do not need to listen for it.
29
+ */
30
+ export declare class HelixHeadlessMapTerrain extends HelixElement {
31
+ /** The elevation provider's credit, shown in the frame's footer. Links in it stay links. */
32
+ attribution?: string;
33
+ /** More about the terrain. Read after the label in the frame's list. */
34
+ description?: string;
35
+ /** How the tiles store heights in their colors: `terrarium` or `mapbox`. */
36
+ encoding: MapTerrainEncoding;
37
+ /** How many times its real height the ground is raised, where `raised` is set. */
38
+ exaggeration: number;
39
+ /**
40
+ * A name this layer shares with other layers, such as a route and its
41
+ * dotted legs. The layers menu shows layers in the same group as one entry,
42
+ * named by the first of them, and its checkbox shows or hides them all.
43
+ */
44
+ group?: string;
45
+ /** Marks this as a layer for the frame and the connector, whatever its tag. */
46
+ readonly isMapLayer = true;
47
+ /** @internal Which kind of layer, which is how the connector draws it. */
48
+ readonly layerKind: 'terrain';
49
+ /** The layer's name in the frame's list. */
50
+ label: string;
51
+ /**
52
+ * The deepest zoom the provider has tiles for. The map enlarges those tiles
53
+ * at deeper zooms, where it would otherwise ask for tiles that do not exist.
54
+ */
55
+ maxZoom?: number;
56
+ /** Raises the ground to its real height in 3D. Tilt the map to see it. */
57
+ raised: boolean;
58
+ /** One elevation tile URL with `{z}`, `{x}`, and `{y}` in it. */
59
+ src?: string;
60
+ /** Tells the frame and the connector the layer changed. */
61
+ protected updated(changed: PropertyValues): void;
62
+ protected render(): typeof nothing;
63
+ }
64
+ declare global {
65
+ interface HTMLElementTagNameMap {
66
+ 'helix-headless-map-terrain': HelixHeadlessMapTerrain;
67
+ }
68
+ }
@@ -0,0 +1,58 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { customElement, HelixElement, HelixMapPartChangeEvent } from '@fusion.dev/helix-core';
8
+ import { nothing } from 'lit';
9
+ import { property } from 'lit/decorators.js';
10
+ let HelixHeadlessMapTerrain = class HelixHeadlessMapTerrain extends HelixElement {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.encoding = 'terrarium';
14
+ this.exaggeration = 1;
15
+ this.isMapLayer = true;
16
+ this.layerKind = 'terrain';
17
+ this.label = 'Terrain';
18
+ this.raised = false;
19
+ }
20
+ updated(changed) {
21
+ super.updated(changed);
22
+ this.dispatchEvent(new HelixMapPartChangeEvent({ kind: 'layer' }));
23
+ }
24
+ render() {
25
+ return nothing;
26
+ }
27
+ };
28
+ __decorate([
29
+ property()
30
+ ], HelixHeadlessMapTerrain.prototype, "attribution", void 0);
31
+ __decorate([
32
+ property()
33
+ ], HelixHeadlessMapTerrain.prototype, "description", void 0);
34
+ __decorate([
35
+ property()
36
+ ], HelixHeadlessMapTerrain.prototype, "encoding", void 0);
37
+ __decorate([
38
+ property({ type: Number })
39
+ ], HelixHeadlessMapTerrain.prototype, "exaggeration", void 0);
40
+ __decorate([
41
+ property()
42
+ ], HelixHeadlessMapTerrain.prototype, "group", void 0);
43
+ __decorate([
44
+ property()
45
+ ], HelixHeadlessMapTerrain.prototype, "label", void 0);
46
+ __decorate([
47
+ property({ attribute: 'max-zoom', type: Number })
48
+ ], HelixHeadlessMapTerrain.prototype, "maxZoom", void 0);
49
+ __decorate([
50
+ property({ type: Boolean })
51
+ ], HelixHeadlessMapTerrain.prototype, "raised", void 0);
52
+ __decorate([
53
+ property()
54
+ ], HelixHeadlessMapTerrain.prototype, "src", void 0);
55
+ HelixHeadlessMapTerrain = __decorate([
56
+ customElement('helix-headless-map-terrain')
57
+ ], HelixHeadlessMapTerrain);
58
+ export { HelixHeadlessMapTerrain };
@@ -2,23 +2,23 @@ import { HelixElement, PopoverController } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessMegamenu_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & typeof HelixElement;
4
4
  /**
5
- * @summary A section of a navigation that opens a panel of destinations.
5
+ * @summary A section of a navigation with a trigger that opens a panel of links.
6
6
  *
7
7
  * @description
8
- * **A disclosure, not a menu, and that is the whole design.** `role="menu"` and
9
- * `menuitem` are for an application's commands: they take over the arrow keys,
10
- * announce "menu" to a reader who asked for navigation, and put every link
11
- * inside a role that is not a link. This is a button that shows and hides a
12
- * region of the consumer's own anchors, which leaves a middle click, a modified
13
- * click and the status bar working. `Menu` remains right for a row of commands.
8
+ * A disclosure: a button that shows and hides a region of your own links. It
9
+ * does not use `role="menu"` or `menuitem`, which are for application commands.
10
+ * Those roles take over the arrow keys, announce "menu" to someone looking for
11
+ * navigation, and put every link inside a role that is not a link. As a
12
+ * disclosure, middle clicks, modified clicks, and the status bar keep working.
13
+ * Use `Menu` for a row of commands.
14
14
  *
15
- * **It renders no links.** A router renders its own anchor and cannot render
16
- * one inside this shadow root, so the panel is a slot and what goes in it is
17
- * the lists and headings the consumer wrote.
15
+ * It renders no links. A router renders its own anchors and cannot render them
16
+ * inside this shadow root, so the panel is a slot for the lists and headings
17
+ * you write.
18
18
  *
19
- * **It opens on hover, and a press is always the fallback.** `open-on` says
20
- * which, and hover is the resting value because a nav bar is where a reader
21
- * expects to sweep along a row and see each section.
19
+ * It opens on hover by default, and a press always opens it too. `open-on` sets
20
+ * which. Hover is the default because in a navigation bar people expect to move
21
+ * along the row and see each section.
22
22
  *
23
23
  * @since 0.1.0
24
24
  * @status stable
@@ -26,24 +26,25 @@ declare const HelixHeadlessMegamenu_base: (new (...args: any[]) => import("@fusi
26
26
  * @aliases Mega menu, Flyout, Nav panel
27
27
  * @documentation https://fusion.dev/helix/components/megamenu
28
28
  *
29
- * @slot - The panel's contents: the consumer's own lists and headings.
30
- * @slot trigger - The control that opens it. Falls back to a button named by `label`.
29
+ * @slot - The panel's contents, such as your own lists of links and their headings.
30
+ * @slot trigger - The control that opens the panel. When it is empty, a button named by `label` is shown.
31
31
  *
32
- * @event {HelixBeforeCloseEvent} helix-before-close - Fired before it closes, and cancelable.
33
- * @event {HelixBeforeOpenEvent} helix-before-open - Fired before it opens, and cancelable.
34
- * @event {Event} toggle - Says the state moved, carrying `newState` and `oldState`.
32
+ * @event {HelixBeforeCloseEvent} helix-before-close - The panel is about to close. Cancelable.
33
+ * @event {HelixBeforeOpenEvent} helix-before-open - The panel is about to open. Cancelable.
34
+ * @event {Event} toggle - The panel opened or closed. Carries `newState` and `oldState`.
35
35
  *
36
- * @csspart surface - The floating panel, which is what opens.
37
- * @csspart trigger - The default trigger, where none was slotted.
36
+ * @csspart surface - The floating panel that opens.
37
+ * @csspart trigger - The default trigger button, shown when the `trigger` slot is empty.
38
38
  *
39
39
  * @cssproperty --megamenu-top - Where the panel starts, measured from the bar above it.
40
40
  *
41
- * @cssstate narrow - While the page is under `band-below`, so the panel is a band whether or not one was asked for.
42
- * @cssstate open - While the panel is open, which is when the trigger reads as current.
41
+ * @cssstate narrow - The page is narrower than `band-below`, so the panel is shown as a band whatever its variant.
42
+ * @cssstate open - The panel is open, and the trigger is shown as current.
43
43
  */
44
44
  export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
45
45
  /**
46
- * The width, in pixels, under which a card becomes a band. Zero never does.
46
+ * The page width, in pixels, below which a card panel is shown as a band. At
47
+ * zero, it never is.
47
48
  *
48
49
  * A card is a panel hung off one word, and there is no room to hang anything
49
50
  * off a word on a phone: the columns do not shrink past
@@ -69,11 +70,12 @@ export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
69
70
  */
70
71
  bandBelow: number;
71
72
  /**
72
- * The section's name, which names the default trigger and the panel.
73
+ * The section's name, used for the default trigger and the panel.
73
74
  */
74
75
  label: string;
75
76
  /**
76
- * Whether hovering the trigger opens the panel, or only a press does.
77
+ * Whether hovering over the trigger opens the panel (`hover`), or only a press
78
+ * does (`click`).
77
79
  *
78
80
  * A press always works. This says whether a mouse also opens it by resting on
79
81
  * the trigger, and it is the default because that is what a navigation bar