@countriesdb/widget 0.1.20 → 0.1.21

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.
@@ -23,7 +23,7 @@ export declare function applyPreselectedValue(select: SelectElement, apiKey?: st
23
23
  /**
24
24
  * Handle API error by showing error message in select
25
25
  */
26
- export declare function handleApiError(select: SelectElement, errorMessage: string | Error): void;
26
+ export declare function handleApiError(select: SelectElement, errorMessage: string | Error, replace?: boolean): void;
27
27
  /**
28
28
  * Parse boolean from string value
29
29
  */
@@ -142,12 +142,19 @@ export function applyPreselectedValue(select, apiKey) {
142
142
  /**
143
143
  * Handle API error by showing error message in select
144
144
  */
145
- export function handleApiError(select, errorMessage) {
145
+ export function handleApiError(select, errorMessage, replace = false) {
146
146
  const message = errorMessage instanceof Error ? errorMessage.message : errorMessage;
147
147
  const defaultValue = select.dataset.defaultValue ?? '';
148
148
  // Add "Error: " prefix to match old widget behavior and test expectations
149
149
  const formattedMessage = message.startsWith('Error: ') ? message : `Error: ${message}`;
150
- select.innerHTML += `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
150
+ if (replace) {
151
+ select.innerHTML = `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
152
+ }
153
+ else {
154
+ select.innerHTML += `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
155
+ }
156
+ // Ensure select is enabled so users can see the error
157
+ select.disabled = false;
151
158
  }
152
159
  /**
153
160
  * Parse boolean from string value
package/dist/index.esm.js CHANGED
@@ -143,12 +143,19 @@ function applyPreselectedValue(select, apiKey) {
143
143
  /**
144
144
  * Handle API error by showing error message in select
145
145
  */
146
- function handleApiError(select, errorMessage) {
146
+ function handleApiError(select, errorMessage, replace = false) {
147
147
  const message = errorMessage instanceof Error ? errorMessage.message : errorMessage;
148
148
  const defaultValue = select.dataset.defaultValue ?? '';
149
149
  // Add "Error: " prefix to match old widget behavior and test expectations
150
150
  const formattedMessage = message.startsWith('Error: ') ? message : `Error: ${message}`;
151
- select.innerHTML += `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
151
+ if (replace) {
152
+ select.innerHTML = `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
153
+ }
154
+ else {
155
+ select.innerHTML += `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
156
+ }
157
+ // Ensure select is enabled so users can see the error
158
+ select.disabled = false;
152
159
  }
153
160
 
154
161
  /**
@@ -458,8 +465,7 @@ async function setupSubdivisionSelection(apiKey, backendUrl, state, config) {
458
465
  : null;
459
466
  // Check if linked country select is multi-select (not allowed)
460
467
  if (linkedCountrySelect && linkedCountrySelect.hasAttribute('multiple')) {
461
- const defaultValue = select.dataset.defaultValue ?? '';
462
- select.innerHTML = `<option value="${defaultValue}" disabled>Error: Cannot link to multi-select country. Use data-country-code instead.</option>`;
468
+ handleApiError(select, 'Cannot link to multi-select country. Use data-country-code instead.', true);
463
469
  continue;
464
470
  }
465
471
  // No direct link → maybe data-country-code
@@ -469,8 +475,7 @@ async function setupSubdivisionSelection(apiKey, backendUrl, state, config) {
469
475
  await updateSubdivisionSelect(select, apiKey, backendUrl, state, config, select.dataset.countryCode);
470
476
  }
471
477
  else {
472
- const defaultValue = select.dataset.defaultValue ?? '';
473
- select.innerHTML += `<option value="${defaultValue}" disabled>Error: No country select present</option>`;
478
+ handleApiError(select, 'No country select present');
474
479
  }
475
480
  }
476
481
  // Always dispatch an update event for user-initiated subdivision changes
@@ -516,7 +521,8 @@ async function updateSubdivisionSelect(select, apiKey, backendUrl, state, config
516
521
  // Use GeoIP only if data-preselected attribute is not set at all
517
522
  const shouldUseGeoIP = preselectedValue === undefined || preselectedValue === null;
518
523
  // Check if this subdivision select prefers official subdivisions
519
- const preferOfficial = select.hasAttribute('data-prefer-official');
524
+ const preferOfficial = select.hasAttribute('data-prefer-official') ||
525
+ config.preferOfficialSubdivisions;
520
526
  const languageHeaders = CountriesDBClient.getLanguageHeaders(config.forcedLanguage, config.defaultLanguage);
521
527
  const subdivisionsResult = await CountriesDBClient.fetchSubdivisions({
522
528
  apiKey,
@@ -613,8 +619,7 @@ async function updateSubdivisionSelect(select, apiKey, backendUrl, state, config
613
619
  }
614
620
  else if (!select.dataset.country ||
615
621
  !document.querySelector(`.country-selection[data-name="${select.dataset.country}"]`)) {
616
- const defaultValue = select.dataset.defaultValue ?? '';
617
- select.innerHTML += `<option value="${defaultValue}" disabled>Error: No country select present</option>`;
622
+ handleApiError(select, 'No country select present');
618
623
  }
619
624
  }
620
625
  /**
@@ -643,8 +648,7 @@ async function setupCountrySelection(apiKey, backendUrl, state, config, subdivis
643
648
  if (name && seenNames[name]) {
644
649
  select.removeAttribute('data-name');
645
650
  initializeSelect(select, '&mdash;');
646
- const defaultValue = select.dataset.defaultValue ?? '';
647
- select.innerHTML += `<option value="${defaultValue}" disabled>Error: Duplicate field</option>`;
651
+ handleApiError(select, 'Duplicate field');
648
652
  continue;
649
653
  }
650
654
  if (name) {
@@ -808,6 +812,7 @@ async function CountriesWidgetLoad(options = {}) {
808
812
  followUpward: config.followUpward || false,
809
813
  showSubdivisionType: config.showSubdivisionType !== false,
810
814
  allowParentSelection: config.allowParentSelection || false,
815
+ preferOfficialSubdivisions: config.preferOfficialSubdivisions || false,
811
816
  subdivisionRomanizationPreference: config.subdivisionRomanizationPreference,
812
817
  preferLocalVariant: config.preferLocalVariant || false,
813
818
  subdivisionNameFilter: config.subdivisionNameFilter,
@@ -817,6 +822,7 @@ async function CountriesWidgetLoad(options = {}) {
817
822
  followUpward: config.followUpward || false,
818
823
  showSubdivisionType: config.showSubdivisionType !== false,
819
824
  allowParentSelection: config.allowParentSelection || false,
825
+ preferOfficialSubdivisions: config.preferOfficialSubdivisions || false,
820
826
  subdivisionRomanizationPreference: config.subdivisionRomanizationPreference,
821
827
  preferLocalVariant: config.preferLocalVariant || false,
822
828
  forcedLanguage: config.forcedLanguage,
@@ -888,30 +894,50 @@ function getConfigFromOptionsOrScript(options) {
888
894
  forcedLanguage: options.forcedLanguage ?? globalConfig?.forcedLanguage ?? scriptUrl?.searchParams.get('forced_language') ?? undefined,
889
895
  showSubdivisionType: options.showSubdivisionType !== undefined
890
896
  ? options.showSubdivisionType
891
- : parseBoolean(scriptUrl?.searchParams.get('show_subdivision_type') ?? '1'),
897
+ : globalConfig?.showSubdivisionType !== undefined
898
+ ? globalConfig.showSubdivisionType
899
+ : parseBoolean(scriptUrl?.searchParams.get('show_subdivision_type') ?? '1'),
892
900
  followRelated: options.followRelated !== undefined
893
901
  ? options.followRelated
894
- : parseBoolean(scriptUrl?.searchParams.get('follow_related') ?? 'false'),
902
+ : globalConfig?.followRelated !== undefined
903
+ ? globalConfig.followRelated
904
+ : parseBoolean(scriptUrl?.searchParams.get('follow_related') ?? 'false'),
895
905
  followUpward: options.followUpward !== undefined
896
906
  ? options.followUpward
897
- : parseBoolean(scriptUrl?.searchParams.get('follow_upward') ?? 'false'),
907
+ : globalConfig?.followUpward !== undefined
908
+ ? globalConfig.followUpward
909
+ : parseBoolean(scriptUrl?.searchParams.get('follow_upward') ?? 'false'),
898
910
  allowParentSelection: options.allowParentSelection !== undefined
899
911
  ? options.allowParentSelection
900
- : parseBoolean(scriptUrl?.searchParams.get('allow_parent_selection') ?? 'false'),
912
+ : globalConfig?.allowParentSelection !== undefined
913
+ ? globalConfig.allowParentSelection
914
+ : parseBoolean(scriptUrl?.searchParams.get('allow_parent_selection') ?? 'false'),
901
915
  isoCountryNames: options.isoCountryNames !== undefined
902
916
  ? options.isoCountryNames
903
- : parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
917
+ : globalConfig?.isoCountryNames !== undefined
918
+ ? globalConfig.isoCountryNames
919
+ : parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
920
+ preferOfficialSubdivisions: options.preferOfficialSubdivisions !== undefined
921
+ ? options.preferOfficialSubdivisions
922
+ : globalConfig?.preferOfficialSubdivisions !== undefined
923
+ ? globalConfig.preferOfficialSubdivisions
924
+ : parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
904
925
  subdivisionRomanizationPreference: options.subdivisionRomanizationPreference ||
926
+ globalConfig?.subdivisionRomanizationPreference ||
905
927
  scriptUrl?.searchParams.get('subdivision_romanization_preference') ||
906
928
  undefined,
907
929
  preferLocalVariant: options.preferLocalVariant !== undefined
908
930
  ? options.preferLocalVariant
909
- : parseBoolean(scriptUrl?.searchParams.get('prefer_local_variant') ?? 'false'),
910
- countryNameFilter: options.countryNameFilter,
911
- subdivisionNameFilter: options.subdivisionNameFilter,
931
+ : globalConfig?.preferLocalVariant !== undefined
932
+ ? globalConfig.preferLocalVariant
933
+ : parseBoolean(scriptUrl?.searchParams.get('prefer_local_variant') ?? 'false'),
934
+ countryNameFilter: options.countryNameFilter ?? globalConfig?.countryNameFilter,
935
+ subdivisionNameFilter: options.subdivisionNameFilter ?? globalConfig?.subdivisionNameFilter,
912
936
  autoInit: options.autoInit !== undefined
913
937
  ? options.autoInit
914
- : parseBoolean(scriptUrl?.searchParams.get('auto_init') ?? 'true'),
938
+ : globalConfig?.autoInit !== undefined
939
+ ? globalConfig.autoInit
940
+ : parseBoolean(scriptUrl?.searchParams.get('auto_init') ?? 'true'),
915
941
  };
916
942
  // Resolve filter functions from global scope if specified by name
917
943
  if (scriptUrl) {
@@ -1011,14 +1037,14 @@ function parseBoolean(value) {
1011
1037
  * Show error when both follow_related and follow_upward are enabled
1012
1038
  */
1013
1039
  function showParamConflictError() {
1014
- const errorMessage = 'Error: Cannot enable both follow_related and follow_upward';
1040
+ const errorMessage = 'Cannot enable both follow_related and follow_upward';
1015
1041
  const countrySelects = Array.from(document.querySelectorAll('.country-selection'));
1016
1042
  for (const select of countrySelects) {
1017
- select.innerHTML = `<option value="${select.dataset.defaultValue ?? ''}" disabled>${errorMessage}</option>`;
1043
+ handleApiError(select, errorMessage, true);
1018
1044
  }
1019
1045
  const subdivisionSelects = Array.from(document.querySelectorAll('.subdivision-selection'));
1020
1046
  for (const select of subdivisionSelects) {
1021
- select.innerHTML = `<option value="${select.dataset.defaultValue ?? ''}" disabled>${errorMessage}</option>`;
1047
+ handleApiError(select, errorMessage, true);
1022
1048
  }
1023
1049
  }
1024
1050
  // Expose public loader