maplibre-gl-basemap-control 0.7.0 → 0.8.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/README.md +4 -2
- package/dist/{BasemapControl-CfFepxWc.js → BasemapControl-C9T87uJx.js} +310 -124
- package/dist/BasemapControl-C9T87uJx.js.map +1 -0
- package/dist/{BasemapControl-qDrnfFqz.cjs → BasemapControl-Dl0aWr1N.cjs} +310 -124
- package/dist/BasemapControl-Dl0aWr1N.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/maplibre-gl-basemap-control.css +107 -8
- package/dist/react.cjs +1 -1
- package/dist/react.mjs +1 -1
- package/dist/types/lib/core/BasemapControl.d.ts +12 -2
- package/dist/types/lib/core/BasemapControl.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/BasemapControl-CfFepxWc.js.map +0 -1
- package/dist/BasemapControl-qDrnfFqz.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -141,8 +141,10 @@ Mapbox styles include Streets, Outdoors, Light, Dark, Satellite, Satellite Stree
|
|
|
141
141
|
and Navigation Night.
|
|
142
142
|
|
|
143
143
|
MapTiler and Amazon Location styles require API keys. Mapbox styles require an access token. Users
|
|
144
|
-
can enter keys and tokens in the
|
|
145
|
-
can provide them when creating the control.
|
|
144
|
+
can enter keys and tokens in the dedicated API keys view, opened from the key button in the panel
|
|
145
|
+
header, or you can provide them when creating the control. When a basemap is selected before its key
|
|
146
|
+
is set, the control surfaces the error and the matching credential field inline, before any
|
|
147
|
+
destructive style change, so the missing key can be entered and the basemap retried with Enter.
|
|
146
148
|
|
|
147
149
|
```typescript
|
|
148
150
|
const control = new BasemapControl({
|
|
@@ -1316,11 +1316,18 @@ class BasemapControl {
|
|
|
1316
1316
|
// a traffic overlay reuses a token until it expires instead of creating a new
|
|
1317
1317
|
// session on every add. Keyed by the serialized config + API key.
|
|
1318
1318
|
__publicField(this, "_googleSessions", new globalThis.Map());
|
|
1319
|
-
|
|
1319
|
+
// Which sub-view the panel content shows: the basemap list, or the dedicated
|
|
1320
|
+
// API-keys settings view opened from the header key button (#837).
|
|
1321
|
+
__publicField(this, "_activeView", "basemaps");
|
|
1322
|
+
__publicField(this, "_settingsButton");
|
|
1320
1323
|
// Provider of the most recent missing-credential error, used to pick the
|
|
1321
|
-
// matching help link
|
|
1322
|
-
// in `
|
|
1324
|
+
// matching help link and the inline credential field beside the error. Kept
|
|
1325
|
+
// in sync with `_state.error` (both are cleared together) so it is never
|
|
1326
|
+
// stale when consulted.
|
|
1323
1327
|
__publicField(this, "_missingCredentialProvider");
|
|
1328
|
+
// The basemap whose application last failed for a missing credential, so the
|
|
1329
|
+
// inline credential field's Enter key can re-attempt it (#837).
|
|
1330
|
+
__publicField(this, "_lastFailedBasemapId");
|
|
1324
1331
|
__publicField(this, "_resizeHandler", null);
|
|
1325
1332
|
__publicField(this, "_mapResizeHandler", null);
|
|
1326
1333
|
__publicField(this, "_resizeAnchor", null);
|
|
@@ -1468,39 +1475,39 @@ class BasemapControl {
|
|
|
1468
1475
|
}
|
|
1469
1476
|
setMapTilerApiKey(apiKey) {
|
|
1470
1477
|
this._mapTilerApiKey = apiKey;
|
|
1471
|
-
this.
|
|
1478
|
+
this._clearError();
|
|
1472
1479
|
this._renderContent();
|
|
1473
1480
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1474
1481
|
}
|
|
1475
1482
|
setAmazonCredentials(apiKey, awsRegion = this._awsRegion) {
|
|
1476
1483
|
this._amazonApiKey = apiKey;
|
|
1477
1484
|
this._awsRegion = awsRegion;
|
|
1478
|
-
this.
|
|
1485
|
+
this._clearError();
|
|
1479
1486
|
this._renderContent();
|
|
1480
1487
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1481
1488
|
}
|
|
1482
1489
|
setMapboxAccessToken(accessToken) {
|
|
1483
1490
|
this._mapboxAccessToken = accessToken;
|
|
1484
|
-
this.
|
|
1491
|
+
this._clearError();
|
|
1485
1492
|
this._renderContent();
|
|
1486
1493
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1487
1494
|
}
|
|
1488
1495
|
setTomTomApiKey(apiKey) {
|
|
1489
1496
|
this._tomtomApiKey = apiKey;
|
|
1490
|
-
this.
|
|
1497
|
+
this._clearError();
|
|
1491
1498
|
this._renderContent();
|
|
1492
1499
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1493
1500
|
}
|
|
1494
1501
|
setHereApiKey(apiKey) {
|
|
1495
1502
|
this._hereApiKey = apiKey;
|
|
1496
|
-
this.
|
|
1503
|
+
this._clearError();
|
|
1497
1504
|
this._renderContent();
|
|
1498
1505
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1499
1506
|
}
|
|
1500
1507
|
setGoogleMapsApiKey(apiKey) {
|
|
1501
1508
|
this._googleMapsApiKey = apiKey;
|
|
1502
1509
|
this._googleSessions.clear();
|
|
1503
|
-
this.
|
|
1510
|
+
this._clearError();
|
|
1504
1511
|
this._renderContent();
|
|
1505
1512
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1506
1513
|
}
|
|
@@ -1568,6 +1575,16 @@ class BasemapControl {
|
|
|
1568
1575
|
}
|
|
1569
1576
|
const isOverlay = basemap.source.type === "raster" || basemap.source.type === "vector-overlay";
|
|
1570
1577
|
const effectiveMode = isOverlay ? mode : "replace";
|
|
1578
|
+
if (!isOverlay) {
|
|
1579
|
+
try {
|
|
1580
|
+
this._resolveStyleUrl(basemap);
|
|
1581
|
+
} catch (cause) {
|
|
1582
|
+
if (cause instanceof MissingCredentialError) {
|
|
1583
|
+
this._enterCredentialError(cause, basemap);
|
|
1584
|
+
throw cause;
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1571
1588
|
if (!isOverlay && this._state.allowMultiple && this._managedRasters.size > 0 && this._options.confirmStyleReplace) {
|
|
1572
1589
|
const replacedBasemapIds = [...this._managedRasters.keys()];
|
|
1573
1590
|
let confirmed = false;
|
|
@@ -1621,13 +1638,14 @@ class BasemapControl {
|
|
|
1621
1638
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1622
1639
|
} catch (cause) {
|
|
1623
1640
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
this.
|
|
1641
|
+
if (error instanceof MissingCredentialError) {
|
|
1642
|
+
this._enterCredentialError(error, basemap);
|
|
1643
|
+
} else {
|
|
1644
|
+
this._state = { ...this._state, loading: false, error: error.message };
|
|
1645
|
+
this._missingCredentialProvider = void 0;
|
|
1646
|
+
this._renderContent(true);
|
|
1647
|
+
this._handleError(error, basemap);
|
|
1628
1648
|
}
|
|
1629
|
-
this._renderContent(true);
|
|
1630
|
-
this._handleError(error, basemap);
|
|
1631
1649
|
throw error;
|
|
1632
1650
|
}
|
|
1633
1651
|
}
|
|
@@ -1690,6 +1708,28 @@ class BasemapControl {
|
|
|
1690
1708
|
this._emit({ type: "error", state: this.getState(), error, basemap });
|
|
1691
1709
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1692
1710
|
}
|
|
1711
|
+
// Clears the current error and its associated missing-credential provider so
|
|
1712
|
+
// the inline credential field and help link disappear together.
|
|
1713
|
+
_clearError() {
|
|
1714
|
+
if (this._state.error === void 0 && this._missingCredentialProvider === void 0 && this._lastFailedBasemapId === void 0) {
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
this._state = { ...this._state, error: void 0 };
|
|
1718
|
+
this._missingCredentialProvider = void 0;
|
|
1719
|
+
this._lastFailedBasemapId = void 0;
|
|
1720
|
+
}
|
|
1721
|
+
// Records a missing-credential failure: stores the error, remembers the
|
|
1722
|
+
// provider (for the help link and inline field) and the basemap to retry, and
|
|
1723
|
+
// surfaces the basemaps view so the inline credential field beside the error
|
|
1724
|
+
// is visible (#837).
|
|
1725
|
+
_enterCredentialError(error, basemap) {
|
|
1726
|
+
this._state = { ...this._state, loading: false, error: error.message };
|
|
1727
|
+
this._missingCredentialProvider = error.provider;
|
|
1728
|
+
this._lastFailedBasemapId = basemap.id;
|
|
1729
|
+
this._activeView = "basemaps";
|
|
1730
|
+
this._renderContent(true);
|
|
1731
|
+
this._handleError(error, basemap);
|
|
1732
|
+
}
|
|
1693
1733
|
_createContainer() {
|
|
1694
1734
|
const container = document.createElement("div");
|
|
1695
1735
|
container.className = `maplibregl-ctrl maplibregl-ctrl-group basemap-control${this._options.className ? ` ${this._options.className}` : ""}`;
|
|
@@ -1724,6 +1764,18 @@ class BasemapControl {
|
|
|
1724
1764
|
const title = document.createElement("span");
|
|
1725
1765
|
title.className = "basemap-control-title";
|
|
1726
1766
|
title.textContent = this._options.title;
|
|
1767
|
+
const settingsBtn = document.createElement("button");
|
|
1768
|
+
settingsBtn.className = "basemap-control-settings-toggle";
|
|
1769
|
+
settingsBtn.type = "button";
|
|
1770
|
+
settingsBtn.setAttribute("aria-label", "API keys");
|
|
1771
|
+
settingsBtn.title = "API keys";
|
|
1772
|
+
settingsBtn.innerHTML = `
|
|
1773
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
1774
|
+
<path d="m21 2-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0 3 3L22 7l-3-3m-3.5 3.5L19 4"/>
|
|
1775
|
+
</svg>
|
|
1776
|
+
`;
|
|
1777
|
+
settingsBtn.addEventListener("click", () => this._toggleSettingsView());
|
|
1778
|
+
this._settingsButton = settingsBtn;
|
|
1727
1779
|
const closeBtn = document.createElement("button");
|
|
1728
1780
|
closeBtn.className = "basemap-control-close";
|
|
1729
1781
|
closeBtn.type = "button";
|
|
@@ -1731,6 +1783,7 @@ class BasemapControl {
|
|
|
1731
1783
|
closeBtn.innerHTML = "×";
|
|
1732
1784
|
closeBtn.addEventListener("click", () => this.collapse());
|
|
1733
1785
|
header.appendChild(title);
|
|
1786
|
+
header.appendChild(settingsBtn);
|
|
1734
1787
|
header.appendChild(closeBtn);
|
|
1735
1788
|
this._content = document.createElement("div");
|
|
1736
1789
|
this._content.className = "basemap-control-content";
|
|
@@ -1752,13 +1805,17 @@ class BasemapControl {
|
|
|
1752
1805
|
_renderContent(preserveResultsScroll = false) {
|
|
1753
1806
|
var _a;
|
|
1754
1807
|
if (!this._content) return;
|
|
1808
|
+
this._reconcileSettingsButton();
|
|
1809
|
+
if (this._activeView === "settings" && this._hasProviderSettings()) {
|
|
1810
|
+
this._content.replaceChildren(this._createSettingsView());
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1755
1813
|
const categories = getBasemapCategories(this._basemaps);
|
|
1756
1814
|
const results = this._getFilteredBasemaps();
|
|
1757
1815
|
const previousResultsScrollTop = preserveResultsScroll ? (_a = this._content.querySelector(".basemap-control-results")) == null ? void 0 : _a.scrollTop : void 0;
|
|
1758
1816
|
this._content.replaceChildren(
|
|
1759
1817
|
this._createSearchRow(),
|
|
1760
1818
|
...this._options.showMultipleToggle ? [this._createMultipleToggleRow()] : [],
|
|
1761
|
-
...this._hasProviderSettings() ? [this._createProviderSettingsSection()] : [],
|
|
1762
1819
|
this._createFilterRow(this._providers, categories),
|
|
1763
1820
|
this._createStatus(results.length),
|
|
1764
1821
|
this._createResults(results)
|
|
@@ -1768,6 +1825,23 @@ class BasemapControl {
|
|
|
1768
1825
|
if (resultsElement) resultsElement.scrollTop = previousResultsScrollTop;
|
|
1769
1826
|
}
|
|
1770
1827
|
}
|
|
1828
|
+
// Show the key button only when the catalog actually needs a provider
|
|
1829
|
+
// credential, and reflect whether the settings view is currently open.
|
|
1830
|
+
_reconcileSettingsButton() {
|
|
1831
|
+
if (!this._settingsButton) return;
|
|
1832
|
+
const hasSettings = this._hasProviderSettings();
|
|
1833
|
+
this._settingsButton.hidden = !hasSettings;
|
|
1834
|
+
this._settingsButton.classList.toggle(
|
|
1835
|
+
"is-active",
|
|
1836
|
+
hasSettings && this._activeView === "settings"
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
_toggleSettingsView() {
|
|
1840
|
+
if (!this._hasProviderSettings()) return;
|
|
1841
|
+
this._activeView = this._activeView === "settings" ? "basemaps" : "settings";
|
|
1842
|
+
this._renderContent();
|
|
1843
|
+
this._emit({ type: "statechange", state: this.getState() });
|
|
1844
|
+
}
|
|
1771
1845
|
_renderFilteredResults() {
|
|
1772
1846
|
var _a, _b;
|
|
1773
1847
|
if (!this._content) return;
|
|
@@ -1822,8 +1896,18 @@ class BasemapControl {
|
|
|
1822
1896
|
input.value = this._state.query;
|
|
1823
1897
|
input.setAttribute("aria-label", "Search basemaps");
|
|
1824
1898
|
input.addEventListener("input", () => {
|
|
1899
|
+
var _a;
|
|
1900
|
+
const hadError = this._state.error !== void 0;
|
|
1825
1901
|
this._state = { ...this._state, query: input.value };
|
|
1826
|
-
this.
|
|
1902
|
+
this._clearError();
|
|
1903
|
+
if (hadError) {
|
|
1904
|
+
this._renderContent();
|
|
1905
|
+
input.focus();
|
|
1906
|
+
const end = input.value.length;
|
|
1907
|
+
(_a = input.setSelectionRange) == null ? void 0 : _a.call(input, end, end);
|
|
1908
|
+
} else {
|
|
1909
|
+
this._renderFilteredResults();
|
|
1910
|
+
}
|
|
1827
1911
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1828
1912
|
});
|
|
1829
1913
|
wrapper.appendChild(input);
|
|
@@ -1845,118 +1929,205 @@ class BasemapControl {
|
|
|
1845
1929
|
wrapper.appendChild(input);
|
|
1846
1930
|
return wrapper;
|
|
1847
1931
|
}
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
value: this._mapTilerApiKey,
|
|
1869
|
-
onInput: (value) => {
|
|
1870
|
-
this._mapTilerApiKey = value;
|
|
1932
|
+
// The ordered set of provider credential fields, gated by whether the catalog
|
|
1933
|
+
// actually contains basemaps for each provider. A single source of truth for
|
|
1934
|
+
// both the centralized settings view and the inline field shown beside a
|
|
1935
|
+
// missing-credential error, so the two never drift (#837).
|
|
1936
|
+
_providerFieldDefs() {
|
|
1937
|
+
return [
|
|
1938
|
+
{
|
|
1939
|
+
provider: "maptiler",
|
|
1940
|
+
label: "MapTiler",
|
|
1941
|
+
has: this._hasMapTilerBasemaps(),
|
|
1942
|
+
fields: [
|
|
1943
|
+
{
|
|
1944
|
+
className: "basemap-control-maptiler-key",
|
|
1945
|
+
type: "password",
|
|
1946
|
+
placeholder: "MapTiler API key",
|
|
1947
|
+
ariaLabel: "MapTiler API key",
|
|
1948
|
+
value: this._mapTilerApiKey,
|
|
1949
|
+
onInput: (value) => {
|
|
1950
|
+
this._mapTilerApiKey = value;
|
|
1951
|
+
}
|
|
1871
1952
|
}
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
this.
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
this._mapboxAccessToken
|
|
1953
|
+
]
|
|
1954
|
+
},
|
|
1955
|
+
{
|
|
1956
|
+
provider: "mapbox",
|
|
1957
|
+
label: "Mapbox",
|
|
1958
|
+
has: this._hasMapboxBasemaps(),
|
|
1959
|
+
fields: [
|
|
1960
|
+
{
|
|
1961
|
+
className: "basemap-control-mapbox-token",
|
|
1962
|
+
type: "password",
|
|
1963
|
+
placeholder: "Mapbox access token",
|
|
1964
|
+
ariaLabel: "Mapbox access token",
|
|
1965
|
+
value: this._mapboxAccessToken,
|
|
1966
|
+
onInput: (value) => {
|
|
1967
|
+
this._mapboxAccessToken = value;
|
|
1968
|
+
}
|
|
1885
1969
|
}
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
this.
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
this._tomtomApiKey
|
|
1970
|
+
]
|
|
1971
|
+
},
|
|
1972
|
+
{
|
|
1973
|
+
provider: "tomtom",
|
|
1974
|
+
label: "TomTom",
|
|
1975
|
+
has: this._hasTomTomBasemaps(),
|
|
1976
|
+
fields: [
|
|
1977
|
+
{
|
|
1978
|
+
className: "basemap-control-tomtom-key",
|
|
1979
|
+
type: "password",
|
|
1980
|
+
placeholder: "TomTom API key",
|
|
1981
|
+
ariaLabel: "TomTom API key",
|
|
1982
|
+
value: this._tomtomApiKey,
|
|
1983
|
+
onInput: (value) => {
|
|
1984
|
+
this._tomtomApiKey = value;
|
|
1985
|
+
}
|
|
1899
1986
|
}
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
this.
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
this._hereApiKey
|
|
1987
|
+
]
|
|
1988
|
+
},
|
|
1989
|
+
{
|
|
1990
|
+
provider: "here",
|
|
1991
|
+
label: "HERE",
|
|
1992
|
+
has: this._hasHereBasemaps(),
|
|
1993
|
+
fields: [
|
|
1994
|
+
{
|
|
1995
|
+
className: "basemap-control-here-key",
|
|
1996
|
+
type: "password",
|
|
1997
|
+
placeholder: "HERE API key",
|
|
1998
|
+
ariaLabel: "HERE API key",
|
|
1999
|
+
value: this._hereApiKey,
|
|
2000
|
+
onInput: (value) => {
|
|
2001
|
+
this._hereApiKey = value;
|
|
2002
|
+
}
|
|
1913
2003
|
}
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
this.
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
this._googleMapsApiKey
|
|
1927
|
-
|
|
2004
|
+
]
|
|
2005
|
+
},
|
|
2006
|
+
{
|
|
2007
|
+
provider: "google",
|
|
2008
|
+
label: "Google",
|
|
2009
|
+
has: this._hasGoogleApiKeyBasemaps(),
|
|
2010
|
+
fields: [
|
|
2011
|
+
{
|
|
2012
|
+
className: "basemap-control-google-key",
|
|
2013
|
+
type: "password",
|
|
2014
|
+
placeholder: "Google Maps API key",
|
|
2015
|
+
ariaLabel: "Google Maps API key",
|
|
2016
|
+
value: this._googleMapsApiKey,
|
|
2017
|
+
onInput: (value) => {
|
|
2018
|
+
this._googleMapsApiKey = value;
|
|
2019
|
+
this._googleSessions.clear();
|
|
2020
|
+
}
|
|
1928
2021
|
}
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
this.
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
this._amazonApiKey
|
|
2022
|
+
]
|
|
2023
|
+
},
|
|
2024
|
+
{
|
|
2025
|
+
provider: "amazon",
|
|
2026
|
+
label: "Amazon",
|
|
2027
|
+
has: this._hasAmazonBasemaps(),
|
|
2028
|
+
fields: [
|
|
2029
|
+
{
|
|
2030
|
+
className: "basemap-control-amazon-key",
|
|
2031
|
+
type: "password",
|
|
2032
|
+
placeholder: "Amazon API key",
|
|
2033
|
+
ariaLabel: "Amazon API key",
|
|
2034
|
+
value: this._amazonApiKey,
|
|
2035
|
+
onInput: (value) => {
|
|
2036
|
+
this._amazonApiKey = value;
|
|
2037
|
+
}
|
|
2038
|
+
},
|
|
2039
|
+
{
|
|
2040
|
+
className: "basemap-control-aws-region",
|
|
2041
|
+
type: "text",
|
|
2042
|
+
placeholder: "AWS region",
|
|
2043
|
+
ariaLabel: "AWS region",
|
|
2044
|
+
value: this._awsRegion,
|
|
2045
|
+
onInput: (value) => {
|
|
2046
|
+
this._awsRegion = value;
|
|
2047
|
+
}
|
|
1942
2048
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
2049
|
+
]
|
|
2050
|
+
}
|
|
2051
|
+
];
|
|
2052
|
+
}
|
|
2053
|
+
// The dedicated API-keys view, opened from the header key button. It collects
|
|
2054
|
+
// every provider credential in one place, separate from the basemap list, so
|
|
2055
|
+
// the list itself stays free of input clutter (#837, Bug 5).
|
|
2056
|
+
_createSettingsView() {
|
|
2057
|
+
const view = document.createElement("div");
|
|
2058
|
+
view.className = "basemap-control-settings-view";
|
|
2059
|
+
const head = document.createElement("div");
|
|
2060
|
+
head.className = "basemap-control-settings-head";
|
|
2061
|
+
const back = document.createElement("button");
|
|
2062
|
+
back.type = "button";
|
|
2063
|
+
back.className = "basemap-control-settings-back";
|
|
2064
|
+
back.setAttribute("aria-label", "Back to basemaps");
|
|
2065
|
+
back.innerHTML = `
|
|
2066
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
2067
|
+
<path d="m15 18-6-6 6-6"/>
|
|
2068
|
+
</svg>
|
|
2069
|
+
<span>Basemaps</span>
|
|
2070
|
+
`;
|
|
2071
|
+
back.addEventListener("click", () => this._toggleSettingsView());
|
|
2072
|
+
const heading = document.createElement("span");
|
|
2073
|
+
heading.className = "basemap-control-settings-heading";
|
|
2074
|
+
heading.textContent = "API keys";
|
|
2075
|
+
head.appendChild(back);
|
|
2076
|
+
head.appendChild(heading);
|
|
2077
|
+
view.appendChild(head);
|
|
2078
|
+
const intro = document.createElement("p");
|
|
2079
|
+
intro.className = "basemap-control-settings-intro";
|
|
2080
|
+
intro.textContent = "Add the credentials each provider requires to use its basemaps.";
|
|
2081
|
+
view.appendChild(intro);
|
|
2082
|
+
const fields = document.createElement("div");
|
|
2083
|
+
fields.className = "basemap-control-provider-settings-fields";
|
|
2084
|
+
for (const def of this._providerFieldDefs()) {
|
|
2085
|
+
if (def.has) fields.appendChild(this._createProviderFieldGroup(def));
|
|
2086
|
+
}
|
|
2087
|
+
view.appendChild(fields);
|
|
2088
|
+
return view;
|
|
2089
|
+
}
|
|
2090
|
+
_createProviderFieldGroup(def) {
|
|
2091
|
+
const group = document.createElement("div");
|
|
2092
|
+
group.className = `basemap-control-provider-group basemap-control-provider-group-${def.provider}`;
|
|
2093
|
+
const label = document.createElement("span");
|
|
2094
|
+
label.className = "basemap-control-provider-group-label";
|
|
2095
|
+
label.textContent = def.label;
|
|
2096
|
+
group.appendChild(label);
|
|
2097
|
+
for (const field of def.fields) {
|
|
2098
|
+
group.appendChild(this._createProviderSettingsInput(field));
|
|
2099
|
+
}
|
|
2100
|
+
return group;
|
|
2101
|
+
}
|
|
2102
|
+
// Renders the credential field(s) for the provider of the active
|
|
2103
|
+
// missing-credential error, inline beside the error message. Only that one
|
|
2104
|
+
// provider is shown, so the user is not asked to wade through every other
|
|
2105
|
+
// provider's inputs (#837, Bug 3). Returns null when no such error is active.
|
|
2106
|
+
_createInlineCredentialFields() {
|
|
2107
|
+
if (!this._state.error || !this._missingCredentialProvider) return null;
|
|
2108
|
+
const def = this._providerFieldDefs().find(
|
|
2109
|
+
(candidate) => candidate.provider === this._missingCredentialProvider && candidate.has
|
|
2110
|
+
);
|
|
2111
|
+
if (!def) return null;
|
|
2112
|
+
const wrapper = document.createElement("div");
|
|
2113
|
+
wrapper.className = "basemap-control-status-fields";
|
|
2114
|
+
for (const field of def.fields) {
|
|
2115
|
+
wrapper.appendChild(
|
|
1946
2116
|
this._createProviderSettingsInput({
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
}
|
|
2117
|
+
...field,
|
|
2118
|
+
// Keep the error (and this field) on screen while the user types, and
|
|
2119
|
+
// let Enter re-attempt the basemap that failed, so the field is not
|
|
2120
|
+
// yanked out from under the cursor on the first keystroke.
|
|
2121
|
+
rerenderOnInput: false,
|
|
2122
|
+
clearErrorOnInput: false,
|
|
2123
|
+
onEnter: () => this._retryLastFailedBasemap()
|
|
1955
2124
|
})
|
|
1956
2125
|
);
|
|
1957
2126
|
}
|
|
1958
|
-
|
|
1959
|
-
|
|
2127
|
+
return wrapper;
|
|
2128
|
+
}
|
|
2129
|
+
_retryLastFailedBasemap() {
|
|
2130
|
+
if (this._lastFailedBasemapId) this._selectBasemap(this._lastFailedBasemapId);
|
|
1960
2131
|
}
|
|
1961
2132
|
_createProviderSettingsInput({
|
|
1962
2133
|
className,
|
|
@@ -1964,7 +2135,10 @@ class BasemapControl {
|
|
|
1964
2135
|
placeholder,
|
|
1965
2136
|
ariaLabel,
|
|
1966
2137
|
value,
|
|
1967
|
-
onInput
|
|
2138
|
+
onInput,
|
|
2139
|
+
rerenderOnInput = true,
|
|
2140
|
+
clearErrorOnInput = true,
|
|
2141
|
+
onEnter
|
|
1968
2142
|
}) {
|
|
1969
2143
|
const wrapper = document.createElement("div");
|
|
1970
2144
|
wrapper.className = className;
|
|
@@ -1981,10 +2155,18 @@ class BasemapControl {
|
|
|
1981
2155
|
input.setAttribute("aria-label", ariaLabel);
|
|
1982
2156
|
input.addEventListener("input", () => {
|
|
1983
2157
|
onInput(input.value);
|
|
1984
|
-
|
|
1985
|
-
this._renderFilteredResults();
|
|
2158
|
+
if (clearErrorOnInput) this._clearError();
|
|
2159
|
+
if (rerenderOnInput) this._renderFilteredResults();
|
|
1986
2160
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1987
2161
|
});
|
|
2162
|
+
if (onEnter) {
|
|
2163
|
+
input.addEventListener("keydown", (event) => {
|
|
2164
|
+
if (event.key === "Enter") {
|
|
2165
|
+
event.preventDefault();
|
|
2166
|
+
onEnter();
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
2169
|
+
}
|
|
1988
2170
|
wrapper.appendChild(input);
|
|
1989
2171
|
return wrapper;
|
|
1990
2172
|
}
|
|
@@ -1998,6 +2180,7 @@ class BasemapControl {
|
|
|
1998
2180
|
providers.map((provider) => ({ value: provider.id, label: provider.name })),
|
|
1999
2181
|
(value) => {
|
|
2000
2182
|
this._state = { ...this._state, providerFilter: value };
|
|
2183
|
+
this._clearError();
|
|
2001
2184
|
this._renderContent();
|
|
2002
2185
|
this._emit({ type: "statechange", state: this.getState() });
|
|
2003
2186
|
}
|
|
@@ -2010,6 +2193,7 @@ class BasemapControl {
|
|
|
2010
2193
|
categories.map((category) => ({ value: category, label: category })),
|
|
2011
2194
|
(value) => {
|
|
2012
2195
|
this._state = { ...this._state, categoryFilter: value };
|
|
2196
|
+
this._clearError();
|
|
2013
2197
|
this._renderContent();
|
|
2014
2198
|
this._emit({ type: "statechange", state: this.getState() });
|
|
2015
2199
|
}
|
|
@@ -2059,10 +2243,12 @@ class BasemapControl {
|
|
|
2059
2243
|
actions.appendChild(link);
|
|
2060
2244
|
const hint = document.createElement("span");
|
|
2061
2245
|
hint.className = "basemap-control-status-hint";
|
|
2062
|
-
hint.textContent = ", then
|
|
2246
|
+
hint.textContent = ", then enter it below and press Enter.";
|
|
2063
2247
|
actions.appendChild(hint);
|
|
2064
2248
|
status.appendChild(actions);
|
|
2065
2249
|
}
|
|
2250
|
+
const inlineFields = this._createInlineCredentialFields();
|
|
2251
|
+
if (inlineFields) status.appendChild(inlineFields);
|
|
2066
2252
|
} else {
|
|
2067
2253
|
status.textContent = `${resultCount} basemap${resultCount === 1 ? "" : "s"}`;
|
|
2068
2254
|
}
|
|
@@ -2635,4 +2821,4 @@ export {
|
|
|
2635
2821
|
getBasemapCategories as g,
|
|
2636
2822
|
resolveBasemapProviders as r
|
|
2637
2823
|
};
|
|
2638
|
-
//# sourceMappingURL=BasemapControl-
|
|
2824
|
+
//# sourceMappingURL=BasemapControl-C9T87uJx.js.map
|