@fusion.dev/helix 0.102.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.
@@ -69361,6 +69361,34 @@
69361
69361
  }
69362
69362
  ],
69363
69363
  "members": [
69364
+ {
69365
+ "kind": "field",
69366
+ "name": "controls",
69367
+ "type": {
69368
+ "text": "string | undefined"
69369
+ },
69370
+ "description": "Which of the controls this frame draws, as a list of what to keep.\n\n**A list rather than a switch, because the overlap is not symmetric.**\nEvery map library draws zoom controls and none of them draws pan buttons:\nMapLibre's navigation control is zoom and a compass, Leaflet's is zoom,\nGoogle's is zoom. So a consumer slotting one of those has our zoom twice\nover and our pan pad not at all, and a single switch would make them choose\nbetween a duplicate and nothing.\n\n`none` draws none of them, which is the right answer where the slotted map\nalready has controls a reader can find: what this family argues for is that\n*a* findable control exists, never that it is ours. The methods stay public\neither way, so a consumer drawing their own chrome can still drive the\nframe.\n\nAbsent is all three, which is this library's rule that a resting value is an\nattribute's absence, and it is what the stylesheet asks about: the layout\nrules are written against `[controls]:not([controls~=\"zoom\"])` rather than\nthe bare negation, or a frame that named no list at all would be laid out as\nthough it had dropped everything.",
69371
+ "attribute": "controls",
69372
+ "reflects": true,
69373
+ "inheritedFrom": {
69374
+ "name": "HelixHeadlessMap",
69375
+ "module": "src/map/root/map-root.ts"
69376
+ }
69377
+ },
69378
+ {
69379
+ "kind": "field",
69380
+ "name": "controlsPlacement",
69381
+ "type": {
69382
+ "text": "'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | undefined"
69383
+ },
69384
+ "description": "Which corner the controls sit in.\n\n**Configurable because there is no safe default**, and this is a collision\nrather than a taste: MapLibre puts its own controls at the top end, Leaflet\nand OpenLayers at the top start, Google's zoom at the bottom end. Whichever\ncorner this took would land on somebody's, which is why every one of those\nlibraries made it a setting too.\n\nLogical corners rather than left and right, so a right-to-left page moves\nthem without a consumer writing a second rule.\n\nAbsent is the top end, which is this library's rule that a resting value is\nan attribute's absence: a default that reflected would write an attribute\nonto every host that no server sent and nobody asked for.",
69385
+ "attribute": "controls-placement",
69386
+ "reflects": true,
69387
+ "inheritedFrom": {
69388
+ "name": "HelixHeadlessMap",
69389
+ "module": "src/map/root/map-root.ts"
69390
+ }
69391
+ },
69364
69392
  {
69365
69393
  "kind": "field",
69366
69394
  "name": "fullscreenLabel",
@@ -69509,6 +69537,29 @@
69509
69537
  "module": "src/map/root/map-root.ts"
69510
69538
  }
69511
69539
  },
69540
+ {
69541
+ "kind": "method",
69542
+ "name": "draws",
69543
+ "privacy": "private",
69544
+ "return": {
69545
+ "type": {
69546
+ "text": "boolean"
69547
+ }
69548
+ },
69549
+ "parameters": [
69550
+ {
69551
+ "name": "group",
69552
+ "type": {
69553
+ "text": "'pan' | 'zoom' | 'fullscreen'"
69554
+ }
69555
+ }
69556
+ ],
69557
+ "description": "Whether a named group of controls is one this frame draws.",
69558
+ "inheritedFrom": {
69559
+ "name": "HelixHeadlessMap",
69560
+ "module": "src/map/root/map-root.ts"
69561
+ }
69562
+ },
69512
69563
  {
69513
69564
  "kind": "method",
69514
69565
  "name": "toggleFullscreen",
@@ -69610,6 +69661,21 @@
69610
69661
  "module": "src/map/root/map-root.ts"
69611
69662
  }
69612
69663
  },
