@fusion.dev/helix-headless 0.101.0 → 0.103.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/types/jsx.d.ts CHANGED
@@ -81,6 +81,7 @@ import type {
81
81
  HelixHeadlessListItem,
82
82
  HelixHeadlessListbox,
83
83
  HelixHeadlessLoader,
84
+ HelixHeadlessMap,
84
85
  HelixHeadlessMegamenu,
85
86
  HelixHeadlessMenu,
86
87
  HelixHeadlessMenuItem,
@@ -150,6 +151,8 @@ import type {
150
151
  HelixHeadlessVideoPlaylistMenu,
151
152
  HelixHeadlessVirtualList,
152
153
  HelixHistoryEvent,
154
+ HelixMapPanEvent,
155
+ HelixMapZoomEvent,
153
156
  HelixNavigateEvent,
154
157
  HelixNextEvent,
155
158
  HelixPreviousEvent,
@@ -9380,6 +9383,236 @@ export type HelixHeadlessLoaderSolidJsProps = {
9380
9383
  textContent?: (string | number) | undefined;
9381
9384
  };
9382
9385
 
9386
+ /** `HelixHeadlessMap` component event */
9387
+ export type HelixHeadlessMapElementEvent<E = Event> = TypedEvent<
9388
+ HelixHeadlessMap,
9389
+ E
9390
+ >;
9391
+ /** `helix-map-pan` event type */
9392
+ export type HelixHeadlessMapHelixMapPanElementEvent =
9393
+ HelixHeadlessMapElementEvent<HelixMapPanEvent>;
9394
+ /** `helix-map-zoom` event type */
9395
+ export type HelixHeadlessMapHelixMapZoomElementEvent =
9396
+ HelixHeadlessMapElementEvent<HelixMapZoomEvent>;
9397
+
9398
+ export type HelixHeadlessMapProps = {
9399
+ /** Which of the controls this frame draws, as a list of what to keep.
9400
+
9401
+ **A list rather than a switch, because the overlap is not symmetric.**
9402
+ Every map library draws zoom controls and none of them draws pan buttons:
9403
+ MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
9404
+ Google's is zoom. So a consumer slotting one of those has our zoom twice
9405
+ over and our pan pad not at all, and a single switch would make them choose
9406
+ between a duplicate and nothing.
9407
+
9408
+ `none` draws none of them, which is the right answer where the slotted map
9409
+ already has controls a reader can find: what this family argues for is that
9410
+ *a* findable control exists, never that it is ours. The methods stay public
9411
+ either way, so a consumer drawing their own chrome can still drive the
9412
+ frame.
9413
+
9414
+ Absent is all three, which is this library's rule that a resting value is an
9415
+ attribute's absence, and it is what the stylesheet asks about: the layout
9416
+ rules are written against `[controls]:not([controls~="zoom"])` rather than
9417
+ the bare negation, or a frame that named no list at all would be laid out as
9418
+ though it had dropped everything. */
9419
+ controls?: (HelixHeadlessMap["controls"]) | undefined;
9420
+ /** Which corner the controls sit in.
9421
+
9422
+ **Configurable because there is no safe default**, and this is a collision
9423
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
9424
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
9425
+ corner this took would land on somebody's, which is why every one of those
9426
+ libraries made it a setting too.
9427
+
9428
+ Logical corners rather than left and right, so a right-to-left page moves
9429
+ them without a consumer writing a second rule.
9430
+
9431
+ Absent is the top end, which is this library's rule that a resting value is
9432
+ an attribute's absence: a default that reflected would write an attribute
9433
+ onto every host that no server sent and nobody asked for. */
9434
+ "controls-placement"?: (HelixHeadlessMap["controlsPlacement"]) | undefined;
9435
+ /** Which corner the controls sit in.
9436
+
9437
+ **Configurable because there is no safe default**, and this is a collision
9438
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
9439
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
9440
+ corner this took would land on somebody's, which is why every one of those
9441
+ libraries made it a setting too.
9442
+
9443
+ Logical corners rather than left and right, so a right-to-left page moves
9444
+ them without a consumer writing a second rule.
9445
+
9446
+ Absent is the top end, which is this library's rule that a resting value is
9447
+ an attribute's absence: a default that reflected would write an attribute
9448
+ onto every host that no server sent and nobody asked for. */
9449
+ controlsPlacement?: (HelixHeadlessMap["controlsPlacement"]) | undefined;
9450
+ /** What the control that fills the screen is called. */
9451
+ "fullscreen-label"?: (HelixHeadlessMap["fullscreenLabel"]) | undefined;
9452
+ /** What the control that fills the screen is called. */
9453
+ fullscreenLabel?: (HelixHeadlessMap["fullscreenLabel"]) | undefined;
9454
+ /** How long the reader may be still before the chrome hides, in milliseconds.
9455
+
9456
+ Zero keeps it up, which is the default: a map's controls are how a keyboard
9457
+ reader operates it, and chrome that hides itself by default would be this
9458
+ component undoing its own argument. Set it for a display map nobody drives. */
9459
+ "idle-delay"?: (HelixHeadlessMap["idleDelay"] | `${number}`) | undefined;
9460
+ /** How long the reader may be still before the chrome hides, in milliseconds.
9461
+
9462
+ Zero keeps it up, which is the default: a map's controls are how a keyboard
9463
+ reader operates it, and chrome that hides itself by default would be this
9464
+ component undoing its own argument. Set it for a display map nobody drives. */
9465
+ idleDelay?: (HelixHeadlessMap["idleDelay"]) | undefined;
9466
+ /** Accessible name for the map, which is the one thing a consumer must write.
9467
+
9468
+ There is no sensible default. "Map" names the widget rather than the place,
9469
+ and a reader meeting three of them on a page learns nothing from hearing the
9470
+ same word three times. */
9471
+ label?: (HelixHeadlessMap["label"]) | undefined;
9472
+ /** What the controls are called, for a page not in English. */
9473
+ "pan-label"?: (HelixHeadlessMap["panLabel"]) | undefined;
9474
+ /** What the controls are called, for a page not in English. */
9475
+ panLabel?: (HelixHeadlessMap["panLabel"]) | undefined;
9476
+ /** How far one press moves the map, as a fraction of what is on screen.
9477
+
9478
+ A fraction rather than a distance, because this frame does not know the
9479
+ scale of what is inside it: a quarter of the viewport is the same gesture at
9480
+ street level and at country level, and a consumer who wants metres can
9481
+ multiply by their own. */
9482
+ "pan-step"?: (HelixHeadlessMap["panStep"] | `${number}`) | undefined;
9483
+ /** How far one press moves the map, as a fraction of what is on screen.
9484
+
9485
+ A fraction rather than a distance, because this frame does not know the
9486
+ scale of what is inside it: a quarter of the viewport is the same gesture at
9487
+ street level and at country level, and a consumer who wants metres can
9488
+ multiply by their own. */
9489
+ panStep?: (HelixHeadlessMap["panStep"]) | undefined;
9490
+ /** What the zoom controls are called. */
9491
+ "zoom-in-label"?: (HelixHeadlessMap["zoomInLabel"]) | undefined;
9492
+ /** What the zoom controls are called. */
9493
+ zoomInLabel?: (HelixHeadlessMap["zoomInLabel"]) | undefined;
9494
+ /** What the zoom control that goes the other way is called. */
9495
+ "zoom-out-label"?: (HelixHeadlessMap["zoomOutLabel"]) | undefined;
9496
+ /** What the zoom control that goes the other way is called. */
9497
+ zoomOutLabel?: (HelixHeadlessMap["zoomOutLabel"]) | undefined;
9498
+
9499
+ /** The reader asked the map to move. Answer it against your own map. */
9500
+ "onhelix-map-pan"?: ((e: HelixHeadlessMapHelixMapPanElementEvent) => void) | undefined;
9501
+ /** The reader asked the map to zoom, by a direction rather than to a level. */
9502
+ "onhelix-map-zoom"?: ((e: HelixHeadlessMapHelixMapZoomElementEvent) => void) | undefined;
9503
+ };
9504
+
9505
+ export type HelixHeadlessMapSolidJsProps = {
9506
+ /** Which of the controls this frame draws, as a list of what to keep.
9507
+
9508
+ **A list rather than a switch, because the overlap is not symmetric.**
9509
+ Every map library draws zoom controls and none of them draws pan buttons:
9510
+ MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
9511
+ Google's is zoom. So a consumer slotting one of those has our zoom twice
9512
+ over and our pan pad not at all, and a single switch would make them choose
9513
+ between a duplicate and nothing.
9514
+
9515
+ `none` draws none of them, which is the right answer where the slotted map
9516
+ already has controls a reader can find: what this family argues for is that
9517
+ *a* findable control exists, never that it is ours. The methods stay public
9518
+ either way, so a consumer drawing their own chrome can still drive the
9519
+ frame.
9520
+
9521
+ Absent is all three, which is this library's rule that a resting value is an
9522
+ attribute's absence, and it is what the stylesheet asks about: the layout
9523
+ rules are written against `[controls]:not([controls~="zoom"])` rather than
9524
+ the bare negation, or a frame that named no list at all would be laid out as
9525
+ though it had dropped everything. */
9526
+ "prop:controls"?: (HelixHeadlessMap["controls"]) | undefined;
9527
+ /** Which corner the controls sit in.
9528
+
9529
+ **Configurable because there is no safe default**, and this is a collision
9530
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
9531
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
9532
+ corner this took would land on somebody's, which is why every one of those
9533
+ libraries made it a setting too.
9534
+
9535
+ Logical corners rather than left and right, so a right-to-left page moves
9536
+ them without a consumer writing a second rule.
9537
+
9538
+ Absent is the top end, which is this library's rule that a resting value is
9539
+ an attribute's absence: a default that reflected would write an attribute
9540
+ onto every host that no server sent and nobody asked for. */
9541
+ "attr:controls-placement"?: (HelixHeadlessMap["controlsPlacement"]) | undefined;
9542
+ /** Which corner the controls sit in.
9543
+
9544
+ **Configurable because there is no safe default**, and this is a collision
9545
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
9546
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
9547
+ corner this took would land on somebody's, which is why every one of those
9548
+ libraries made it a setting too.
9549
+
9550
+ Logical corners rather than left and right, so a right-to-left page moves
9551
+ them without a consumer writing a second rule.
9552
+
9553
+ Absent is the top end, which is this library's rule that a resting value is
9554
+ an attribute's absence: a default that reflected would write an attribute
9555
+ onto every host that no server sent and nobody asked for. */
9556
+ "prop:controlsPlacement"?: (HelixHeadlessMap["controlsPlacement"]) | undefined;
9557
+ /** What the control that fills the screen is called. */
9558
+ "attr:fullscreen-label"?: (HelixHeadlessMap["fullscreenLabel"]) | undefined;
9559
+ /** What the control that fills the screen is called. */
9560
+ "prop:fullscreenLabel"?: (HelixHeadlessMap["fullscreenLabel"]) | undefined;
9561
+ /** How long the reader may be still before the chrome hides, in milliseconds.
9562
+
9563
+ Zero keeps it up, which is the default: a map's controls are how a keyboard
9564
+ reader operates it, and chrome that hides itself by default would be this
9565
+ component undoing its own argument. Set it for a display map nobody drives. */
9566
+ "attr:idle-delay"?: (HelixHeadlessMap["idleDelay"] | `${number}`) | undefined;
9567
+ /** How long the reader may be still before the chrome hides, in milliseconds.
9568
+
9569
+ Zero keeps it up, which is the default: a map's controls are how a keyboard
9570
+ reader operates it, and chrome that hides itself by default would be this
9571
+ component undoing its own argument. Set it for a display map nobody drives. */
9572
+ "prop:idleDelay"?: (HelixHeadlessMap["idleDelay"]) | undefined;
9573
+ /** Accessible name for the map, which is the one thing a consumer must write.
9574
+
9575
+ There is no sensible default. "Map" names the widget rather than the place,
9576
+ and a reader meeting three of them on a page learns nothing from hearing the
9577
+ same word three times. */
9578
+ "prop:label"?: (HelixHeadlessMap["label"]) | undefined;
9579
+ /** What the controls are called, for a page not in English. */
9580
+ "attr:pan-label"?: (HelixHeadlessMap["panLabel"]) | undefined;
9581
+ /** What the controls are called, for a page not in English. */
9582
+ "prop:panLabel"?: (HelixHeadlessMap["panLabel"]) | undefined;
9583
+ /** How far one press moves the map, as a fraction of what is on screen.
9584
+
9585
+ A fraction rather than a distance, because this frame does not know the
9586
+ scale of what is inside it: a quarter of the viewport is the same gesture at
9587
+ street level and at country level, and a consumer who wants metres can
9588
+ multiply by their own. */
9589
+ "attr:pan-step"?: (HelixHeadlessMap["panStep"] | `${number}`) | undefined;
9590
+ /** How far one press moves the map, as a fraction of what is on screen.
9591
+
9592
+ A fraction rather than a distance, because this frame does not know the
9593
+ scale of what is inside it: a quarter of the viewport is the same gesture at
9594
+ street level and at country level, and a consumer who wants metres can
9595
+ multiply by their own. */
9596
+ "prop:panStep"?: (HelixHeadlessMap["panStep"]) | undefined;
9597
+ /** What the zoom controls are called. */
9598
+ "attr:zoom-in-label"?: (HelixHeadlessMap["zoomInLabel"]) | undefined;
9599
+ /** What the zoom controls are called. */
9600
+ "prop:zoomInLabel"?: (HelixHeadlessMap["zoomInLabel"]) | undefined;
9601
+ /** What the zoom control that goes the other way is called. */
9602
+ "attr:zoom-out-label"?: (HelixHeadlessMap["zoomOutLabel"]) | undefined;
9603
+ /** What the zoom control that goes the other way is called. */
9604
+ "prop:zoomOutLabel"?: (HelixHeadlessMap["zoomOutLabel"]) | undefined;
9605
+ /** The reader asked the map to move. Answer it against your own map. */
9606
+ "on:helix-map-pan"?: ((e: HelixHeadlessMapHelixMapPanElementEvent) => void) | undefined;
9607
+ /** The reader asked the map to zoom, by a direction rather than to a level. */
9608
+ "on:helix-map-zoom"?: ((e: HelixHeadlessMapHelixMapZoomElementEvent) => void) | undefined;
9609
+
9610
+ /** Set the innerHTML of the element */
9611
+ innerHTML?: (string) | undefined;
9612
+ /** Set the textContent of the element */
9613
+ textContent?: (string | number) | undefined;
9614
+ };
9615
+
9383
9616
  /** `HelixHeadlessMegamenu` component event */
9384
9617
  export type HelixHeadlessMegamenuElementEvent<E = Event> = TypedEvent<
9385
9618
  HelixHeadlessMegamenu,
@@ -27354,6 +27587,161 @@ export type CustomElements = {
27354
27587
  HelixHeadlessLoaderProps & BaseProps<HelixHeadlessLoader> & BaseEvents<HelixHeadlessLoader>
27355
27588
  >;
27356
27589
 
27590
+ /**
27591
+ * **Helix draws no map.** There are no tiles here, no projection and no
27592
+ * network, and there should not be: a tile renderer is a library, and what a
27593
+ * design system can add to MapLibre or Leaflet is the frame. The consumer slots
27594
+ * their map and this owns the box, the name, the controls and the way out,
27595
+ * which is the shape `VideoPlaylist` uses for a player it never renders.
27596
+ *
27597
+ * **The accessibility argument is the reason this exists**, and it was measured
27598
+ * rather than assumed: a map embedded the ordinary way is a canvas with no role
27599
+ * and no name, and it has *no node at all* in the accessibility tree. A reader
27600
+ * using a screen reader does not walk past it so much as never meet it. A named
27601
+ * region with controls in it is the whole of the difference.
27602
+ *
27603
+ * **The controls are buttons, and that is a deliberate choice against arrow
27604
+ * keys.** Arrows work here too, but what a screen reader does with them is not
27605
+ * ours to decide: macOS passes them through, Windows readers hold them for
27606
+ * their own reading mode unless a page takes `role="application"`, which costs
27607
+ * the reader their normal way of reading everything else in the frame. A button
27608
+ * is findable and operable in every screen reader on every platform without
27609
+ * that bargain, so panning and zooming are buttons first and keys second.
27610
+ *
27611
+ * **Nothing here moves the map.** Both controls ask, through `helix-map-pan`
27612
+ * and `helix-map-zoom`, and the consumer answers against whatever they slotted.
27613
+ * A frame that moved the map would have to know whose map it was.
27614
+ *
27615
+ * ## Attributes & Properties
27616
+ *
27617
+ * Component attributes and properties that can be applied to the element or by using JavaScript.
27618
+ *
27619
+ * - `controls`: Which of the controls this frame draws, as a list of what to keep.
27620
+ *
27621
+ * **A list rather than a switch, because the overlap is not symmetric.**
27622
+ * Every map library draws zoom controls and none of them draws pan buttons:
27623
+ * MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
27624
+ * Google's is zoom. So a consumer slotting one of those has our zoom twice
27625
+ * over and our pan pad not at all, and a single switch would make them choose
27626
+ * between a duplicate and nothing.
27627
+ *
27628
+ * `none` draws none of them, which is the right answer where the slotted map
27629
+ * already has controls a reader can find: what this family argues for is that
27630
+ * *a* findable control exists, never that it is ours. The methods stay public
27631
+ * either way, so a consumer drawing their own chrome can still drive the
27632
+ * frame.
27633
+ *
27634
+ * Absent is all three, which is this library's rule that a resting value is an
27635
+ * attribute's absence, and it is what the stylesheet asks about: the layout
27636
+ * rules are written against `[controls]:not([controls~="zoom"])` rather than
27637
+ * the bare negation, or a frame that named no list at all would be laid out as
27638
+ * though it had dropped everything.
27639
+ * - `controls-placement`/`controlsPlacement`: Which corner the controls sit in.
27640
+ *
27641
+ * **Configurable because there is no safe default**, and this is a collision
27642
+ * rather than a taste: MapLibre puts its own controls at the top end, Leaflet
27643
+ * and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
27644
+ * corner this took would land on somebody's, which is why every one of those
27645
+ * libraries made it a setting too.
27646
+ *
27647
+ * Logical corners rather than left and right, so a right-to-left page moves
27648
+ * them without a consumer writing a second rule.
27649
+ *
27650
+ * Absent is the top end, which is this library's rule that a resting value is
27651
+ * an attribute's absence: a default that reflected would write an attribute
27652
+ * onto every host that no server sent and nobody asked for.
27653
+ * - `fullscreen-label`/`fullscreenLabel`: What the control that fills the screen is called.
27654
+ * - `idle-delay`/`idleDelay`: How long the reader may be still before the chrome hides, in milliseconds.
27655
+ *
27656
+ * Zero keeps it up, which is the default: a map's controls are how a keyboard
27657
+ * reader operates it, and chrome that hides itself by default would be this
27658
+ * component undoing its own argument. Set it for a display map nobody drives.
27659
+ * - `label`: Accessible name for the map, which is the one thing a consumer must write.
27660
+ *
27661
+ * There is no sensible default. "Map" names the widget rather than the place,
27662
+ * and a reader meeting three of them on a page learns nothing from hearing the
27663
+ * same word three times.
27664
+ * - `pan-label`/`panLabel`: What the controls are called, for a page not in English.
27665
+ * - `pan-step`/`panStep`: How far one press moves the map, as a fraction of what is on screen.
27666
+ *
27667
+ * A fraction rather than a distance, because this frame does not know the
27668
+ * scale of what is inside it: a quarter of the viewport is the same gesture at
27669
+ * street level and at country level, and a consumer who wants metres can
27670
+ * multiply by their own.
27671
+ * - `zoom-in-label`/`zoomInLabel`: What the zoom controls are called.
27672
+ * - `zoom-out-label`/`zoomOutLabel`: What the zoom control that goes the other way is called.
27673
+ * - `whenSettled`: Resolves a frame after the first update, when transitions are switched on.
27674
+ *
27675
+ * **Named `whenSettled` because `settled` is taken four times over**, by
27676
+ * Image, Splitter and both color controls, none of them about transitions. A
27677
+ * base class takes the name every subclass then cannot use.
27678
+ *
27679
+ * **The state it reports cannot be watched, which is why this exists.** A
27680
+ * custom state is deliberately not in the DOM, so there is no
27681
+ * `MutationObserver` equivalent for `ElementInternals.states`. Await this
27682
+ * instead.
27683
+ *
27684
+ * Separate from `updateComplete`, which resolves in the microtask checkpoint
27685
+ * the suppression is still active in. That is the distinction `readyToMove`
27686
+ * in `@fusion.dev/helix-testing` is written around.
27687
+ *
27688
+ * It never resolves where `requestAnimationFrame` never fires, which is a
27689
+ * server, a hidden tab, and happy-dom. Callers that must not hang there race
27690
+ * it against a timeout, as the happy-dom harness's `readyToMove` does. The
27691
+ * browser harness's awaits it alone: a browser always runs the frame, and a
27692
+ * timer beside it was a bet on how long one takes, which a busy run lost. (property only) (readonly)
27693
+ *
27694
+ * ## Events
27695
+ *
27696
+ * Events that will be emitted by the component.
27697
+ *
27698
+ * - `helix-map-pan`: The reader asked the map to move. Answer it against your own map.
27699
+ * - `helix-map-zoom`: The reader asked the map to zoom, by a direction rather than to a level.
27700
+ *
27701
+ * ## Slots
27702
+ *
27703
+ * Areas where markup can be added to the component.
27704
+ *
27705
+ * - `(default)`: The map, which is the consumer's own.
27706
+ * - `attribution`: Whoever the tiles belong to, which most licenses require you to say.
27707
+ * - `footer`: Chrome below the map, such as a legend or a scale.
27708
+ * - `header`: Chrome above the map, such as a title or a search field.
27709
+ *
27710
+ * ## Methods
27711
+ *
27712
+ * Methods that can be called to access component functionality.
27713
+ *
27714
+ * - `toggleFullscreen() => void`: Fills the screen with the frame, or comes back.
27715
+ * - `pan(to: Way) => void`: Asks for the map to move, which the consumer answers.
27716
+ * - `zoom(by: number) => void`: Asks for the map to zoom, `1` in and `-1` out.
27717
+ *
27718
+ * ## CSS Parts
27719
+ *
27720
+ * Custom selectors for styling elements within the component.
27721
+ *
27722
+ * - `controls`: The group the pan and zoom buttons sit in.
27723
+ * - `fullscreen`: The button that fills the screen.
27724
+ * - `pan-down`: The button that moves the map down.
27725
+ * - `pan-end`: The button that moves the map the way the text ends, which is right on an English page.
27726
+ * - `pan-start`: The button that moves the map the way the text starts, which is left on an English page.
27727
+ * - `pan-up`: The button that moves the map up.
27728
+ * - `region`: The named region the map is slotted into.
27729
+ * - `viewport`: The box the map is drawn in.
27730
+ * - `zoom-in`: The button that zooms in.
27731
+ * - `zoom-out`: The button that zooms out.
27732
+ *
27733
+ * ## CSS States
27734
+ *
27735
+ * These can be used to apply styling when a component is in a given state.
27736
+ *
27737
+ * - `fullscreen`: While the frame fills the screen.
27738
+ * - `idle`: While the reader has been still long enough to hide the chrome.
27739
+ * - `settled`: Set a frame after the first render. Transitions are held off until it is, so an element never animates its own arrival.
27740
+ */
27741
+ "helix-headless-map": Partial<
27742
+ HelixHeadlessMapProps & BaseProps<HelixHeadlessMap> & BaseEvents<HelixHeadlessMap>
27743
+ >;
27744
+
27357
27745
  /**
27358
27746
  * **A disclosure, not a menu, and that is the whole design.** `role="menu"` and
27359
27747
  * `menuitem` are for an application's commands: they take over the arrow keys,
@@ -45701,6 +46089,164 @@ export type CustomElementsSolidJs = {
45701
46089
  BaseEvents<HelixHeadlessLoader>
45702
46090
  >;
45703
46091
 
46092
+ /**
46093
+ * **Helix draws no map.** There are no tiles here, no projection and no
46094
+ * network, and there should not be: a tile renderer is a library, and what a
46095
+ * design system can add to MapLibre or Leaflet is the frame. The consumer slots
46096
+ * their map and this owns the box, the name, the controls and the way out,
46097
+ * which is the shape `VideoPlaylist` uses for a player it never renders.
46098
+ *
46099
+ * **The accessibility argument is the reason this exists**, and it was measured
46100
+ * rather than assumed: a map embedded the ordinary way is a canvas with no role
46101
+ * and no name, and it has *no node at all* in the accessibility tree. A reader
46102
+ * using a screen reader does not walk past it so much as never meet it. A named
46103
+ * region with controls in it is the whole of the difference.
46104
+ *
46105
+ * **The controls are buttons, and that is a deliberate choice against arrow
46106
+ * keys.** Arrows work here too, but what a screen reader does with them is not
46107
+ * ours to decide: macOS passes them through, Windows readers hold them for
46108
+ * their own reading mode unless a page takes `role="application"`, which costs
46109
+ * the reader their normal way of reading everything else in the frame. A button
46110
+ * is findable and operable in every screen reader on every platform without
46111
+ * that bargain, so panning and zooming are buttons first and keys second.
46112
+ *
46113
+ * **Nothing here moves the map.** Both controls ask, through `helix-map-pan`
46114
+ * and `helix-map-zoom`, and the consumer answers against whatever they slotted.
46115
+ * A frame that moved the map would have to know whose map it was.
46116
+ *
46117
+ * ## Attributes & Properties
46118
+ *
46119
+ * Component attributes and properties that can be applied to the element or by using JavaScript.
46120
+ *
46121
+ * - `controls`: Which of the controls this frame draws, as a list of what to keep.
46122
+ *
46123
+ * **A list rather than a switch, because the overlap is not symmetric.**
46124
+ * Every map library draws zoom controls and none of them draws pan buttons:
46125
+ * MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
46126
+ * Google's is zoom. So a consumer slotting one of those has our zoom twice
46127
+ * over and our pan pad not at all, and a single switch would make them choose
46128
+ * between a duplicate and nothing.
46129
+ *
46130
+ * `none` draws none of them, which is the right answer where the slotted map
46131
+ * already has controls a reader can find: what this family argues for is that
46132
+ * *a* findable control exists, never that it is ours. The methods stay public
46133
+ * either way, so a consumer drawing their own chrome can still drive the
46134
+ * frame.
46135
+ *
46136
+ * Absent is all three, which is this library's rule that a resting value is an
46137
+ * attribute's absence, and it is what the stylesheet asks about: the layout
46138
+ * rules are written against `[controls]:not([controls~="zoom"])` rather than
46139
+ * the bare negation, or a frame that named no list at all would be laid out as
46140
+ * though it had dropped everything.
46141
+ * - `controls-placement`/`controlsPlacement`: Which corner the controls sit in.
46142
+ *
46143
+ * **Configurable because there is no safe default**, and this is a collision
46144
+ * rather than a taste: MapLibre puts its own controls at the top end, Leaflet
46145
+ * and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
46146
+ * corner this took would land on somebody's, which is why every one of those
46147
+ * libraries made it a setting too.
46148
+ *
46149
+ * Logical corners rather than left and right, so a right-to-left page moves
46150
+ * them without a consumer writing a second rule.
46151
+ *
46152
+ * Absent is the top end, which is this library's rule that a resting value is
46153
+ * an attribute's absence: a default that reflected would write an attribute
46154
+ * onto every host that no server sent and nobody asked for.
46155
+ * - `fullscreen-label`/`fullscreenLabel`: What the control that fills the screen is called.
46156
+ * - `idle-delay`/`idleDelay`: How long the reader may be still before the chrome hides, in milliseconds.
46157
+ *
46158
+ * Zero keeps it up, which is the default: a map's controls are how a keyboard
46159
+ * reader operates it, and chrome that hides itself by default would be this
46160
+ * component undoing its own argument. Set it for a display map nobody drives.
46161
+ * - `label`: Accessible name for the map, which is the one thing a consumer must write.
46162
+ *
46163
+ * There is no sensible default. "Map" names the widget rather than the place,
46164
+ * and a reader meeting three of them on a page learns nothing from hearing the
46165
+ * same word three times.
46166
+ * - `pan-label`/`panLabel`: What the controls are called, for a page not in English.
46167
+ * - `pan-step`/`panStep`: How far one press moves the map, as a fraction of what is on screen.
46168
+ *
46169
+ * A fraction rather than a distance, because this frame does not know the
46170
+ * scale of what is inside it: a quarter of the viewport is the same gesture at
46171
+ * street level and at country level, and a consumer who wants metres can
46172
+ * multiply by their own.
46173
+ * - `zoom-in-label`/`zoomInLabel`: What the zoom controls are called.
46174
+ * - `zoom-out-label`/`zoomOutLabel`: What the zoom control that goes the other way is called.
46175
+ * - `whenSettled`: Resolves a frame after the first update, when transitions are switched on.
46176
+ *
46177
+ * **Named `whenSettled` because `settled` is taken four times over**, by
46178
+ * Image, Splitter and both color controls, none of them about transitions. A
46179
+ * base class takes the name every subclass then cannot use.
46180
+ *
46181
+ * **The state it reports cannot be watched, which is why this exists.** A
46182
+ * custom state is deliberately not in the DOM, so there is no
46183
+ * `MutationObserver` equivalent for `ElementInternals.states`. Await this
46184
+ * instead.
46185
+ *
46186
+ * Separate from `updateComplete`, which resolves in the microtask checkpoint
46187
+ * the suppression is still active in. That is the distinction `readyToMove`
46188
+ * in `@fusion.dev/helix-testing` is written around.
46189
+ *
46190
+ * It never resolves where `requestAnimationFrame` never fires, which is a
46191
+ * server, a hidden tab, and happy-dom. Callers that must not hang there race
46192
+ * it against a timeout, as the happy-dom harness's `readyToMove` does. The
46193
+ * browser harness's awaits it alone: a browser always runs the frame, and a
46194
+ * timer beside it was a bet on how long one takes, which a busy run lost. (property only) (readonly)
46195
+ *
46196
+ * ## Events
46197
+ *
46198
+ * Events that will be emitted by the component.
46199
+ *
46200
+ * - `helix-map-pan`: The reader asked the map to move. Answer it against your own map.
46201
+ * - `helix-map-zoom`: The reader asked the map to zoom, by a direction rather than to a level.
46202
+ *
46203
+ * ## Slots
46204
+ *
46205
+ * Areas where markup can be added to the component.
46206
+ *
46207
+ * - `(default)`: The map, which is the consumer's own.
46208
+ * - `attribution`: Whoever the tiles belong to, which most licenses require you to say.
46209
+ * - `footer`: Chrome below the map, such as a legend or a scale.
46210
+ * - `header`: Chrome above the map, such as a title or a search field.
46211
+ *
46212
+ * ## Methods
46213
+ *
46214
+ * Methods that can be called to access component functionality.
46215
+ *
46216
+ * - `toggleFullscreen() => void`: Fills the screen with the frame, or comes back.
46217
+ * - `pan(to: Way) => void`: Asks for the map to move, which the consumer answers.
46218
+ * - `zoom(by: number) => void`: Asks for the map to zoom, `1` in and `-1` out.
46219
+ *
46220
+ * ## CSS Parts
46221
+ *
46222
+ * Custom selectors for styling elements within the component.
46223
+ *
46224
+ * - `controls`: The group the pan and zoom buttons sit in.
46225
+ * - `fullscreen`: The button that fills the screen.
46226
+ * - `pan-down`: The button that moves the map down.
46227
+ * - `pan-end`: The button that moves the map the way the text ends, which is right on an English page.
46228
+ * - `pan-start`: The button that moves the map the way the text starts, which is left on an English page.
46229
+ * - `pan-up`: The button that moves the map up.
46230
+ * - `region`: The named region the map is slotted into.
46231
+ * - `viewport`: The box the map is drawn in.
46232
+ * - `zoom-in`: The button that zooms in.
46233
+ * - `zoom-out`: The button that zooms out.
46234
+ *
46235
+ * ## CSS States
46236
+ *
46237
+ * These can be used to apply styling when a component is in a given state.
46238
+ *
46239
+ * - `fullscreen`: While the frame fills the screen.
46240
+ * - `idle`: While the reader has been still long enough to hide the chrome.
46241
+ * - `settled`: Set a frame after the first render. Transitions are held off until it is, so an element never animates its own arrival.
46242
+ */
46243
+ "helix-headless-map": Partial<
46244
+ HelixHeadlessMapProps &
46245
+ HelixHeadlessMapSolidJsProps &
46246
+ BaseProps<HelixHeadlessMap> &
46247
+ BaseEvents<HelixHeadlessMap>
46248
+ >;
46249
+
45704
46250
  /**
45705
46251
  * **A disclosure, not a menu, and that is the whole design.** `role="menu"` and
45706
46252
  * `menuitem` are for an application's commands: they take over the arrow keys,
package/types/svelte.d.ts CHANGED
@@ -69,6 +69,7 @@ declare module 'svelte/elements' {
69
69
  'helix-headless-list': CustomElements['helix-headless-list']
70
70
  'helix-headless-listbox': CustomElements['helix-headless-listbox']
71
71
  'helix-headless-loader': CustomElements['helix-headless-loader']
72
+ 'helix-headless-map': CustomElements['helix-headless-map']
72
73
  'helix-headless-megamenu': CustomElements['helix-headless-megamenu']
73
74
  'helix-headless-menu-item': CustomElements['helix-headless-menu-item']
74
75
  'helix-headless-menu': CustomElements['helix-headless-menu']