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 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 collapsible provider settings section in the control panel, or you
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
- __publicField(this, "_providerSettingsCollapsed", true);
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. Kept in sync with `_state.error` (both are set together
1322
- // in `_applyBasemapChange`'s catch) so it is never stale when consulted.
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._state = { ...this._state, error: void 0 };
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._state = { ...this._state, error: void 0 };
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._state = { ...this._state, error: void 0 };
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._state = { ...this._state, error: void 0 };
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._state = { ...this._state, error: void 0 };
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._state = { ...this._state, error: void 0 };
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
- this._state = { ...this._state, loading: false, error: error.message };
1625
- this._missingCredentialProvider = cause instanceof MissingCredentialError ? cause.provider : void 0;
1626
- if (cause instanceof MissingCredentialError) {
1627
- this._providerSettingsCollapsed = false;
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 = "&times;";
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._renderFilteredResults();
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
- _createProviderSettingsSection() {
1849
- const details = document.createElement("details");
1850
- details.className = "basemap-control-provider-settings";
1851
- details.open = !this._providerSettingsCollapsed;
1852
- details.addEventListener("toggle", () => {
1853
- this._providerSettingsCollapsed = !details.open;
1854
- });
1855
- const summary = document.createElement("summary");
1856
- summary.className = "basemap-control-provider-settings-summary";
1857
- summary.textContent = "Provider settings";
1858
- details.appendChild(summary);
1859
- const fields = document.createElement("div");
1860
- fields.className = "basemap-control-provider-settings-fields";
1861
- if (this._hasMapTilerBasemaps()) {
1862
- fields.appendChild(
1863
- this._createProviderSettingsInput({
1864
- className: "basemap-control-maptiler-key",
1865
- type: "password",
1866
- placeholder: "MapTiler API key",
1867
- ariaLabel: "MapTiler API key",
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
- if (this._hasMapboxBasemaps()) {
1876
- fields.appendChild(
1877
- this._createProviderSettingsInput({
1878
- className: "basemap-control-mapbox-token",
1879
- type: "password",
1880
- placeholder: "Mapbox access token",
1881
- ariaLabel: "Mapbox access token",
1882
- value: this._mapboxAccessToken,
1883
- onInput: (value) => {
1884
- this._mapboxAccessToken = value;
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
- if (this._hasTomTomBasemaps()) {
1890
- fields.appendChild(
1891
- this._createProviderSettingsInput({
1892
- className: "basemap-control-tomtom-key",
1893
- type: "password",
1894
- placeholder: "TomTom API key",
1895
- ariaLabel: "TomTom API key",
1896
- value: this._tomtomApiKey,
1897
- onInput: (value) => {
1898
- this._tomtomApiKey = value;
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
- if (this._hasHereBasemaps()) {
1904
- fields.appendChild(
1905
- this._createProviderSettingsInput({
1906
- className: "basemap-control-here-key",
1907
- type: "password",
1908
- placeholder: "HERE API key",
1909
- ariaLabel: "HERE API key",
1910
- value: this._hereApiKey,
1911
- onInput: (value) => {
1912
- this._hereApiKey = value;
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
- if (this._hasGoogleApiKeyBasemaps()) {
1918
- fields.appendChild(
1919
- this._createProviderSettingsInput({
1920
- className: "basemap-control-google-key",
1921
- type: "password",
1922
- placeholder: "Google Maps API key",
1923
- ariaLabel: "Google Maps API key",
1924
- value: this._googleMapsApiKey,
1925
- onInput: (value) => {
1926
- this._googleMapsApiKey = value;
1927
- this._googleSessions.clear();
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
- if (this._hasAmazonBasemaps()) {
1933
- fields.appendChild(
1934
- this._createProviderSettingsInput({
1935
- className: "basemap-control-amazon-key",
1936
- type: "password",
1937
- placeholder: "Amazon API key",
1938
- ariaLabel: "Amazon API key",
1939
- value: this._amazonApiKey,
1940
- onInput: (value) => {
1941
- this._amazonApiKey = value;
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
- fields.appendChild(
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
- className: "basemap-control-aws-region",
1948
- type: "text",
1949
- placeholder: "AWS region",
1950
- ariaLabel: "AWS region",
1951
- value: this._awsRegion,
1952
- onInput: (value) => {
1953
- this._awsRegion = value;
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
- details.appendChild(fields);
1959
- return details;
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
- this._state = { ...this._state, error: void 0 };
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 add it under Provider settings below.";
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-CfFepxWc.js.map
2824
+ //# sourceMappingURL=BasemapControl-C9T87uJx.js.map