69664
+ {
69665
+ "kind": "method",
69666
+ "name": "renderControls",
69667
+ "privacy": "private",
69668
+ "return": {
69669
+ "type": {
69670
+ "text": "TemplateResult | typeof nothing"
69671
+ }
69672
+ },
69673
+ "description": "The controls, or nothing where a consumer kept none of them.\n\n**Written out rather than generated**, because a part name behind an\ninterpolation is a part the manifest cannot see: it would publish `pan-`\nand a consumer's `::part(pan-up)` would match nothing. The same cost\n`drawIcon` names for `Trend`.",
69674
+ "inheritedFrom": {
69675
+ "name": "HelixHeadlessMap",
69676
+ "module": "src/map/root/map-root.ts"
69677
+ }
69678
+ },
69613
69679
  {
69614
69680
  "kind": "field",
69615
69681
  "name": "tier",
@@ -69955,7 +70021,7 @@
69955
70021
  "part": "Root",
69956
70022
  "examples": [
69957
70023
  {
69958
- "description": "A map the consumer brings, in a frame that names it and can be driven from the keyboard.",
70024
+ "description": "A map the consumer brings, keeping the pan pad their own library does not draw and dropping the zoom it does.",
69959
70025
  "slug": "framed"
69960
70026
  }
69961
70027
  ],
@@ -70080,6 +70146,30 @@
70080
70146
  }
70081
70147
  ],
