diff --git a/package-lock.json b/package-lock.json
index f96bd8a3a5e..89f917c0578 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32981,12 +32981,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/timezone-groups": {
- "version": "0.8.0",
- "bin": {
- "timezone-groups": "dist/cli.cjs"
- }
- },
"node_modules/timm": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz",
@@ -35894,7 +35888,7 @@
"focus-trap": "7.5.4",
"lodash-es": "4.17.21",
"sortablejs": "1.15.1",
- "timezone-groups": "0.8.0",
+ "timezone-groups": "0.9.0",
"type-fest": "4.18.2"
},
"devDependencies": {
@@ -39466,6 +39460,14 @@
"node": ">=8"
}
},
+ "packages/calcite-components/node_modules/timezone-groups": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/timezone-groups/-/timezone-groups-0.9.0.tgz",
+ "integrity": "sha512-6Os7VhGet5ZU5q7Sx5hxzyzyym5+IfVax5m6LBz1LqZGshlcDRykYyyD4j7yhN1yn/jjw4eJpd8KpzyPWKU+nQ==",
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
"packages/calcite-components/node_modules/type-fest": {
"version": "4.18.2",
"license": "(MIT OR CC0-1.0)",
diff --git a/packages/calcite-components/package.json b/packages/calcite-components/package.json
index 170a52ab6fb..36092cf27c5 100644
--- a/packages/calcite-components/package.json
+++ b/packages/calcite-components/package.json
@@ -72,7 +72,7 @@
"focus-trap": "7.5.4",
"lodash-es": "4.17.21",
"sortablejs": "1.15.1",
- "timezone-groups": "0.8.0",
+ "timezone-groups": "0.9.0",
"type-fest": "4.18.2"
},
"devDependencies": {
diff --git a/packages/calcite-components/src/components/input-time-zone/assets/input-time-zone/t9n/messages.json b/packages/calcite-components/src/components/input-time-zone/assets/input-time-zone/t9n/messages.json
index 93a716c624d..378072b74f4 100644
--- a/packages/calcite-components/src/components/input-time-zone/assets/input-time-zone/t9n/messages.json
+++ b/packages/calcite-components/src/components/input-time-zone/assets/input-time-zone/t9n/messages.json
@@ -1,6 +1,7 @@
{
"chooseTimeZone": "Choose time zone.",
"offsetPlaceholder": "Search by city, region or offset",
+ "regionPlaceholder": "Search by city, country, region or offset",
"namePlaceholder": "Search by time zone",
"timeZoneLabel": "({offset}) {cities}",
"Africa/Abidjan": "Abidjan",
@@ -431,5 +432,254 @@
"Pacific/Tongatapu": "Tongatapu",
"Pacific/Truk": "Truk",
"Pacific/Wake": "Wake",
- "Pacific/Wallis": "Wallis"
+ "Pacific/Wallis": "Wallis",
+ "AD": "Andorra",
+ "AE": "United Arab Emirates",
+ "AF": "Afghanistan",
+ "AG": "Antigua and Barbuda",
+ "AI": "Anguilla",
+ "AL": "Albania",
+ "AM": "Armenia",
+ "AO": "Angola",
+ "AQ": "Antarctica",
+ "AR": "Argentina",
+ "AS": "American Samoa",
+ "AT": "Austria",
+ "AU": "Australia",
+ "AW": "Aruba",
+ "AX": "Åland Islands",
+ "AZ": "Azerbaijan",
+ "BA": "Bosnia and Herzegovina",
+ "BB": "Barbados",
+ "BD": "Bangladesh",
+ "BE": "Belgium",
+ "BF": "Burkina Faso",
+ "BG": "Bulgaria",
+ "BH": "Bahrain",
+ "BI": "Burundi",
+ "BJ": "Benin",
+ "BL": "Saint Barthélemy",
+ "BM": "Bermuda",
+ "BN": "Brunei",
+ "BO": "Bolivia",
+ "BQ": "Bonaire, Sint Eustatius and Saba",
+ "BR": "Brazil",
+ "BS": "Bahamas",
+ "BT": "Bhutan",
+ "BV": "Bouvet Island",
+ "BW": "Botswana",
+ "BY": "Belarus",
+ "BZ": "Belize",
+ "CA": "Canada",
+ "CC": "Cocos (Keeling) Islands",
+ "CD": "Democratic Republic of the Congo",
+ "CF": "Central African Republic",
+ "CG": "Republic of the Congo",
+ "CH": "Switzerland",
+ "CI": "Côte d'Ivoire",
+ "CK": "Cook Islands",
+ "CL": "Chile",
+ "CM": "Cameroon",
+ "CN": "China",
+ "CO": "Colombia",
+ "CR": "Costa Rica",
+ "CU": "Cuba",
+ "CV": "Cape Verde",
+ "CW": "Curaçao",
+ "CX": "Christmas Island",
+ "CY": "Cyprus",
+ "CZ": "Czech Republic",
+ "DE": "Germany",
+ "DJ": "Djibouti",
+ "DK": "Denmark",
+ "DM": "Dominica",
+ "DO": "Dominican Republic",
+ "DZ": "Algeria",
+ "EC": "Ecuador",
+ "EE": "Estonia",
+ "EG": "Egypt",
+ "EH": "Western Sahara",
+ "ER": "Eritrea",
+ "ES": "Spain",
+ "ET": "Ethiopia",
+ "FI": "Finland",
+ "FJ": "Fiji",
+ "FK": "Falkland Islands",
+ "FM": "Micronesia",
+ "FO": "Faroe Islands",
+ "FR": "France",
+ "GA": "Gabon",
+ "GB": "United Kingdom",
+ "GD": "Grenada",
+ "GE": "Georgia",
+ "GF": "French Guiana",
+ "GG": "Guernsey",
+ "GH": "Ghana",
+ "GI": "Gibraltar",
+ "GL": "Greenland",
+ "GM": "Gambia",
+ "GN": "Guinea",
+ "GP": "Guadeloupe",
+ "GQ": "Equatorial Guinea",
+ "GR": "Greece",
+ "GS": "South Georgia and the South Sandwich Islands",
+ "GT": "Guatemala",
+ "GU": "Guam",
+ "GW": "Guinea-Bissau",
+ "GY": "Guyana",
+ "HK": "Hong Kong",
+ "HM": "Heard Island and McDonald Islands",
+ "HN": "Honduras",
+ "HR": "Croatia",
+ "HT": "Haiti",
+ "HU": "Hungary",
+ "ID": "Indonesia",
+ "IE": "Ireland",
+ "IL": "Israel",
+ "IM": "Isle of Man",
+ "IN": "India",
+ "IO": "British Indian Ocean Territory",
+ "IQ": "Iraq",
+ "IR": "Iran",
+ "IS": "Iceland",
+ "IT": "Italy",
+ "JE": "Jersey",
+ "JM": "Jamaica",
+ "JO": "Jordan",
+ "JP": "Japan",
+ "KE": "Kenya",
+ "KG": "Kyrgyzstan",
+ "KH": "Cambodia",
+ "KI": "Kiribati",
+ "KM": "Comoros",
+ "KN": "Saint Kitts and Nevis",
+ "KP": "North Korea",
+ "KR": "South Korea",
+ "KW": "Kuwait",
+ "KY": "Cayman Islands",
+ "KZ": "Kazakhstan",
+ "LA": "Laos",
+ "LB": "Lebanon",
+ "LC": "Saint Lucia",
+ "LI": "Liechtenstein",
+ "LK": "Sri Lanka",
+ "LR": "Liberia",
+ "LS": "Lesotho",
+ "LT": "Lithuania",
+ "LU": "Luxembourg",
+ "LV": "Latvia",
+ "LY": "Libya",
+ "MA": "Morocco",
+ "MC": "Monaco",
+ "MD": "Moldova",
+ "ME": "Montenegro",
+ "MF": "Saint Martin",
+ "MG": "Madagascar",
+ "MH": "Marshall Islands",
+ "MK": "North Macedonia",
+ "ML": "Mali",
+ "MM": "Myanmar",
+ "MN": "Mongolia",
+ "MO": "Macau",
+ "MP": "Northern Mariana Islands",
+ "MQ": "Martinique",
+ "MR": "Mauritania",
+ "MS": "Montserrat",
+ "MT": "Malta",
+ "MU": "Mauritius",
+ "MV": "Maldives",
+ "MW": "Malawi",
+ "MX": "Mexico",
+ "MY": "Malaysia",
+ "MZ": "Mozambique",
+ "NA": "Namibia",
+ "NC": "New Caledonia",
+ "NE": "Niger",
+ "NF": "Norfolk Island",
+ "NG": "Nigeria",
+ "NI": "Nicaragua",
+ "NL": "Netherlands",
+ "NO": "Norway",
+ "NP": "Nepal",
+ "NR": "Nauru",
+ "NU": "Niue",
+ "NZ": "New Zealand",
+ "OM": "Oman",
+ "PA": "Panama",
+ "PE": "Peru",
+ "PF": "French Polynesia",
+ "PG": "Papua New Guinea",
+ "PH": "Philippines",
+ "PK": "Pakistan",
+ "PL": "Poland",
+ "PM": "Saint Pierre and Miquelon",
+ "PN": "Pitcairn Islands",
+ "PR": "Puerto Rico",
+ "PS": "Palestine",
+ "PT": "Portugal",
+ "PW": "Palau",
+ "PY": "Paraguay",
+ "QA": "Qatar",
+ "RE": "Réunion",
+ "RO": "Romania",
+ "RS": "Serbia",
+ "RU": "Russia",
+ "RW": "Rwanda",
+ "SA": "Saudi Arabia",
+ "SB": "Solomon Islands",
+ "SC": "Seychelles",
+ "SD": "Sudan",
+ "SE": "Sweden",
+ "SG": "Singapore",
+ "SH": "Saint Helena",
+ "SI": "Slovenia",
+ "SJ": "Svalbard and Jan Mayen",
+ "SK": "Slovakia",
+ "SL": "Sierra Leone",
+ "SM": "San Marino",
+ "SN": "Senegal",
+ "SO": "Somalia",
+ "SR": "Suriname",
+ "SS": "South Sudan",
+ "ST": "São Tomé and Príncipe",
+ "SV": "El Salvador",
+ "SX": "Sint Maarten",
+ "SY": "Syria",
+ "SZ": "Eswatini",
+ "TC": "Turks and Caicos Islands",
+ "TD": "Chad",
+ "TF": "French Southern Territories",
+ "TG": "Togo",
+ "TH": "Thailand",
+ "TJ": "Tajikistan",
+ "TK": "Tokelau",
+ "TL": "Timor-Leste",
+ "TM": "Turkmenistan",
+ "TN": "Tunisia",
+ "TO": "Tonga",
+ "TR": "Turkey",
+ "TT": "Trinidad and Tobago",
+ "TV": "Tuvalu",
+ "TW": "Taiwan",
+ "TZ": "Tanzania",
+ "UA": "Ukraine",
+ "UG": "Uganda",
+ "UM": "United States Minor Outlying Islands",
+ "US": "United States",
+ "UY": "Uruguay",
+ "UZ": "Uzbekistan",
+ "VA": "Vatican City",
+ "VC": "Saint Vincent and the Grenadines",
+ "VE": "Venezuela",
+ "VG": "British Virgin Islands",
+ "VI": "United States Virgin Islands",
+ "VN": "Vietnam",
+ "VU": "Vanuatu",
+ "WF": "Wallis and Futuna",
+ "WS": "Samoa",
+ "YE": "Yemen",
+ "YT": "Mayotte",
+ "ZA": "South Africa",
+ "ZM": "Zambia",
+ "ZW": "Zimbabwe"
}
diff --git a/packages/calcite-components/src/components/input-time-zone/assets/input-time-zone/t9n/messages_en.json b/packages/calcite-components/src/components/input-time-zone/assets/input-time-zone/t9n/messages_en.json
index 93a716c624d..378072b74f4 100644
--- a/packages/calcite-components/src/components/input-time-zone/assets/input-time-zone/t9n/messages_en.json
+++ b/packages/calcite-components/src/components/input-time-zone/assets/input-time-zone/t9n/messages_en.json
@@ -1,6 +1,7 @@
{
"chooseTimeZone": "Choose time zone.",
"offsetPlaceholder": "Search by city, region or offset",
+ "regionPlaceholder": "Search by city, country, region or offset",
"namePlaceholder": "Search by time zone",
"timeZoneLabel": "({offset}) {cities}",
"Africa/Abidjan": "Abidjan",
@@ -431,5 +432,254 @@
"Pacific/Tongatapu": "Tongatapu",
"Pacific/Truk": "Truk",
"Pacific/Wake": "Wake",
- "Pacific/Wallis": "Wallis"
+ "Pacific/Wallis": "Wallis",
+ "AD": "Andorra",
+ "AE": "United Arab Emirates",
+ "AF": "Afghanistan",
+ "AG": "Antigua and Barbuda",
+ "AI": "Anguilla",
+ "AL": "Albania",
+ "AM": "Armenia",
+ "AO": "Angola",
+ "AQ": "Antarctica",
+ "AR": "Argentina",
+ "AS": "American Samoa",
+ "AT": "Austria",
+ "AU": "Australia",
+ "AW": "Aruba",
+ "AX": "Åland Islands",
+ "AZ": "Azerbaijan",
+ "BA": "Bosnia and Herzegovina",
+ "BB": "Barbados",
+ "BD": "Bangladesh",
+ "BE": "Belgium",
+ "BF": "Burkina Faso",
+ "BG": "Bulgaria",
+ "BH": "Bahrain",
+ "BI": "Burundi",
+ "BJ": "Benin",
+ "BL": "Saint Barthélemy",
+ "BM": "Bermuda",
+ "BN": "Brunei",
+ "BO": "Bolivia",
+ "BQ": "Bonaire, Sint Eustatius and Saba",
+ "BR": "Brazil",
+ "BS": "Bahamas",
+ "BT": "Bhutan",
+ "BV": "Bouvet Island",
+ "BW": "Botswana",
+ "BY": "Belarus",
+ "BZ": "Belize",
+ "CA": "Canada",
+ "CC": "Cocos (Keeling) Islands",
+ "CD": "Democratic Republic of the Congo",
+ "CF": "Central African Republic",
+ "CG": "Republic of the Congo",
+ "CH": "Switzerland",
+ "CI": "Côte d'Ivoire",
+ "CK": "Cook Islands",
+ "CL": "Chile",
+ "CM": "Cameroon",
+ "CN": "China",
+ "CO": "Colombia",
+ "CR": "Costa Rica",
+ "CU": "Cuba",
+ "CV": "Cape Verde",
+ "CW": "Curaçao",
+ "CX": "Christmas Island",
+ "CY": "Cyprus",
+ "CZ": "Czech Republic",
+ "DE": "Germany",
+ "DJ": "Djibouti",
+ "DK": "Denmark",
+ "DM": "Dominica",
+ "DO": "Dominican Republic",
+ "DZ": "Algeria",
+ "EC": "Ecuador",
+ "EE": "Estonia",
+ "EG": "Egypt",
+ "EH": "Western Sahara",
+ "ER": "Eritrea",
+ "ES": "Spain",
+ "ET": "Ethiopia",
+ "FI": "Finland",
+ "FJ": "Fiji",
+ "FK": "Falkland Islands",
+ "FM": "Micronesia",
+ "FO": "Faroe Islands",
+ "FR": "France",
+ "GA": "Gabon",
+ "GB": "United Kingdom",
+ "GD": "Grenada",
+ "GE": "Georgia",
+ "GF": "French Guiana",
+ "GG": "Guernsey",
+ "GH": "Ghana",
+ "GI": "Gibraltar",
+ "GL": "Greenland",
+ "GM": "Gambia",
+ "GN": "Guinea",
+ "GP": "Guadeloupe",
+ "GQ": "Equatorial Guinea",
+ "GR": "Greece",
+ "GS": "South Georgia and the South Sandwich Islands",
+ "GT": "Guatemala",
+ "GU": "Guam",
+ "GW": "Guinea-Bissau",
+ "GY": "Guyana",
+ "HK": "Hong Kong",
+ "HM": "Heard Island and McDonald Islands",
+ "HN": "Honduras",
+ "HR": "Croatia",
+ "HT": "Haiti",
+ "HU": "Hungary",
+ "ID": "Indonesia",
+ "IE": "Ireland",
+ "IL": "Israel",
+ "IM": "Isle of Man",
+ "IN": "India",
+ "IO": "British Indian Ocean Territory",
+ "IQ": "Iraq",
+ "IR": "Iran",
+ "IS": "Iceland",
+ "IT": "Italy",
+ "JE": "Jersey",
+ "JM": "Jamaica",
+ "JO": "Jordan",
+ "JP": "Japan",
+ "KE": "Kenya",
+ "KG": "Kyrgyzstan",
+ "KH": "Cambodia",
+ "KI": "Kiribati",
+ "KM": "Comoros",
+ "KN": "Saint Kitts and Nevis",
+ "KP": "North Korea",
+ "KR": "South Korea",
+ "KW": "Kuwait",
+ "KY": "Cayman Islands",
+ "KZ": "Kazakhstan",
+ "LA": "Laos",
+ "LB": "Lebanon",
+ "LC": "Saint Lucia",
+ "LI": "Liechtenstein",
+ "LK": "Sri Lanka",
+ "LR": "Liberia",
+ "LS": "Lesotho",
+ "LT": "Lithuania",
+ "LU": "Luxembourg",
+ "LV": "Latvia",
+ "LY": "Libya",
+ "MA": "Morocco",
+ "MC": "Monaco",
+ "MD": "Moldova",
+ "ME": "Montenegro",
+ "MF": "Saint Martin",
+ "MG": "Madagascar",
+ "MH": "Marshall Islands",
+ "MK": "North Macedonia",
+ "ML": "Mali",
+ "MM": "Myanmar",
+ "MN": "Mongolia",
+ "MO": "Macau",
+ "MP": "Northern Mariana Islands",
+ "MQ": "Martinique",
+ "MR": "Mauritania",
+ "MS": "Montserrat",
+ "MT": "Malta",
+ "MU": "Mauritius",
+ "MV": "Maldives",
+ "MW": "Malawi",
+ "MX": "Mexico",
+ "MY": "Malaysia",
+ "MZ": "Mozambique",
+ "NA": "Namibia",
+ "NC": "New Caledonia",
+ "NE": "Niger",
+ "NF": "Norfolk Island",
+ "NG": "Nigeria",
+ "NI": "Nicaragua",
+ "NL": "Netherlands",
+ "NO": "Norway",
+ "NP": "Nepal",
+ "NR": "Nauru",
+ "NU": "Niue",
+ "NZ": "New Zealand",
+ "OM": "Oman",
+ "PA": "Panama",
+ "PE": "Peru",
+ "PF": "French Polynesia",
+ "PG": "Papua New Guinea",
+ "PH": "Philippines",
+ "PK": "Pakistan",
+ "PL": "Poland",
+ "PM": "Saint Pierre and Miquelon",
+ "PN": "Pitcairn Islands",
+ "PR": "Puerto Rico",
+ "PS": "Palestine",
+ "PT": "Portugal",
+ "PW": "Palau",
+ "PY": "Paraguay",
+ "QA": "Qatar",
+ "RE": "Réunion",
+ "RO": "Romania",
+ "RS": "Serbia",
+ "RU": "Russia",
+ "RW": "Rwanda",
+ "SA": "Saudi Arabia",
+ "SB": "Solomon Islands",
+ "SC": "Seychelles",
+ "SD": "Sudan",
+ "SE": "Sweden",
+ "SG": "Singapore",
+ "SH": "Saint Helena",
+ "SI": "Slovenia",
+ "SJ": "Svalbard and Jan Mayen",
+ "SK": "Slovakia",
+ "SL": "Sierra Leone",
+ "SM": "San Marino",
+ "SN": "Senegal",
+ "SO": "Somalia",
+ "SR": "Suriname",
+ "SS": "South Sudan",
+ "ST": "São Tomé and Príncipe",
+ "SV": "El Salvador",
+ "SX": "Sint Maarten",
+ "SY": "Syria",
+ "SZ": "Eswatini",
+ "TC": "Turks and Caicos Islands",
+ "TD": "Chad",
+ "TF": "French Southern Territories",
+ "TG": "Togo",
+ "TH": "Thailand",
+ "TJ": "Tajikistan",
+ "TK": "Tokelau",
+ "TL": "Timor-Leste",
+ "TM": "Turkmenistan",
+ "TN": "Tunisia",
+ "TO": "Tonga",
+ "TR": "Turkey",
+ "TT": "Trinidad and Tobago",
+ "TV": "Tuvalu",
+ "TW": "Taiwan",
+ "TZ": "Tanzania",
+ "UA": "Ukraine",
+ "UG": "Uganda",
+ "UM": "United States Minor Outlying Islands",
+ "US": "United States",
+ "UY": "Uruguay",
+ "UZ": "Uzbekistan",
+ "VA": "Vatican City",
+ "VC": "Saint Vincent and the Grenadines",
+ "VE": "Venezuela",
+ "VG": "British Virgin Islands",
+ "VI": "United States Virgin Islands",
+ "VN": "Vietnam",
+ "VU": "Vanuatu",
+ "WF": "Wallis and Futuna",
+ "WS": "Samoa",
+ "YE": "Yemen",
+ "YT": "Mayotte",
+ "ZA": "South Africa",
+ "ZM": "Zambia",
+ "ZW": "Zimbabwe"
}
diff --git a/packages/calcite-components/src/components/input-time-zone/input-time-zone.e2e.ts b/packages/calcite-components/src/components/input-time-zone/input-time-zone.e2e.ts
index d2a0feb9cd5..da4b93d456e 100644
--- a/packages/calcite-components/src/components/input-time-zone/input-time-zone.e2e.ts
+++ b/packages/calcite-components/src/components/input-time-zone/input-time-zone.e2e.ts
@@ -14,7 +14,7 @@ import {
} from "../../tests/commonTests";
import { TagAndPage } from "../../tests/commonTests/interfaces";
import { DEBOUNCE } from "../../utils/resources";
-import { toUserFriendlyName } from "./utils";
+import { getCity, toUserFriendlyName } from "./utils";
/*
* **Notes**
@@ -319,6 +319,71 @@ describe("calcite-input-time-zone", () => {
expect(await timeZoneItem.getProperty("textLabel")).toMatch(toUserFriendlyName(testTimeZoneItems[0].name));
});
});
+
+ describe("region", () => {
+ describe("selects user's matching time zone name on initialization", () => {
+ testTimeZoneItems.forEach(({ name }) => {
+ it(`selects default time zone for "${name}"`, async () => {
+ const page = await newE2EPage();
+ await page.emulateTimezone(name);
+ await page.setContent(
+ await overrideSupportedTimeZones(html``),
+ );
+ await page.waitForChanges();
+
+ const input = await page.find("calcite-input-time-zone");
+ expect(await input.getProperty("value")).toBe(name);
+
+ const timeZoneItem = await page.find("calcite-input-time-zone >>> calcite-combobox-item[selected]");
+
+ expect(await timeZoneItem.getProperty("textLabel")).toMatch(toUserFriendlyName(getCity(name)));
+ });
+ });
+ });
+
+ it("allows users to preselect a time zone by name", async () => {
+ const page = await newE2EPage();
+ await page.emulateTimezone(testTimeZoneItems[0].name);
+ await page.setContent(
+ await overrideSupportedTimeZones(
+ html``,
+ ),
+ );
+
+ const input = await page.find("calcite-input-time-zone");
+
+ expect(await input.getProperty("value")).toBe(testTimeZoneItems[1].name);
+
+ const timeZoneItem = await page.find("calcite-input-time-zone >>> calcite-combobox-item[selected]");
+
+ expect(await timeZoneItem.getProperty("textLabel")).toMatch(
+ toUserFriendlyName(getCity(testTimeZoneItems[1].name)),
+ );
+ });
+
+ it("ignores invalid values", async () => {
+ const page = await newE2EPage();
+ await page.emulateTimezone(testTimeZoneItems[0].name);
+ await page.setContent(
+ await overrideSupportedTimeZones(
+ html``,
+ ),
+ );
+
+ const input = await page.find("calcite-input-time-zone");
+
+ expect(await input.getProperty("value")).toBe(testTimeZoneItems[0].name);
+
+ const timeZoneItem = await page.find("calcite-input-time-zone >>> calcite-combobox-item[selected]");
+
+ expect(await timeZoneItem.getProperty("textLabel")).toMatch(
+ toUserFriendlyName(getCity(testTimeZoneItems[0].name)),
+ );
+ });
+ });
});
describe("clearable", () => {
diff --git a/packages/calcite-components/src/components/input-time-zone/input-time-zone.scss b/packages/calcite-components/src/components/input-time-zone/input-time-zone.scss
index b3ac7411e63..25b19175dd4 100644
--- a/packages/calcite-components/src/components/input-time-zone/input-time-zone.scss
+++ b/packages/calcite-components/src/components/input-time-zone/input-time-zone.scss
@@ -2,6 +2,10 @@
display: block;
}
+.offset {
+ white-space: nowrap;
+}
+
@include base-component();
@include disabled();
@include hidden-form-input();
diff --git a/packages/calcite-components/src/components/input-time-zone/input-time-zone.stories.ts b/packages/calcite-components/src/components/input-time-zone/input-time-zone.stories.ts
index a19a8a8d850..aa312f37d03 100644
--- a/packages/calcite-components/src/components/input-time-zone/input-time-zone.stories.ts
+++ b/packages/calcite-components/src/components/input-time-zone/input-time-zone.stories.ts
@@ -62,10 +62,12 @@ export const clearable = (): string => html`
+
+
`;
clearable.parameters = { chromatic: { delay: 500 } };
@@ -74,6 +76,10 @@ export const timeZoneNameMode_TestOnly = (): string => html`
`;
+export const timeZoneRegionMode_TestOnly = (): string => html`
+
+`;
+
export const initialNameSelected_TestOnly = (): string =>
// for stability, we use a timezone unaffected by daylight savings time
html``;
diff --git a/packages/calcite-components/src/components/input-time-zone/input-time-zone.tsx b/packages/calcite-components/src/components/input-time-zone/input-time-zone.tsx
index db0221fe17a..8c7a1302159 100644
--- a/packages/calcite-components/src/components/input-time-zone/input-time-zone.tsx
+++ b/packages/calcite-components/src/components/input-time-zone/input-time-zone.tsx
@@ -47,6 +47,7 @@ import {
MutableValidityState,
} from "../../utils/form";
import { IconNameOrString } from "../icon/interfaces";
+import { CSS } from "./resources";
import {
createTimeZoneItems,
findTimeZoneItemByProp,
@@ -54,7 +55,7 @@ import {
getUserTimeZoneOffset,
} from "./utils";
import { InputTimeZoneMessages } from "./assets/input-time-zone/t9n";
-import { OffsetStyle, TimeZoneItem, TimeZoneMode } from "./interfaces";
+import { OffsetStyle, TimeZoneItem, TimeZoneItemGroup, TimeZoneMode } from "./interfaces";
@Component({
tag: "calcite-input-time-zone",
@@ -324,7 +325,7 @@ export class InputTimeZone
private selectedTimeZoneItem: TimeZoneItem;
- private timeZoneItems: TimeZoneItem[];
+ private timeZoneItems: TimeZoneItem[] | TimeZoneItemGroup[];
//--------------------------------------------------------------------------
//
@@ -410,7 +411,7 @@ export class InputTimeZone
this.findTimeZoneItem(valueToMatch) || this.findTimeZoneItem(fallbackValue);
}
- private async createTimeZoneItems(): Promise {
+ private async createTimeZoneItems(): Promise {
if (!this.effectiveLocale || !this.messages) {
return [];
}
@@ -488,7 +489,11 @@ export class InputTimeZone
open={this.open}
overlayPositioning={this.overlayPositioning}
placeholder={
- this.mode === "name" ? this.messages.namePlaceholder : this.messages.offsetPlaceholder
+ this.mode === "name"
+ ? this.messages.namePlaceholder
+ : this.mode === "offset"
+ ? this.messages.offsetPlaceholder
+ : this.messages.regionPlaceholder
}
readOnly={this.readOnly}
ref={this.setComboboxRef}
@@ -498,24 +503,59 @@ export class InputTimeZone
validation-icon={this.validationIcon}
validation-message={this.validationMessage}
>
- {this.timeZoneItems.map((group) => {
- const selected = this.selectedTimeZoneItem === group;
- const { label, value } = group;
-
- return (
-
- );
- })}
+ {this.renderItems()}
);
}
+
+ private renderItems(): VNode[] {
+ if (this.mode === "region") {
+ return this.renderRegionItems();
+ }
+
+ return this.timeZoneItems.map((group) => {
+ const selected = this.selectedTimeZoneItem === group;
+ const { label, value } = group;
+
+ return (
+
+ );
+ });
+ }
+
+ private renderRegionItems(): VNode[] {
+ return (this.timeZoneItems as TimeZoneItemGroup[]).flatMap(({ label, items }) => (
+
+ {items.map((item) => {
+ const selected = this.selectedTimeZoneItem === item;
+ const { label, value } = item;
+
+ return (
+
+
+ {item.metadata.offset}
+
+
+ );
+ })}
+
+ ));
+ }
}
diff --git a/packages/calcite-components/src/components/input-time-zone/interfaces.d.ts b/packages/calcite-components/src/components/input-time-zone/interfaces.d.ts
index 6e29ffffc8e..2b13fdc0c0a 100644
--- a/packages/calcite-components/src/components/input-time-zone/interfaces.d.ts
+++ b/packages/calcite-components/src/components/input-time-zone/interfaces.d.ts
@@ -1,17 +1,37 @@
declare global {
namespace Intl {
- function supportedValuesOf(key: "timeZone"): TimeZoneName[];
+ function supportedValuesOf(key: "timeZone"): TimeZone[];
}
}
-export type TimeZoneName = string;
+export type TimeZone = string;
-export type TimeZoneMode = "offset" | "name";
+export interface TimeZoneGroup extends BasicTimeZoneGroup {
+ offsetGroupLabel: string;
+ offsetGroupRepTimeZone: string;
+ offsetGroupTimeZones: string[];
+}
+
+export interface BasicTimeZoneGroup {
+ offsetLabel: string;
+ offsetValue: number;
+}
+
+export type TimeZoneMode = "offset" | "name" | "region";
export interface TimeZoneItem {
label: string;
value: T;
filterValue: string | string[];
+ metadata?: {
+ offset?: string;
+ country?: string;
+ };
+}
+
+export interface TimeZoneItemGroup {
+ label: string;
+ items: TimeZoneItem[];
}
export type OffsetStyle = "user" | "utc" | "gmt";
diff --git a/packages/calcite-components/src/components/input-time-zone/resources.ts b/packages/calcite-components/src/components/input-time-zone/resources.ts
new file mode 100644
index 00000000000..f20cb242136
--- /dev/null
+++ b/packages/calcite-components/src/components/input-time-zone/resources.ts
@@ -0,0 +1,3 @@
+export const CSS = {
+ offset: "offset",
+};
diff --git a/packages/calcite-components/src/components/input-time-zone/utils.ts b/packages/calcite-components/src/components/input-time-zone/utils.ts
index 12f632156a0..11b99174c43 100644
--- a/packages/calcite-components/src/components/input-time-zone/utils.ts
+++ b/packages/calcite-components/src/components/input-time-zone/utils.ts
@@ -1,5 +1,5 @@
import { getDateTimeFormat, SupportedLocale } from "../../utils/locale";
-import { OffsetStyle, TimeZoneItem, TimeZoneMode, TimeZoneName } from "./interfaces";
+import { OffsetStyle, TimeZone, TimeZoneItem, TimeZoneItemGroup, TimeZoneMode } from "./interfaces";
import { InputTimeZoneMessages } from "./assets/input-time-zone/t9n";
const hourToMinutes = 60;
@@ -35,7 +35,7 @@ function timeZoneOffsetToDecimal(shortOffsetTimeZoneName: string): string {
);
}
-function toOffsetValue(timeZoneName: TimeZoneName, referenceDateInMs: number): number {
+function toOffsetValue(timeZoneName: TimeZone, referenceDateInMs: number): number {
// we use "en-US" to allow us to reliably remove the standard time token
const offset = getTimeZoneShortOffset(timeZoneName, "en-US", referenceDateInMs).replace("GMT", "");
@@ -59,7 +59,19 @@ export function getUserTimeZoneName(): string {
/**
* The lazy-loaded timezone-groups lib to be used across instances.
*/
-let timeZoneGroups: Promise<[any, any]>;
+let offsetGroupUtils: Promise<
+ [
+ typeof import("timezone-groups/dist/groupByOffset/index.mjs"),
+ typeof import("timezone-groups/dist/groupByOffset/strategy/native.mjs"),
+ ]
+>;
+let regionGroupUtils: Promise<
+ [
+ typeof import("timezone-groups/dist/groupByRegion/index.mjs"),
+ typeof import("timezone-groups/dist/utils/country.mjs"),
+ ]
+>;
+let nameGroupUtils: Promise;
export async function createTimeZoneItems(
locale: SupportedLocale,
@@ -67,97 +79,143 @@ export async function createTimeZoneItems(
mode: TimeZoneMode,
referenceDate: Date,
standardTime: OffsetStyle,
-): Promise {
+): Promise {
+ if (mode === "name") {
+ if (!nameGroupUtils) {
+ nameGroupUtils = import("timezone-groups/dist/groupByName/index.mjs");
+ }
+
+ return nameGroupUtils.then(async ({ groupByName }) => {
+ const groups = await groupByName();
+
+ return groups
+ .map>(({ label: timeZone }) => {
+ const label = toUserFriendlyName(timeZone);
+ const value = timeZone;
+
+ return {
+ label,
+ value,
+ filterValue: timeZone,
+ };
+ })
+ .filter((group) => !!group)
+ .sort();
+ });
+ }
+
+ const effectiveLocale =
+ standardTime === "user"
+ ? locale
+ : // we use locales that will always yield a short offset that matches `standardTime`
+ standardTime === "utc"
+ ? "fr"
+ : "en-GB";
const referenceDateInMs: number = referenceDate.getTime();
- const timeZoneNames = Intl.supportedValuesOf("timeZone");
- if (mode === "offset") {
- if (!timeZoneGroups) {
- timeZoneGroups = Promise.all([
- import("timezone-groups/dist/index.js"),
- import("timezone-groups/dist/strategy/native/index.js"),
+ if (mode === "region") {
+ if (!regionGroupUtils) {
+ regionGroupUtils = Promise.all([
+ import("timezone-groups/dist/groupByRegion/index.mjs"),
+ import("timezone-groups/dist/utils/country.mjs"),
]);
}
- return timeZoneGroups.then(async ([{ groupTimeZones }, { DateEngine }]) => {
- const timeZoneGroups: { labelTzIndices: number[]; tzs: TimeZoneName[] }[] = await groupTimeZones({
- dateEngine: new DateEngine(),
- groupDateRange: 1,
- startDate: new Date(referenceDateInMs).toISOString(),
- });
+ return regionGroupUtils.then(async ([{ groupByRegion }, { getCountry }]) => {
+ const groups = await groupByRegion();
- const listFormatter = new Intl.ListFormat(locale, { style: "long", type: "conjunction" });
+ return groups
+ .map(({ label: region, tzs }) => {
+ return {
+ label: region,
+ items: tzs.map((timeZone) => {
+ const decimalOffset = timeZoneOffsetToDecimal(
+ getTimeZoneShortOffset(timeZone, effectiveLocale, referenceDateInMs),
+ );
+
+ return {
+ label: getTimeZoneLabel(timeZone, messages),
+ value: timeZone,
+ filterValue: toUserFriendlyName(timeZone),
+ metadata: {
+ offset: decimalOffset,
+ country: getCountry(timeZone),
+ },
+ };
+ }),
+ };
+ })
+ .sort((groupA, groupB) => groupA.label.localeCompare(groupB.label));
+ });
+ }
+
+ if (!offsetGroupUtils) {
+ offsetGroupUtils = Promise.all([
+ import("timezone-groups/dist/groupByOffset/index.mjs"),
+ import("timezone-groups/dist/groupByOffset/strategy/native/index.mjs"),
+ ]);
+ }
- // we remove blocked entries from tzs and adjust label indices accordingly
- timeZoneGroups.forEach((group) => {
- const indexOffsets: number[] = [];
- let removedSoFar = 0;
+ return offsetGroupUtils.then(async ([{ groupByOffset }, { DateEngine }]) => {
+ const groups = await groupByOffset({
+ dateEngine: new DateEngine(),
+ groupDateRange: 1,
+ startDate: new Date(referenceDateInMs).toISOString(),
+ });
- group.tzs.forEach((tz, index) => {
- if (timeZoneNameBlockList.includes(tz)) {
- removedSoFar++;
- }
- indexOffsets[index] = removedSoFar;
- });
+ const listFormatter = new Intl.ListFormat(locale, { style: "long", type: "conjunction" });
- group.tzs = group.tzs.filter((tz) => !timeZoneNameBlockList.includes(tz));
+ // we remove blocked entries from tzs and adjust label indices accordingly
+ groups.forEach((group) => {
+ const indexOffsets: number[] = [];
+ let removedSoFar = 0;
- group.labelTzIndices = group.labelTzIndices
- .map((index) => index - indexOffsets[index])
- .filter((index) => index >= 0 && index < group.tzs.length);
+ group.tzs.forEach((tz, index) => {
+ if (timeZoneNameBlockList.includes(tz)) {
+ removedSoFar++;
+ }
+ indexOffsets[index] = removedSoFar;
});
- const effectiveLocale =
- standardTime === "user"
- ? locale
- : // we use locales that will always yield a short offset that matches `standardTime`
- standardTime === "utc"
- ? "fr"
- : "en-GB";
-
- return timeZoneGroups
- .map>(({ labelTzIndices, tzs }) => {
- const groupRepTz = tzs[0];
- const decimalOffset = timeZoneOffsetToDecimal(
- getTimeZoneShortOffset(groupRepTz, effectiveLocale, referenceDateInMs),
- );
- const value = toOffsetValue(groupRepTz, referenceDateInMs);
- const tzLabels = labelTzIndices.map((index: number) => {
- const timeZone = tzs[index];
- const timeZoneLabel = messages[timeZone];
- return (
- timeZoneLabel ||
- // get city token
- timeZone.split("/").pop()
- );
- });
-
- const label = createTimeZoneOffsetLabel(messages, decimalOffset, listFormatter.format(tzLabels));
+ group.tzs = group.tzs.filter((tz) => !timeZoneNameBlockList.includes(tz));
- return {
- label,
- value,
- filterValue: tzs.map((tz) => toUserFriendlyName(tz)),
- };
- })
- .filter((group) => !!group)
- .sort((groupA, groupB) => groupA.value - groupB.value);
+ group.labelTzIdx = group.labelTzIdx
+ .map((index) => index - indexOffsets[index])
+ .filter((index) => index >= 0 && index < group.tzs.length);
});
- }
- return timeZoneNames
- .map>((timeZone) => {
- const label = toUserFriendlyName(timeZone);
- const value = timeZone;
-
- return {
- label,
- value,
- filterValue: timeZone,
- };
- })
- .filter((group) => !!group)
- .sort();
+ return groups
+ .map>(({ labelTzIdx, tzs }) => {
+ const groupRepTz = tzs[0];
+ const decimalOffset = timeZoneOffsetToDecimal(
+ getTimeZoneShortOffset(groupRepTz, effectiveLocale, referenceDateInMs),
+ );
+ const value = toOffsetValue(groupRepTz, referenceDateInMs);
+ const tzLabels = labelTzIdx.map((index: number) => getTimeZoneLabel(tzs[index], messages));
+ const label = createTimeZoneOffsetLabel(messages, decimalOffset, listFormatter.format(tzLabels));
+
+ return {
+ label,
+ value,
+ filterValue: tzs.map((tz) => toUserFriendlyName(tz)),
+ };
+ })
+ .filter((group) => !!group)
+ .sort((groupA, groupB) => groupA.value - groupB.value);
+ });
+}
+
+function getTimeZoneLabel(timeZone: string, messages: InputTimeZoneMessages): string {
+ return messages[timeZone] || getCity(timeZone);
+}
+
+/**
+ * Exported for testing purposes only
+ *
+ * @internal
+ */
+export function getCity(timeZone: string): string {
+ return timeZone.split("/").pop();
}
/**
@@ -174,7 +232,7 @@ function createTimeZoneOffsetLabel(messages: InputTimeZoneMessages, offsetLabel:
}
function getTimeZoneShortOffset(
- timeZone: TimeZoneName,
+ timeZone: TimeZone,
locale: SupportedLocale,
referenceDateInMs: number = Date.now(),
): string {
@@ -183,14 +241,22 @@ function getTimeZoneShortOffset(
return parts.find(({ type }) => type === "timeZoneName").value;
}
+function isGroup(item: TimeZoneItem | TimeZoneItemGroup): item is TimeZoneItemGroup {
+ return (item as TimeZoneItemGroup).items !== undefined;
+}
+
+function flattenTimeZoneItems(timeZoneItems: TimeZoneItem[] | TimeZoneItemGroup[]): TimeZoneItem[] {
+ return isGroup(timeZoneItems[0]) ? timeZoneItems.flatMap((item) => item.items) : timeZoneItems;
+}
+
export function findTimeZoneItemByProp(
- timeZoneItems: TimeZoneItem[],
+ timeZoneItems: TimeZoneItem[] | TimeZoneItemGroup[],
prop: string,
valueToMatch: string | number | null,
): TimeZoneItem | null {
return valueToMatch == null
? null
- : timeZoneItems.find(
+ : flattenTimeZoneItems(timeZoneItems).find(
(item) =>
// intentional == to match string to number
item[prop] == valueToMatch,