70082
70148
  "attributes": [
70149
+ {
70150
+ "name": "controls",
70151
+ "type": {
70152
+ "text": "string | undefined"
70153
+ },
70154
+ "description": "Which of the controls this frame draws, as a list of what to keep.\n\n**A list rather than a switch, because the overlap is not symmetric.**\nEvery map library draws zoom controls and none of them draws pan buttons:\nMapLibre's navigation control is zoom and a compass, Leaflet's is zoom,\nGoogle's is zoom. So a consumer slotting one of those has our zoom twice\nover and our pan pad not at all, and a single switch would make them choose\nbetween a duplicate and nothing.\n\n`none` draws none of them, which is the right answer where the slotted map\nalready has controls a reader can find: what this family argues for is that\n*a* findable control exists, never that it is ours. The methods stay public\neither way, so a consumer drawing their own chrome can still drive the\nframe.\n\nAbsent is all three, which is this library's rule that a resting value is an\nattribute's absence, and it is what the stylesheet asks about: the layout\nrules are written against `[controls]:not([controls~=\"zoom\"])` rather than\nthe bare negation, or a frame that named no list at all would be laid out as\nthough it had dropped everything.",
70155
+ "fieldName": "controls",
70156
+ "inheritedFrom": {
70157
+ "name": "HelixHeadlessMap",
70158
+ "module": "src/map/root/map-root.ts"
70159
+ }
70160
+ },
70161
+ {
70162
+ "name": "controls-placement",
70163
+ "type": {
70164
+ "text": "'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | undefined"
70165
+ },
70166
+ "description": "Which corner the controls sit in.\n\n**Configurable because there is no safe default**, and this is a collision\nrather than a taste: MapLibre puts its own controls at the top end, Leaflet\nand OpenLayers at the top start, Google's zoom at the bottom end. Whichever\ncorner this took would land on somebody's, which is why every one of those\nlibraries made it a setting too.\n\nLogical corners rather than left and right, so a right-to-left page moves\nthem without a consumer writing a second rule.\n\nAbsent is the top end, which is this library's rule that a resting value is\nan attribute's absence: a default that reflected would write an attribute\nonto every host that no server sent and nobody asked for.",
70167
+ "fieldName": "controlsPlacement",
70168
+ "inheritedFrom": {
70169
+ "name": "HelixHeadlessMap",
70170
+ "module": "src/map/root/map-root.ts"
70171
+ }
70172
+ },
70083
70173
  {
70084
70174
  "name": "fullscreen-label",
70085
70175
  "type": {
@@ -39,12 +39,47 @@ grid-template-areas:
39
39
  ". up . zoomin"
40
40
  "start . end zoomout"
41
41
  ". down . full";
42
+ position: absolute;
43
+
42
44
  inset-block-start: var(--helix-space-sm);
43
45
  inset-inline-end: var(--helix-space-sm);
44
- position: absolute;
45
46
  transition: opacity var(--helix-duration-fast) var(--helix-easing-standard);
46
47
  }
47
48
 
49
+ :host([controls]:not([controls~="zoom"])) [part="controls"] {
50
+ grid-template-areas:
51
+ ". up ."
52
+ "start . end"
53
+ ". down full";
54
+ }
55
+
56
+ :host([controls]:not([controls~="pan"])) [part="controls"] {
57
+ grid-template-areas:
58
+ "zoomin"
59
+ "zoomout"
60
+ "full";
61
+ }
62
+
63
+ :host([controls-placement="top-end"]) [part="controls"] {
64
+ inset-block: var(--helix-space-sm) auto;
65
+ inset-inline: auto var(--helix-space-sm);
66
+ }
67
+
68
+ :host([controls-placement="top-start"]) [part="controls"] {
69
+ inset-block: var(--helix-space-sm) auto;
70
+ inset-inline: var(--helix-space-sm) auto;
71
+ }
72
+
73
+ :host([controls-placement="bottom-end"]) [part="controls"] {
74
+ inset-block: auto var(--helix-space-sm);
75
+ inset-inline: auto var(--helix-space-sm);
76
+ }
77
+
78
+ :host([controls-placement="bottom-start"]) [part="controls"] {
79
+ inset-block: auto var(--helix-space-sm);
80
+ inset-inline: var(--helix-space-sm) auto;
81
+ }
82
+
48
83
  [part="pan-up"] {
49
84
  grid-area: up;
50
85
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix",
3
3
  "description": "Styled component tier. Extends the headless tier with token-driven presentation.",
4
- "version": "0.102.0",
4
+ "version": "0.103.0",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -47,13 +47,13 @@
47
47
  },
48
48
  "bugs": "https://github.com/project-fusion/fusion/issues",
49
49
  "dependencies": {
50
- "@fusion.dev/helix-core": "0.102.0",
51
- "@fusion.dev/helix-headless": "0.102.0",
52
- "@fusion.dev/helix-styles": "0.102.0"
50
+ "@fusion.dev/helix-core": "0.103.0",
51
+ "@fusion.dev/helix-headless": "0.103.0",
52
+ "@fusion.dev/helix-styles": "0.103.0"
53
53
  },
54
54
  "devDependencies": {
55
- "@fusion.dev/helix-cem": "0.102.0",
56
- "@fusion.dev/helix-testing": "0.102.0",
55
+ "@fusion.dev/helix-cem": "0.103.0",
56
+ "@fusion.dev/helix-testing": "0.103.0",
57
57
  "@fusion.dev/scripts": "0.0.0-dev",
58
58
  "@happy-dom/global-registrator": "^20.0.0",
59
59
  "@lit-labs/ssr": "^4.1.0",
package/types/jsx.d.ts CHANGED
@@ -11510,6 +11510,57 @@ export type HelixMapHelixMapZoomElementEvent =
11510
11510
  HelixMapElementEvent<HelixMapZoomEvent>;
11511
11511
 
11512
11512
  export type HelixMapProps = {
11513
+ /** Which of the controls this frame draws, as a list of what to keep.
11514
+
11515
+ **A list rather than a switch, because the overlap is not symmetric.**
11516
+ Every map library draws zoom controls and none of them draws pan buttons:
11517
+ MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
11518
+ Google's is zoom. So a consumer slotting one of those has our zoom twice
11519
+ over and our pan pad not at all, and a single switch would make them choose
11520
+ between a duplicate and nothing.
11521
+
11522
+ `none` draws none of them, which is the right answer where the slotted map
11523
+ already has controls a reader can find: what this family argues for is that
11524
+ *a* findable control exists, never that it is ours. The methods stay public
11525
+ either way, so a consumer drawing their own chrome can still drive the
11526
+ frame.
11527
+
11528
+ Absent is all three, which is this library's rule that a resting value is an
11529
+ attribute's absence, and it is what the stylesheet asks about: the layout
11530
+ rules are written against `[controls]:not([controls~="zoom"])` rather than
11531
+ the bare negation, or a frame that named no list at all would be laid out as
11532
+ though it had dropped everything. */
11533
+ controls?: (HelixMap["controls"]) | undefined;
11534
+ /** Which corner the controls sit in.
11535
+
11536
+ **Configurable because there is no safe default**, and this is a collision
11537
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
11538
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
11539
+ corner this took would land on somebody's, which is why every one of those
11540
+ libraries made it a setting too.
11541
+
11542
+ Logical corners rather than left and right, so a right-to-left page moves
11543
+ them without a consumer writing a second rule.
11544
+
11545
+ Absent is the top end, which is this library's rule that a resting value is
11546
+ an attribute's absence: a default that reflected would write an attribute
11547
+ onto every host that no server sent and nobody asked for. */
11548
+ "controls-placement"?: (HelixMap["controlsPlacement"]) | undefined;
11549
+ /** Which corner the controls sit in.
11550
+
11551
+ **Configurable because there is no safe default**, and this is a collision
11552
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
11553
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
11554
+ corner this took would land on somebody's, which is why every one of those
11555
+ libraries made it a setting too.
11556
+
11557
+ Logical corners rather than left and right, so a right-to-left page moves
11558
+ them without a consumer writing a second rule.
11559
+
11560
+ Absent is the top end, which is this library's rule that a resting value is
11561
+ an attribute's absence: a default that reflected would write an attribute
11562
+ onto every host that no server sent and nobody asked for. */
11563
+ controlsPlacement?: (HelixMap["controlsPlacement"]) | undefined;
11513
11564
  /** What the control that fills the screen is called. */
11514
11565
  "fullscreen-label"?: (HelixMap["fullscreenLabel"]) | undefined;
11515
11566
  /** What the control that fills the screen is called. */
@@ -11566,6 +11617,57 @@ multiply by their own. */
11566
11617
  };
11567
11618
 
11568
11619
  export type HelixMapSolidJsProps = {
11620
+ /** Which of the controls this frame draws, as a list of what to keep.
11621
+
11622
+ **A list rather than a switch, because the overlap is not symmetric.**
11623
+ Every map library draws zoom controls and none of them draws pan buttons:
11624
+ MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
11625
+ Google's is zoom. So a consumer slotting one of those has our zoom twice
11626
+ over and our pan pad not at all, and a single switch would make them choose
11627
+ between a duplicate and nothing.
11628
+
11629
+ `none` draws none of them, which is the right answer where the slotted map
11630
+ already has controls a reader can find: what this family argues for is that
11631
+ *a* findable control exists, never that it is ours. The methods stay public
11632
+ either way, so a consumer drawing their own chrome can still drive the
11633
+ frame.
11634
+
11635
+ Absent is all three, which is this library's rule that a resting value is an
11636
+ attribute's absence, and it is what the stylesheet asks about: the layout
11637
+ rules are written against `[controls]:not([controls~="zoom"])` rather than
11638
+ the bare negation, or a frame that named no list at all would be laid out as
11639
+ though it had dropped everything. */
11640
+ "prop:controls"?: (HelixMap["controls"]) | undefined;
11641
+ /** Which corner the controls sit in.
11642
+
11643
+ **Configurable because there is no safe default**, and this is a collision
11644
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
11645
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
11646
+ corner this took would land on somebody's, which is why every one of those
11647
+ libraries made it a setting too.
11648
+
11649
+ Logical corners rather than left and right, so a right-to-left page moves
11650
+ them without a consumer writing a second rule.
11651
+
11652
+ Absent is the top end, which is this library's rule that a resting value is
11653
+ an attribute's absence: a default that reflected would write an attribute
11654
+ onto every host that no server sent and nobody asked for. */
11655
+ "attr:controls-placement"?: (HelixMap["controlsPlacement"]) | undefined;
11656
+ /** Which corner the controls sit in.
11657
+
11658
+ **Configurable because there is no safe default**, and this is a collision
11659
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
11660
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
11661
+ corner this took would land on somebody's, which is why every one of those
11662
+ libraries made it a setting too.
11663
+
11664
+ Logical corners rather than left and right, so a right-to-left page moves
11665
+ them without a consumer writing a second rule.
11666
+
11667
+ Absent is the top end, which is this library's rule that a resting value is
11668
+ an attribute's absence: a default that reflected would write an attribute
11669
+ onto every host that no server sent and nobody asked for. */
11670
+ "prop:controlsPlacement"?: (HelixMap["controlsPlacement"]) | undefined;
11569
11671
  /** What the control that fills the screen is called. */
11570
11672
  "attr:fullscreen-label"?: (HelixMap["fullscreenLabel"]) | undefined;
11571
11673
  /** What the control that fills the screen is called. */
@@ -31771,6 +31873,40 @@ export type CustomElements = {
31771
31873
  *
31772
31874
  * Component attributes and properties that can be applied to the element or by using JavaScript.
31773
31875
  *
31876
+ * - `controls`: Which of the controls this frame draws, as a list of what to keep.
31877
+ *
31878
+ * **A list rather than a switch, because the overlap is not symmetric.**
31879
+ * Every map library draws zoom controls and none of them draws pan buttons:
31880
+ * MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
31881
+ * Google's is zoom. So a consumer slotting one of those has our zoom twice
31882
+ * over and our pan pad not at all, and a single switch would make them choose
31883
+ * between a duplicate and nothing.
31884
+ *
31885
+ * `none` draws none of them, which is the right answer where the slotted map
31886
+ * already has controls a reader can find: what this family argues for is that
31887
+ * *a* findable control exists, never that it is ours. The methods stay public
31888
+ * either way, so a consumer drawing their own chrome can still drive the
31889
+ * frame.
31890
+ *
31891
+ * Absent is all three, which is this library's rule that a resting value is an
31892
+ * attribute's absence, and it is what the stylesheet asks about: the layout
31893
+ * rules are written against `[controls]:not([controls~="zoom"])` rather than
31894
+ * the bare negation, or a frame that named no list at all would be laid out as
31895
+ * though it had dropped everything.
31896
+ * - `controls-placement`/`controlsPlacement`: Which corner the controls sit in.
31897
+ *
31898
+ * **Configurable because there is no safe default**, and this is a collision
31899
+ * rather than a taste: MapLibre puts its own controls at the top end, Leaflet
31900
+ * and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
31901
+ * corner this took would land on somebody's, which is why every one of those
31902
+ * libraries made it a setting too.
31903
+ *
31904
+ * Logical corners rather than left and right, so a right-to-left page moves
31905
+ * them without a consumer writing a second rule.
31906
+ *
31907
+ * Absent is the top end, which is this library's rule that a resting value is
31908
+ * an attribute's absence: a default that reflected would write an attribute
31909
+ * onto every host that no server sent and nobody asked for.
31774
31910
  * - `fullscreen-label`/`fullscreenLabel`: What the control that fills the screen is called.
31775
31911
  * - `idle-delay`/`idleDelay`: How long the reader may be still before the chrome hides, in milliseconds.
31776
31912
  *
@@ -51970,6 +52106,40 @@ export type CustomElementsSolidJs = {
51970
52106
  *
51971
52107
  * Component attributes and properties that can be applied to the element or by using JavaScript.
51972
52108
  *
52109
+ * - `controls`: Which of the controls this frame draws, as a list of what to keep.
52110
+ *
52111
+ * **A list rather than a switch, because the overlap is not symmetric.**
52112
+ * Every map library draws zoom controls and none of them draws pan buttons:
52113
+ * MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
52114
+ * Google's is zoom. So a consumer slotting one of those has our zoom twice
52115
+ * over and our pan pad not at all, and a single switch would make them choose
52116
+ * between a duplicate and nothing.
52117
+ *
52118
+ * `none` draws none of them, which is the right answer where the slotted map
52119
+ * already has controls a reader can find: what this family argues for is that
52120
+ * *a* findable control exists, never that it is ours. The methods stay public
52121
+ * either way, so a consumer drawing their own chrome can still drive the
52122
+ * frame.
52123
+ *
52124
+ * Absent is all three, which is this library's rule that a resting value is an
52125
+ * attribute's absence, and it is what the stylesheet asks about: the layout
52126
+ * rules are written against `[controls]:not([controls~="zoom"])` rather than
52127
+ * the bare negation, or a frame that named no list at all would be laid out as
52128
+ * though it had dropped everything.
52129
+ * - `controls-placement`/`controlsPlacement`: Which corner the controls sit in.
52130
+ *
52131
+ * **Configurable because there is no safe default**, and this is a collision
52132
+ * rather than a taste: MapLibre puts its own controls at the top end, Leaflet
52133
+ * and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
52134
+ * corner this took would land on somebody's, which is why every one of those
52135
+ * libraries made it a setting too.
52136
+ *
52137
+ * Logical corners rather than left and right, so a right-to-left page moves
52138
+ * them without a consumer writing a second rule.
52139
+ *
52140
+ * Absent is the top end, which is this library's rule that a resting value is
52141
+ * an attribute's absence: a default that reflected would write an attribute
52142
+ * onto every host that no server sent and nobody asked for.
51973
52143
  * - `fullscreen-label`/`fullscreenLabel`: What the control that fills the screen is called.
51974
52144
  * - `idle-delay`/`idleDelay`: How long the reader may be still before the chrome hides, in milliseconds.
51975
52145
  *
package/types/vue.d.ts CHANGED
@@ -5880,6 +5880,57 @@ export type HelixMapHelixMapZoomElementEvent =
5880
5880
  HelixMapElementEvent<HelixMapZoomEvent>;
5881
5881
 
5882
5882
  export type HelixMapVueProps = {
5883
+ /** Which of the controls this frame draws, as a list of what to keep.
5884
+
5885
+ **A list rather than a switch, because the overlap is not symmetric.**
5886
+ Every map library draws zoom controls and none of them draws pan buttons:
5887
+ MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
5888
+ Google's is zoom. So a consumer slotting one of those has our zoom twice
5889
+ over and our pan pad not at all, and a single switch would make them choose
5890
+ between a duplicate and nothing.
5891
+
5892
+ `none` draws none of them, which is the right answer where the slotted map
5893
+ already has controls a reader can find: what this family argues for is that
5894
+ *a* findable control exists, never that it is ours. The methods stay public
5895
+ either way, so a consumer drawing their own chrome can still drive the
5896
+ frame.
5897
+
5898
+ Absent is all three, which is this library's rule that a resting value is an
5899
+ attribute's absence, and it is what the stylesheet asks about: the layout
5900
+ rules are written against `[controls]:not([controls~="zoom"])` rather than
5901
+ the bare negation, or a frame that named no list at all would be laid out as
5902
+ though it had dropped everything. */
5903
+ controls?: (HelixMap["controls"]) | undefined;
5904
+ /** Which corner the controls sit in.
5905
+
5906
+ **Configurable because there is no safe default**, and this is a collision
5907
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
5908
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
5909
+ corner this took would land on somebody's, which is why every one of those
5910
+ libraries made it a setting too.
5911
+
5912
+ Logical corners rather than left and right, so a right-to-left page moves
5913
+ them without a consumer writing a second rule.
5914
+
5915
+ Absent is the top end, which is this library's rule that a resting value is
5916
+ an attribute's absence: a default that reflected would write an attribute
5917
+ onto every host that no server sent and nobody asked for. */
5918
+ "controls-placement"?: (HelixMap["controlsPlacement"]) | undefined;
5919
+ /** Which corner the controls sit in.
5920
+
5921
+ **Configurable because there is no safe default**, and this is a collision
5922
+ rather than a taste: MapLibre puts its own controls at the top end, Leaflet
5923
+ and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
5924
+ corner this took would land on somebody's, which is why every one of those
5925
+ libraries made it a setting too.
5926
+
5927
+ Logical corners rather than left and right, so a right-to-left page moves
5928
+ them without a consumer writing a second rule.
5929
+
5930
+ Absent is the top end, which is this library's rule that a resting value is
5931
+ an attribute's absence: a default that reflected would write an attribute
5932
+ onto every host that no server sent and nobody asked for. */
5933
+ controlsPlacement?: (HelixMap["controlsPlacement"]) | undefined;
5883
5934
  /** What the control that fills the screen is called. */
5884
5935
  "fullscreen-label"?: (HelixMap["fullscreenLabel"]) | undefined;
5885
5936
  /** What the control that fills the screen is called. */