From d7d780143de2417f01e2a07250bfbdab5708b455 Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Mon, 12 Jan 2026 13:46:15 +0545 Subject: [PATCH 01/12] feat(ui/country-picker): add grouping logic --- .../CountryDisplay/CountryDisplayDemo.tsx | 18 ++-- .../src/FormWidgets/CountryPicker/index.tsx | 90 +++++++++++-------- 2 files changed, 63 insertions(+), 45 deletions(-) diff --git a/apps/demo/src/Views/Ui/components/CountryDisplay/CountryDisplayDemo.tsx b/apps/demo/src/Views/Ui/components/CountryDisplay/CountryDisplayDemo.tsx index 9a502c898..24153f844 100644 --- a/apps/demo/src/Views/Ui/components/CountryDisplay/CountryDisplayDemo.tsx +++ b/apps/demo/src/Views/Ui/components/CountryDisplay/CountryDisplayDemo.tsx @@ -37,7 +37,7 @@ export const CountryDisplayDemo = () => { }, { id: 4, - prop: "i18n", + prop: "locales", type: "Record>", default: "{}", description: t("countryDisplay.propertiesDescription.i18n"), @@ -84,7 +84,7 @@ export const CountryDisplayDemo = () => { @@ -98,7 +98,7 @@ const selectedLocale = "np"; ' /> @@ -107,7 +107,7 @@ const selectedLocale = "np";
' /> @@ -196,18 +196,18 @@ fallbackLocale = np;
>; + exampleCode={`type Locales = Record>; interface CountryDisplayProperties { code: string; className?: string; fallbackLocale?: string; - i18n?: I18nData; + locales?: Locales; locale?: string; showFlag?: boolean; } -Example I18n: +Example locales: { en:{ "US": "USA" }, fr: { "US": "États-Unis" } diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index 29165dca6..481b45c13 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -2,7 +2,6 @@ import React, { useCallback, useMemo } from "react"; import { getFallbackTranslation } from "../../utils/CountryPicker"; import { Select, ISelectProperties } from "../Select"; -import defaultGroups from "./groups.json"; import type { Option, GroupedOption as OptionGroup } from "../Select"; @@ -35,51 +34,40 @@ export type CountryPickerProperties = Omit< locales?: Locales; }; -export { defaultGroups }; - const getBaseOptions = ( exclude: string[] | undefined, - fallbackLocale: string, + fallbackTranslation: Translation | undefined, include: string[] | undefined, locale: string, locales: Locales | undefined, ): Option[] => { - const fallbackData = getFallbackTranslation(fallbackLocale, locales); - - if (!fallbackData) { + if (!fallbackTranslation) { return []; } const baseOptions: Option[] = []; + const processCode = (code: string, fallbackLabel: string) => { + if (exclude?.includes(code)) { + return; + } + baseOptions.push({ + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackLabel), + }); + }; if (include?.length) { include.forEach((code) => { - if (exclude?.includes(code)) { - return; + const fallbackLabel = fallbackTranslation[code]; + if (fallbackLabel) { + processCode(code, fallbackLabel); } - - if (!fallbackData[code]) { - return; - } - - baseOptions.push({ - value: code as unknown as T, - label: getLabel(code, locale, locales, fallbackData[code]), - }); }); - return baseOptions; } - Object.entries(fallbackData).forEach(([code, fallbackLabel]) => { - if (exclude?.includes(code)) { - return; - } - - baseOptions.push({ - value: code as unknown as T, - label: getLabel(code, locale, locales, fallbackLabel), - }); + Object.entries(fallbackTranslation).forEach(([code, fallbackLabel]) => { + processCode(code, fallbackLabel); }); return baseOptions; @@ -101,19 +89,31 @@ const getFlagClass = ( .filter(Boolean) .join(" "); -const getGroups = (groups: Groups, list: Option[]): OptionGroup[] => { +const getGroups = ( + groups: Groups, + list: Option[], + locale: string, + locales: Locales | undefined, + fallbackTranslation: Translation | undefined, +): OptionGroup[] => { const optionMap = new Map( list.map((option) => [String(option.value), option]), ); return Object.entries(groups).reduce[]>( - (groupedOptions, [groupLabel, groupCodes]) => { + (groupedOptions, [groupKey, groupCodes]) => { const options = groupCodes .map((code) => optionMap.get(code)) .filter(Boolean) as Option[]; if (options.length) { - groupedOptions.push({ label: groupLabel, options }); + const label = getLabel( + groupKey, + locale, + locales, + fallbackTranslation?.[groupKey], + ); + groupedOptions.push({ label, options }); } return groupedOptions; @@ -133,7 +133,7 @@ const getLabel = ( const getOptions = ({ autoSortOptions = true, - exclude, + exclude = [], fallbackLocale = "en", favorites, groups, @@ -155,9 +155,15 @@ const getOptions = ({ | "locale" | "locales" >) => { + const fallbackTranslation = + getFallbackTranslation(fallbackLocale, locales) ?? undefined; + + const groupKeys = groups ? Object.keys(groups) : []; + const excludeKeys = [...exclude, ...groupKeys]; + const baseOptions = getBaseOptions( - exclude, - fallbackLocale, + excludeKeys, + fallbackTranslation, include, locale, locales, @@ -170,6 +176,9 @@ const getOptions = ({ includeFavorites, groups, labels, + locale, + locales, + fallbackTranslation, ); const hasFavoriteOptions = optionsWithFavorites[0].options.length > 0; @@ -182,7 +191,13 @@ const getOptions = ({ } if (groups && Object.keys(groups).length > 0) { - const optionGroups = getGroups(groups, baseOptions); + const optionGroups = getGroups( + groups, + baseOptions, + locale, + locales, + fallbackTranslation, + ); return getSortedOptions(autoSortOptions, optionGroups); } @@ -196,6 +211,9 @@ const getOptionsWithFavorites = ( includeFavorites: boolean, groups?: Groups, labels?: CountryPickerLabels, + locale: string = "en", + locales?: Locales, + fallbackTranslation?: Translation, ) => { const favoriteOptions = favorites .map((code) => baseOptions.find((option) => String(option.value) === code)) @@ -207,7 +225,7 @@ const getOptionsWithFavorites = ( const mainGroups = groups && Object.keys(groups).length > 0 - ? getGroups(groups, mainOptions) + ? getGroups(groups, mainOptions, locale, locales, fallbackTranslation) : [ { label: labels?.allCountries || "All countries", From 737712b871c5d38d6b1196b5c28f610e1899881d Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Mon, 12 Jan 2026 14:43:50 +0545 Subject: [PATCH 02/12] feat(ui/country-picker): add grouping and update demo --- .../CountryDisplay/CountryDisplayDemo.tsx | 18 +- .../components/FormWidgets/CountryPicker.tsx | 96 ++++--- .../Views/Ui/components/FormWidgets/en.json | 251 ++++++++++++++++++ apps/demo/src/locales/en/ui.json | 4 +- apps/demo/src/locales/fr/ui.json | 4 +- .../src/FormWidgets/CountryPicker/index.tsx | 2 + 6 files changed, 328 insertions(+), 47 deletions(-) create mode 100644 apps/demo/src/Views/Ui/components/FormWidgets/en.json diff --git a/apps/demo/src/Views/Ui/components/CountryDisplay/CountryDisplayDemo.tsx b/apps/demo/src/Views/Ui/components/CountryDisplay/CountryDisplayDemo.tsx index 24153f844..9a502c898 100644 --- a/apps/demo/src/Views/Ui/components/CountryDisplay/CountryDisplayDemo.tsx +++ b/apps/demo/src/Views/Ui/components/CountryDisplay/CountryDisplayDemo.tsx @@ -37,7 +37,7 @@ export const CountryDisplayDemo = () => { }, { id: 4, - prop: "locales", + prop: "i18n", type: "Record>", default: "{}", description: t("countryDisplay.propertiesDescription.i18n"), @@ -84,7 +84,7 @@ export const CountryDisplayDemo = () => { @@ -98,7 +98,7 @@ const selectedLocale = "np"; ' /> @@ -107,7 +107,7 @@ const selectedLocale = "np";
' /> @@ -196,18 +196,18 @@ fallbackLocale = np;
>; + exampleCode={`type I18nData = Record>; interface CountryDisplayProperties { code: string; className?: string; fallbackLocale?: string; - locales?: Locales; + i18n?: I18nData; locale?: string; showFlag?: boolean; } -Example locales: +Example I18n: { en:{ "US": "USA" }, fr: { "US": "États-Unis" } diff --git a/apps/demo/src/Views/Ui/components/FormWidgets/CountryPicker.tsx b/apps/demo/src/Views/Ui/components/FormWidgets/CountryPicker.tsx index 3686b0947..cb18e05d1 100644 --- a/apps/demo/src/Views/Ui/components/FormWidgets/CountryPicker.tsx +++ b/apps/demo/src/Views/Ui/components/FormWidgets/CountryPicker.tsx @@ -4,11 +4,11 @@ import { Page, Button, TDataTable, - defaultGroups, } from "@prefabs.tech/react-ui"; import { useState } from "react"; import { useNavigate } from "react-router-dom"; +import englishData from "./en.json"; import frenchData from "./fr.json"; import nepaliData from "./np.json"; import { CodeBlock, Section } from "../../../../components/Demo"; @@ -18,6 +18,17 @@ export const CountryPickerDemo = () => { const navigate = useNavigate(); const locale = i18n.language; + const frenchTranslation = { + ...frenchData, + EU: "Union Européenne", + ASEAN: "ASEAN", + }; + const englishTranslation = { + ...englishData, + EU: "European Union", + ASEAN: "ASEAN", + }; + const data = [ { default: "true", @@ -168,9 +179,10 @@ export const CountryPickerDemo = () => { const [flagsSelectValue, setFlagsSelectValue] = useState(""); const [includeFavoritesValue, setIncludeFavoritesValue] = useState(""); - const [groupedValue, setGroupedValue] = useState(""); const [customGroupValue, setCustomGroupValue] = useState(""); const [favoriteGroupValue, setFavoriteGroupValue] = useState(""); + const [translationGroupValue, setTranslationGroupValue] = + useState(""); const customFlagsPath = (code: string) => { return `https://flagcdn.com/${code.toLowerCase().trim()}.svg`; @@ -470,69 +482,85 @@ const selectedLocale = i18n.language;
- setGroupedValue(value as string) + setCustomGroupValue(value as string) } />
-
+
- setCustomGroupValue(value as string) + setTranslationGroupValue(value as string) } /> setCustomGroupValue(value)} + groups={myGroups} + locale={selectedLocale} + locales={locales} + value={value} + onChange={(value) => setSingleSelectValue(value)} />' />
@@ -568,7 +596,7 @@ const myRegions = { name="countryPicker" placeholder={t("countryPicker.placeholders.single")} value={favoriteGroupValue} - onChange={(value) => setFavoriteGroupValue(value)} + onChange={(value) => setSingleSelectValue(value)} />' />
diff --git a/apps/demo/src/Views/Ui/components/FormWidgets/en.json b/apps/demo/src/Views/Ui/components/FormWidgets/en.json new file mode 100644 index 000000000..531c47afe --- /dev/null +++ b/apps/demo/src/Views/Ui/components/FormWidgets/en.json @@ -0,0 +1,251 @@ +{ + "AF": "Afghanistan", + "AX": "Åland Islands", + "AL": "Albania", + "DZ": "Algeria", + "AS": "American Samoa", + "AD": "Andorra", + "AO": "Angola", + "AI": "Anguilla", + "AQ": "Antarctica", + "AG": "Antigua and Barbuda", + "AR": "Argentina", + "AM": "Armenia", + "AW": "Aruba", + "AU": "Australia", + "AT": "Austria", + "AZ": "Azerbaijan", + "BS": "Bahamas", + "BH": "Bahrain", + "BD": "Bangladesh", + "BB": "Barbados", + "BY": "Belarus", + "BE": "Belgium", + "BZ": "Belize", + "BJ": "Benin", + "BM": "Bermuda", + "BT": "Bhutan", + "BO": "Bolivia", + "BQ": "Bonaire, Sint Eustatius and Saba", + "BA": "Bosnia and Herzegovina", + "BW": "Botswana", + "BV": "Bouvet Island", + "BR": "Brazil", + "IO": "British Indian Ocean Territory", + "BN": "Brunei Darussalam", + "BG": "Bulgaria", + "BF": "Burkina Faso", + "BI": "Burundi", + "CV": "Cabo Verde", + "KH": "Cambodia", + "CM": "Cameroon", + "CA": "Canada", + "KY": "Cayman Islands", + "CF": "Central African Republic", + "TD": "Chad", + "CL": "Chile", + "CN": "China", + "CX": "Christmas Island", + "CC": "Cocos (Keeling) Islands", + "CO": "Colombia", + "KM": "Comoros", + "CG": "Congo", + "CD": "Congo, Democratic Republic of the", + "CK": "Cook Islands", + "CR": "Costa Rica", + "CI": "Côte d'Ivoire", + "HR": "Croatia", + "CU": "Cuba", + "CW": "Curaçao", + "CY": "Cyprus", + "CZ": "Czechia", + "DK": "Denmark", + "DJ": "Djibouti", + "DM": "Dominica", + "DO": "Dominican Republic", + "EC": "Ecuador", + "EG": "Egypt", + "SV": "El Salvador", + "GQ": "Equatorial Guinea", + "ER": "Eritrea", + "EE": "Estonia", + "SZ": "Eswatini", + "ET": "Ethiopia", + "FK": "Falkland Islands (Malvinas)", + "FO": "Faroe Islands", + "FJ": "Fiji", + "FI": "Finland", + "FR": "France", + "GF": "French Guiana", + "PF": "French Polynesia", + "TF": "French Southern Territories", + "GA": "Gabon", + "GM": "Gambia", + "GE": "Georgia", + "DE": "Germany", + "GH": "Ghana", + "GI": "Gibraltar", + "GR": "Greece", + "GL": "Greenland", + "GD": "Grenada", + "GP": "Guadeloupe", + "GU": "Guam", + "GT": "Guatemala", + "GG": "Guernsey", + "GN": "Guinea", + "GW": "Guinea-Bissau", + "GY": "Guyana", + "HT": "Haiti", + "HM": "Heard Island and McDonald Islands", + "VA": "Holy See", + "HN": "Honduras", + "HK": "Hong Kong", + "HU": "Hungary", + "IS": "Iceland", + "IN": "India", + "ID": "Indonesia", + "IR": "Iran", + "IQ": "Iraq", + "IE": "Ireland", + "IM": "Isle of Man", + "IL": "Israel", + "IT": "Italy", + "JM": "Jamaica", + "JP": "Japan", + "JE": "Jersey", + "JO": "Jordan", + "KZ": "Kazakhstan", + "KE": "Kenya", + "KI": "Kiribati", + "KP": "Korea, Democratic People's Republic of", + "KR": "Korea, Republic of", + "KW": "Kuwait", + "KG": "Kyrgyzstan", + "LA": "Lao People's Democratic Republic", + "LV": "Latvia", + "LB": "Lebanon", + "LS": "Lesotho", + "LR": "Liberia", + "LY": "Libya", + "LI": "Liechtenstein", + "LT": "Lithuania", + "LU": "Luxembourg", + "MO": "Macao", + "MG": "Madagascar", + "MW": "Malawi", + "MY": "Malaysia", + "MV": "Maldives", + "ML": "Mali", + "MT": "Malta", + "MH": "Marshall Islands", + "MQ": "Martinique", + "MR": "Mauritania", + "MU": "Mauritius", + "YT": "Mayotte", + "MX": "Mexico", + "FM": "Micronesia", + "MD": "Moldova", + "MC": "Monaco", + "MN": "Mongolia", + "ME": "Montenegro", + "MS": "Montserrat", + "MA": "Morocco", + "MZ": "Mozambique", + "MM": "Myanmar", + "NA": "Namibia", + "NR": "Nauru", + "NP": "Nepal", + "NL": "Netherlands", + "NC": "New Caledonia", + "NZ": "New Zealand", + "NI": "Nicaragua", + "NE": "Niger", + "NG": "Nigeria", + "NU": "Niue", + "NF": "Norfolk Island", + "MK": "North Macedonia", + "MP": "Northern Mariana Islands", + "NO": "Norway", + "OM": "Oman", + "PK": "Pakistan", + "PW": "Palau", + "PS": "Palestine, State of", + "PA": "Panama", + "PG": "Papua New Guinea", + "PY": "Paraguay", + "PE": "Peru", + "PH": "Philippines", + "PN": "Pitcairn", + "PL": "Poland", + "PT": "Portugal", + "PR": "Puerto Rico", + "QA": "Qatar", + "RE": "Réunion", + "RO": "Romania", + "RU": "Russian Federation", + "RW": "Rwanda", + "BL": "Saint Barthélemy", + "SH": "Saint Helena, Ascension and Tristan da Cunha", + "KN": "Saint Kitts and Nevis", + "LC": "Saint Lucia", + "MF": "Saint Martin (French part)", + "PM": "Saint Pierre and Miquelon", + "VC": "Saint Vincent and the Grenadines", + "WS": "Samoa", + "SM": "San Marino", + "ST": "Sao Tome and Principe", + "SA": "Saudi Arabia", + "SN": "Senegal", + "RS": "Serbia", + "SC": "Seychelles", + "SL": "Sierra Leone", + "SG": "Singapore", + "SX": "Sint Maarten (Dutch part)", + "SK": "Slovakia", + "SI": "Slovenia", + "SB": "Solomon Islands", + "SO": "Somalia", + "ZA": "South Africa", + "GS": "South Georgia and the South Sandwich Islands", + "SS": "South Sudan", + "ES": "Spain", + "LK": "Sri Lanka", + "SD": "Sudan", + "SR": "Suriname", + "SJ": "Svalbard and Jan Mayen", + "SE": "Sweden", + "CH": "Switzerland", + "SY": "Syrian Arab Republic", + "TW": "Taiwan", + "TJ": "Tajikistan", + "TZ": "Tanzania, United Republic of", + "TH": "Thailand", + "TL": "Timor-Leste", + "TG": "Togo", + "TK": "Tokelau", + "TO": "Tonga", + "TT": "Trinidad and Tobago", + "TN": "Tunisia", + "TR": "Turkey", + "TM": "Turkmenistan", + "TC": "Turks and Caicos Islands", + "TV": "Tuvalu", + "UG": "Uganda", + "UA": "Ukraine", + "AE": "United Arab Emirates", + "GB": "United Kingdom", + "US": "United States", + "UM": "United States Minor Outlying Islands", + "UY": "Uruguay", + "UZ": "Uzbekistan", + "VU": "Vanuatu", + "VE": "Venezuela", + "VN": "Viet Nam", + "VG": "Virgin Islands, British", + "VI": "Virgin Islands, U.S.", + "WF": "Wallis and Futuna", + "EH": "Western Sahara", + "YE": "Yemen", + "ZM": "Zambia", + "ZW": "Zimbabwe" +} diff --git a/apps/demo/src/locales/en/ui.json b/apps/demo/src/locales/en/ui.json index a9d406e24..755196966 100644 --- a/apps/demo/src/locales/en/ui.json +++ b/apps/demo/src/locales/en/ui.json @@ -131,9 +131,9 @@ "fallbackLocale": "Fallback locale", "favorites": "Favorites", "flagsStyle": "Flags style and position", - "groupingCustom": "Custom grouping", - "groupingDefault": "Default grouping", + "groupingDefault": "Grouping", "groupingFavorites": "Grouping with favorites", + "groupingWithTranslation": "Grouping with translations", "include": "Include filter", "includeFavorites": "Include favorites", "labels": { diff --git a/apps/demo/src/locales/fr/ui.json b/apps/demo/src/locales/fr/ui.json index 4e92a5aba..49d344fe5 100644 --- a/apps/demo/src/locales/fr/ui.json +++ b/apps/demo/src/locales/fr/ui.json @@ -131,9 +131,9 @@ "fallbackLocale": "Fallback locale (fr)", "favorites": "Favorites (fr)", "flagsStyle": "Flags style and position (fr)", - "groupingCustom": "Custom grouping (fr)", - "groupingDefault": "Default grouping (fr)", + "groupingDefault": "Grouping (fr)", "groupingFavorites": "Grouping with favorites (fr)", + "groupingWithTranslation": "Grouping with translations (fr)", "locale": "New locale support (fr)", "include": "Include filter (fr)", "includeFavorites": "Include favorites (fr)", diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index 481b45c13..1a76b573b 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -2,6 +2,7 @@ import React, { useCallback, useMemo } from "react"; import { getFallbackTranslation } from "../../utils/CountryPicker"; import { Select, ISelectProperties } from "../Select"; +import defaultGroups from "./groups.json"; import type { Option, GroupedOption as OptionGroup } from "../Select"; @@ -33,6 +34,7 @@ export type CountryPickerProperties = Omit< locale?: string; locales?: Locales; }; +export { defaultGroups }; const getBaseOptions = ( exclude: string[] | undefined, From ad265f491279128ea3a9a78e2dc62b63f3622ed4 Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Tue, 13 Jan 2026 10:04:49 +0545 Subject: [PATCH 03/12] refactor(ui/countryPicker): remove default groups --- packages/ui/src/FormWidgets/CountryPicker/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index 1a76b573b..481b45c13 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -2,7 +2,6 @@ import React, { useCallback, useMemo } from "react"; import { getFallbackTranslation } from "../../utils/CountryPicker"; import { Select, ISelectProperties } from "../Select"; -import defaultGroups from "./groups.json"; import type { Option, GroupedOption as OptionGroup } from "../Select"; @@ -34,7 +33,6 @@ export type CountryPickerProperties = Omit< locale?: string; locales?: Locales; }; -export { defaultGroups }; const getBaseOptions = ( exclude: string[] | undefined, From 9addd2ec415ac7672f405de2e82db132efe02d9c Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Tue, 13 Jan 2026 13:43:15 +0545 Subject: [PATCH 04/12] refactor(ui/country): add empty line --- packages/ui/src/FormWidgets/CountryPicker/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index 481b45c13..42d8b2de7 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -46,6 +46,7 @@ const getBaseOptions = ( } const baseOptions: Option[] = []; + const processCode = (code: string, fallbackLabel: string) => { if (exclude?.includes(code)) { return; @@ -59,10 +60,12 @@ const getBaseOptions = ( if (include?.length) { include.forEach((code) => { const fallbackLabel = fallbackTranslation[code]; + if (fallbackLabel) { processCode(code, fallbackLabel); } }); + return baseOptions; } From 589e499d261bc53c5b9d6e8e8e998b1c2a26baf2 Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Thu, 15 Jan 2026 14:06:50 +0545 Subject: [PATCH 05/12] refactor(ui/country-picker): update logic --- .../src/FormWidgets/CountryPicker/index.tsx | 375 ++++++++---------- 1 file changed, 164 insertions(+), 211 deletions(-) diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index ee8c61c83..6a062e961 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -7,81 +7,122 @@ import { import { Select, ISelectProperties } from "../Select"; import type { - CountryPickerLabels, CountryPickerProperties, Groups, Locales, Translation, } from "../../types/country-picker"; -import type { Option, GroupedOption as OptionGroup } from "../Select"; +import type { GroupedOption as OptionGroup, Option } from "../Select"; -const getBaseOptions = ( - exclude: string[] | undefined, - fallbackTranslation: Translation | undefined, - include: string[] | undefined, +const getLabel = ( + code: string, locale: string, locales: Locales | undefined, -): Option[] => { - if (!fallbackTranslation) { - return []; - } - - const baseOptions: Option[] = []; + fallbackLabel?: string, +) => locales?.[locale]?.[code] || fallbackLabel || code; - const processCode = (code: string, fallbackLabel: string) => { - if (exclude?.includes(code)) { - return; - } - baseOptions.push({ - value: code as unknown as T, - label: getLabel(code, locale, locales, fallbackLabel), - }); - }; +const sortByLabel = ( + a: Option | OptionGroup, + b: Option | OptionGroup, +) => (a.label || "").localeCompare(b.label || ""); - if (include?.length) { - include.forEach((code) => { - const fallbackLabel = fallbackTranslation[code]; +const getAuthoritativeList = ( + fallbackTranslation: Translation, + locale: string, + locales: Locales | undefined, + groups?: Groups, + include?: string[], + exclude: string[] = [], +): Option[] => { + const options: Option[] = []; + const processedCodes = new Set(); - if (fallbackLabel) { - processCode(code, fallbackLabel); + if (groups && Object.keys(groups).length > 0) { + Object.values(groups) + .flat() + .forEach((code) => { + if (!processedCodes.has(code) && fallbackTranslation[code]) { + processedCodes.add(code); + options.push({ + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackTranslation[code]), + }); + } + }); + } else { + const sourceCodes = include || Object.keys(fallbackTranslation); + sourceCodes.forEach((code) => { + if ( + !exclude.includes(code) && + !processedCodes.has(code) && + fallbackTranslation[code] + ) { + processedCodes.add(code); + options.push({ + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackTranslation[code]), + }); } }); + } + + return options; +}; - return baseOptions; +const getFavoriteOptions = ( + allOptions: Option[], + favorites: string[], + autoSortOptions: boolean, +): Option[] => { + if (!favorites.length) { + return []; } - Object.entries(fallbackTranslation).forEach(([code, fallbackLabel]) => { - processCode(code, fallbackLabel); + const favoriteOptions: Option[] = []; + + favorites.forEach((favoriteCode) => { + const found = allOptions.find((opt) => String(opt.value) === favoriteCode); + if (found) favoriteOptions.push(found); }); - return baseOptions; + if (autoSortOptions) favoriteOptions.sort(sortByLabel); + + return favoriteOptions; }; -const getGroups = ( +const getGroupedOptions = ( + allOptions: Option[], groups: Groups, - list: Option[], + favorites: string[], + includeFavorites: boolean, locale: string, locales: Locales | undefined, - fallbackTranslation: Translation | undefined, + fallbackTranslation: Translation, + autoSortOptions: boolean, ): OptionGroup[] => { - const optionMap = new Map( - list.map((option) => [String(option.value), option]), - ); - return Object.entries(groups).reduce[]>( (groupedOptions, [groupKey, groupCodes]) => { - const options = groupCodes - .map((code) => optionMap.get(code)) - .filter(Boolean) as Option[]; - - if (options.length) { - const label = getLabel( - groupKey, - locale, - locales, - fallbackTranslation?.[groupKey], + let groupOptions = allOptions.filter((option) => + groupCodes.includes(String(option.value)), + ); + + if (!includeFavorites && favorites.length > 0) { + groupOptions = groupOptions.filter( + (option) => !favorites.includes(String(option.value)), ); - groupedOptions.push({ label, options }); + } + + if (groupOptions.length > 0) { + if (autoSortOptions) groupOptions.sort(sortByLabel); + groupedOptions.push({ + label: getLabel( + groupKey, + locale, + locales, + fallbackTranslation[groupKey], + ), + options: groupOptions, + }); } return groupedOptions; @@ -90,20 +131,37 @@ const getGroups = ( ); }; -const getLabel = ( - code: string, - locale: string, - locales: Locales | undefined, - fallbackLabel?: string, -) => { - return locales?.[locale]?.[code] || fallbackLabel || code; +const getAllCountries = ( + allOptions: Option[], + favorites: string[], + includeFavorites: boolean, + labels: CountryPickerProperties["labels"], + autoSortOptions: boolean, +): Option[] | OptionGroup[] => { + const allCountries = + !includeFavorites && favorites.length > 0 + ? allOptions.filter((option) => !favorites.includes(String(option.value))) + : [...allOptions]; + + if (autoSortOptions) allCountries.sort(sortByLabel); + + if (favorites.length > 0) { + return [ + { + label: labels?.allCountries || "All Countries", + options: allCountries, + }, + ]; + } + + return allCountries; }; const getOptions = ({ autoSortOptions = true, exclude = [], fallbackLocale = "en", - favorites, + favorites = [], groups, include, includeFavorites = true, @@ -124,176 +182,58 @@ const getOptions = ({ | "locales" >) => { const fallbackTranslation = - getFallbackTranslation(fallbackLocale, locales) ?? undefined; - - const groupKeys = groups ? Object.keys(groups) : []; - const excludeKeys = [...exclude, ...groupKeys]; + getFallbackTranslation(fallbackLocale, locales) || {}; - const baseOptions = getBaseOptions( - excludeKeys, + const allOptions = getAuthoritativeList( fallbackTranslation, - include, locale, locales, + groups, + include, + exclude, ); - if (favorites && favorites.length > 0) { - const optionsWithFavorites = getOptionsWithFavorites( - baseOptions, - favorites, - includeFavorites, - groups, - labels, - locale, - locales, - fallbackTranslation, - ); - - const hasFavoriteOptions = optionsWithFavorites[0].options.length > 0; + const favoriteOptions = getFavoriteOptions( + allOptions, + favorites, + autoSortOptions, + ); - return getSortedOptions( - autoSortOptions, - optionsWithFavorites, - hasFavoriteOptions, - ); - } + let groupedOptions: Option[] | OptionGroup[] = []; if (groups && Object.keys(groups).length > 0) { - const optionGroups = getGroups( + groupedOptions = getGroupedOptions( + allOptions, groups, - baseOptions, + favorites, + includeFavorites, locale, locales, fallbackTranslation, + autoSortOptions, + ); + } else { + groupedOptions = getAllCountries( + allOptions, + favorites, + includeFavorites, + labels, + autoSortOptions, ); - - return getSortedOptions(autoSortOptions, optionGroups); } - return getSortedOptions(autoSortOptions, baseOptions); -}; + const options: (Option | OptionGroup)[] = []; -const getOptionsWithFavorites = ( - baseOptions: Option[], - favorites: string[], - includeFavorites: boolean, - groups?: Groups, - labels?: CountryPickerLabels, - locale: string = "en", - locales?: Locales, - fallbackTranslation?: Translation, -) => { - const favoriteOptions = favorites - .map((code) => baseOptions.find((option) => String(option.value) === code)) - .filter(Boolean) as Option[]; - - const mainOptions = includeFavorites - ? baseOptions - : baseOptions.filter((option) => !favorites.includes(String(option.value))); - - const mainGroups = - groups && Object.keys(groups).length > 0 - ? getGroups(groups, mainOptions, locale, locales, fallbackTranslation) - : [ - { - label: labels?.allCountries || "All countries", - options: mainOptions, - }, - ]; - - return [ - { + if (favoriteOptions.length > 0) { + options.push({ label: labels?.favorites || "Favorites", options: favoriteOptions, - }, - ...mainGroups, - ]; -}; - -const getSortedOptions = ( - autoSortOptions: boolean, - options: Option[] | OptionGroup[], - hasFavoriteOptions?: boolean, -) => { - if (!autoSortOptions) { - return options as Option[] | OptionGroup[]; - } - - if (!hasOptionGroup(options)) { - return [...(options as Option[])].sort(sortByLabel); - } - - const sortedOptionsGroup = (options as OptionGroup[]).map((group) => { - return { - ...group, - options: [...(group.options as Option[])].sort(sortByLabel), - }; - }); - - if (hasFavoriteOptions) { - return [ - sortedOptionsGroup[0], - ...sortedOptionsGroup.slice(1).sort(sortByLabel), - ]; - } - - return sortedOptionsGroup.sort(sortByLabel); -}; - -const hasOptionGroup = ( - options: Option[] | OptionGroup[], -): options is OptionGroup[] => { - return ( - Array.isArray(options) && - options.length > 0 && - options.every( - (option): option is OptionGroup => - typeof option === "object" && "options" in option, - ) - ); -}; - -const renderCountryOption = ( - option: Option, - { - flags, - flagsPath, - flagsPosition = "left", - flagsStyle = "rectangular", - }: Pick< - CountryPickerProperties, - "flags" | "flagsPath" | "flagsPosition" | "flagsStyle" - >, -) => { - const code = String(option.value); - const flagClass = getFlagClass(code, flagsPosition, flagsStyle); - - return ( -
- {flags && - (flagsPath ? ( - {option.label} - ) : ( - - ))} - {option.label} -
- ); -}; - -const sortByLabel = ( - optionA: Option | OptionGroup, - optionB: Option | OptionGroup, -) => { - if (!optionA.label) { - return 1; + }); } - if (!optionB.label) { - return -1; - } + options.push(...(groupedOptions as (Option | OptionGroup)[])); - return optionA.label.localeCompare(optionB.label); + return options; }; export const CountryPicker = ({ @@ -354,13 +294,26 @@ export const CountryPicker = ({ ); const handleRenderOption = useCallback( - (option: Option) => - renderCountryOption(option, { - flags, - flagsPath, - flagsPosition, - flagsStyle, - }), + (option: Option) => { + const code = String(option.value); + const flagClass = getFlagClass(code, flagsPosition, flagsStyle); + + return ( +
+ {flags && + (flagsPath ? ( + {option.label} + ) : ( + + ))} + {option.label} +
+ ); + }, [flags, flagsPath, flagsPosition, flagsStyle], ); From 35b0144379a52bad529280cd973ce2cff42f4c50 Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Fri, 16 Jan 2026 09:59:27 +0545 Subject: [PATCH 06/12] refactor(ui/country-picker): arrange functions in asc order --- .../src/FormWidgets/CountryPicker/index.tsx | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index 6a062e961..4a6ff0361 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -14,17 +14,31 @@ import type { } from "../../types/country-picker"; import type { GroupedOption as OptionGroup, Option } from "../Select"; -const getLabel = ( - code: string, - locale: string, - locales: Locales | undefined, - fallbackLabel?: string, -) => locales?.[locale]?.[code] || fallbackLabel || code; +const getAllCountries = ( + allOptions: Option[], + favorites: string[], + includeFavorites: boolean, + labels: CountryPickerProperties["labels"], + autoSortOptions: boolean, +): Option[] | OptionGroup[] => { + const allCountries = + !includeFavorites && favorites.length > 0 + ? allOptions.filter((option) => !favorites.includes(String(option.value))) + : [...allOptions]; -const sortByLabel = ( - a: Option | OptionGroup, - b: Option | OptionGroup, -) => (a.label || "").localeCompare(b.label || ""); + if (autoSortOptions) allCountries.sort(sortByLabel); + + if (favorites.length > 0) { + return [ + { + label: labels?.allCountries || "All Countries", + options: allCountries, + }, + ]; + } + + return allCountries; +}; const getAuthoritativeList = ( fallbackTranslation: Translation, @@ -131,31 +145,12 @@ const getGroupedOptions = ( ); }; -const getAllCountries = ( - allOptions: Option[], - favorites: string[], - includeFavorites: boolean, - labels: CountryPickerProperties["labels"], - autoSortOptions: boolean, -): Option[] | OptionGroup[] => { - const allCountries = - !includeFavorites && favorites.length > 0 - ? allOptions.filter((option) => !favorites.includes(String(option.value))) - : [...allOptions]; - - if (autoSortOptions) allCountries.sort(sortByLabel); - - if (favorites.length > 0) { - return [ - { - label: labels?.allCountries || "All Countries", - options: allCountries, - }, - ]; - } - - return allCountries; -}; +const getLabel = ( + code: string, + locale: string, + locales: Locales | undefined, + fallbackLabel?: string, +) => locales?.[locale]?.[code] || fallbackLabel || code; const getOptions = ({ autoSortOptions = true, @@ -236,6 +231,11 @@ const getOptions = ({ return options; }; +const sortByLabel = ( + a: Option | OptionGroup, + b: Option | OptionGroup, +) => (a.label || "").localeCompare(b.label || ""); + export const CountryPicker = ({ autoSortOptions = true, exclude, From 790cf988f058347090d8897f421b6f9330ff96a2 Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Fri, 16 Jan 2026 10:11:19 +0545 Subject: [PATCH 07/12] refactor(ui/country-picker): update logic --- .../ui/src/FormWidgets/CountryPicker/index.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index 4a6ff0361..e3bef4636 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -49,14 +49,14 @@ const getAuthoritativeList = ( exclude: string[] = [], ): Option[] => { const options: Option[] = []; - const processedCodes = new Set(); + const countryCodes = new Set(); if (groups && Object.keys(groups).length > 0) { Object.values(groups) .flat() .forEach((code) => { - if (!processedCodes.has(code) && fallbackTranslation[code]) { - processedCodes.add(code); + if (!countryCodes.has(code) && fallbackTranslation[code]) { + countryCodes.add(code); options.push({ value: code as unknown as T, label: getLabel(code, locale, locales, fallbackTranslation[code]), @@ -64,14 +64,14 @@ const getAuthoritativeList = ( } }); } else { - const sourceCodes = include || Object.keys(fallbackTranslation); - sourceCodes.forEach((code) => { + const availableCodes = include || Object.keys(fallbackTranslation); + availableCodes.forEach((code) => { if ( !exclude.includes(code) && - !processedCodes.has(code) && + !countryCodes.has(code) && fallbackTranslation[code] ) { - processedCodes.add(code); + countryCodes.add(code); options.push({ value: code as unknown as T, label: getLabel(code, locale, locales, fallbackTranslation[code]), From 5b794b06a445d4251a2938b14effc7854e96a0c9 Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Fri, 16 Jan 2026 13:46:10 +0545 Subject: [PATCH 08/12] refactor(ui/country-picker): refactor component logic --- .../src/FormWidgets/CountryPicker/index.tsx | 239 +++++++----------- 1 file changed, 89 insertions(+), 150 deletions(-) diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index e3bef4636..18eda601f 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -14,143 +14,107 @@ import type { } from "../../types/country-picker"; import type { GroupedOption as OptionGroup, Option } from "../Select"; -const getAllCountries = ( - allOptions: Option[], - favorites: string[], - includeFavorites: boolean, - labels: CountryPickerProperties["labels"], - autoSortOptions: boolean, -): Option[] | OptionGroup[] => { - const allCountries = - !includeFavorites && favorites.length > 0 - ? allOptions.filter((option) => !favorites.includes(String(option.value))) - : [...allOptions]; - - if (autoSortOptions) allCountries.sort(sortByLabel); - - if (favorites.length > 0) { - return [ - { - label: labels?.allCountries || "All Countries", - options: allCountries, - }, - ]; - } - - return allCountries; -}; - -const getAuthoritativeList = ( - fallbackTranslation: Translation, +const getLabel = ( + code: string, locale: string, locales: Locales | undefined, - groups?: Groups, - include?: string[], - exclude: string[] = [], -): Option[] => { - const options: Option[] = []; - const countryCodes = new Set(); - - if (groups && Object.keys(groups).length > 0) { - Object.values(groups) - .flat() - .forEach((code) => { - if (!countryCodes.has(code) && fallbackTranslation[code]) { - countryCodes.add(code); - options.push({ - value: code as unknown as T, - label: getLabel(code, locale, locales, fallbackTranslation[code]), - }); - } - }); - } else { - const availableCodes = include || Object.keys(fallbackTranslation); - availableCodes.forEach((code) => { - if ( - !exclude.includes(code) && - !countryCodes.has(code) && - fallbackTranslation[code] - ) { - countryCodes.add(code); - options.push({ - value: code as unknown as T, - label: getLabel(code, locale, locales, fallbackTranslation[code]), - }); - } - }); - } + fallbackTranslation: Translation, +) => { + return locales?.[locale]?.[code] || fallbackTranslation[code] || code; +}; - return options; +const sortByLabel = ( + a: Option | OptionGroup, + b: Option | OptionGroup, +) => { + return (a.label || "").localeCompare(b.label || ""); }; const getFavoriteOptions = ( - allOptions: Option[], favorites: string[], + locale: string, + locales: Locales | undefined, + fallbackTranslation: Translation, autoSortOptions: boolean, ): Option[] => { if (!favorites.length) { return []; } - const favoriteOptions: Option[] = []; + const options = favorites.map((code) => ({ + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackTranslation), + })); - favorites.forEach((favoriteCode) => { - const found = allOptions.find((opt) => String(opt.value) === favoriteCode); - if (found) favoriteOptions.push(found); - }); - - if (autoSortOptions) favoriteOptions.sort(sortByLabel); + if (autoSortOptions) { + options.sort(sortByLabel); + } - return favoriteOptions; + return options; }; -const getGroupedOptions = ( - allOptions: Option[], - groups: Groups, +const getFullList = ( + groups: Groups | undefined, + include: string[] | undefined, + exclude: string[], favorites: string[], includeFavorites: boolean, locale: string, locales: Locales | undefined, fallbackTranslation: Translation, + labels: CountryPickerProperties["labels"], autoSortOptions: boolean, -): OptionGroup[] => { - return Object.entries(groups).reduce[]>( - (groupedOptions, [groupKey, groupCodes]) => { - let groupOptions = allOptions.filter((option) => - groupCodes.includes(String(option.value)), - ); +): Option[] | OptionGroup[] => { + if (groups && Object.keys(groups).length > 0) { + return Object.entries(groups).map(([groupKey, groupCodes]) => { + const groupOptions = groupCodes.map((code) => ({ + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackTranslation), + })); + + if (autoSortOptions) { + groupOptions.sort(sortByLabel); + } + + return { + label: getLabel(groupKey, locale, locales, fallbackTranslation), + options: groupOptions, + }; + }); + } + + const codes = include || Object.keys(fallbackTranslation); - if (!includeFavorites && favorites.length > 0) { - groupOptions = groupOptions.filter( - (option) => !favorites.includes(String(option.value)), - ); + const options = codes + .filter((code) => { + if (exclude.includes(code)) { + return false; } - if (groupOptions.length > 0) { - if (autoSortOptions) groupOptions.sort(sortByLabel); - groupedOptions.push({ - label: getLabel( - groupKey, - locale, - locales, - fallbackTranslation[groupKey], - ), - options: groupOptions, - }); + if (!includeFavorites && favorites.includes(code)) { + return false; } - return groupedOptions; - }, - [], - ); -}; + return true; + }) + .map((code) => ({ + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackTranslation), + })); -const getLabel = ( - code: string, - locale: string, - locales: Locales | undefined, - fallbackLabel?: string, -) => locales?.[locale]?.[code] || fallbackLabel || code; + if (autoSortOptions) options.sort(sortByLabel); + + if (favorites.length > 0) { + return [ + { + label: labels?.allCountries || "All Countries", + options: options, + }, + ]; + } + + return options; +}; const getOptions = ({ autoSortOptions = true, @@ -179,63 +143,41 @@ const getOptions = ({ const fallbackTranslation = getFallbackTranslation(fallbackLocale, locales) || {}; - const allOptions = getAuthoritativeList( - fallbackTranslation, + const favoriteOptions = getFavoriteOptions( + favorites, locale, locales, + fallbackTranslation, + autoSortOptions, + ); + + const mainList = getFullList( groups, include, exclude, - ); - - const favoriteOptions = getFavoriteOptions( - allOptions, favorites, + includeFavorites, + locale, + locales, + fallbackTranslation, + labels, autoSortOptions, ); - let groupedOptions: Option[] | OptionGroup[] = []; - - if (groups && Object.keys(groups).length > 0) { - groupedOptions = getGroupedOptions( - allOptions, - groups, - favorites, - includeFavorites, - locale, - locales, - fallbackTranslation, - autoSortOptions, - ); - } else { - groupedOptions = getAllCountries( - allOptions, - favorites, - includeFavorites, - labels, - autoSortOptions, - ); - } - - const options: (Option | OptionGroup)[] = []; + const finalOptions: (Option | OptionGroup)[] = []; if (favoriteOptions.length > 0) { - options.push({ + finalOptions.push({ label: labels?.favorites || "Favorites", options: favoriteOptions, }); } - options.push(...(groupedOptions as (Option | OptionGroup)[])); + finalOptions.push(...(mainList as (Option | OptionGroup)[])); - return options; + return finalOptions; }; -const sortByLabel = ( - a: Option | OptionGroup, - b: Option | OptionGroup, -) => (a.label || "").localeCompare(b.label || ""); - export const CountryPicker = ({ autoSortOptions = true, exclude, @@ -281,10 +223,7 @@ export const CountryPicker = ({ const handleOnChange = useCallback( (value: T | T[]) => { - if (!properties.onChange) { - return; - } - + if (!properties.onChange) return; const result = Array.isArray(value) ? (Array.from(new Set(value)) as T[]) : value; From d127cb3ba0649225f3b940ecea630b94deb266d7 Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Fri, 16 Jan 2026 17:06:38 +0545 Subject: [PATCH 09/12] refactor(ui/country-picker): update sorting logic --- .../src/FormWidgets/CountryPicker/index.tsx | 60 +++++++++++++------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/packages/ui/src/FormWidgets/CountryPicker/index.tsx b/packages/ui/src/FormWidgets/CountryPicker/index.tsx index 18eda601f..28cd63f48 100644 --- a/packages/ui/src/FormWidgets/CountryPicker/index.tsx +++ b/packages/ui/src/FormWidgets/CountryPicker/index.tsx @@ -24,10 +24,18 @@ const getLabel = ( }; const sortByLabel = ( - a: Option | OptionGroup, - b: Option | OptionGroup, + optionA: Option | OptionGroup, + optionB: Option | OptionGroup, ) => { - return (a.label || "").localeCompare(b.label || ""); + if (!optionA.label) { + return 1; + } + + if (!optionB.label) { + return -1; + } + + return optionA.label.localeCompare(optionB.label); }; const getFavoriteOptions = ( @@ -41,10 +49,12 @@ const getFavoriteOptions = ( return []; } - const options = favorites.map((code) => ({ - value: code as unknown as T, - label: getLabel(code, locale, locales, fallbackTranslation), - })); + const options = favorites.map((code) => { + return { + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackTranslation), + }; + }); if (autoSortOptions) { options.sort(sortByLabel); @@ -66,11 +76,13 @@ const getFullList = ( autoSortOptions: boolean, ): Option[] | OptionGroup[] => { if (groups && Object.keys(groups).length > 0) { - return Object.entries(groups).map(([groupKey, groupCodes]) => { - const groupOptions = groupCodes.map((code) => ({ - value: code as unknown as T, - label: getLabel(code, locale, locales, fallbackTranslation), - })); + const groupList = Object.entries(groups).map(([groupKey, groupCodes]) => { + const groupOptions = groupCodes.map((code) => { + return { + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackTranslation), + }; + }); if (autoSortOptions) { groupOptions.sort(sortByLabel); @@ -81,6 +93,12 @@ const getFullList = ( options: groupOptions, }; }); + + if (autoSortOptions) { + groupList.sort(sortByLabel); + } + + return groupList; } const codes = include || Object.keys(fallbackTranslation); @@ -97,12 +115,16 @@ const getFullList = ( return true; }) - .map((code) => ({ - value: code as unknown as T, - label: getLabel(code, locale, locales, fallbackTranslation), - })); + .map((code) => { + return { + value: code as unknown as T, + label: getLabel(code, locale, locales, fallbackTranslation), + }; + }); - if (autoSortOptions) options.sort(sortByLabel); + if (autoSortOptions) { + options.sort(sortByLabel); + } if (favorites.length > 0) { return [ @@ -223,7 +245,9 @@ export const CountryPicker = ({ const handleOnChange = useCallback( (value: T | T[]) => { - if (!properties.onChange) return; + if (!properties.onChange) { + return; + } const result = Array.isArray(value) ? (Array.from(new Set(value)) as T[]) : value; From fcd473622a8c3b68e3230fc45a6b1f664f589ea2 Mon Sep 17 00:00:00 2001 From: Utsav Luintel Date: Mon, 19 Jan 2026 10:16:09 +0545 Subject: [PATCH 10/12] refactor(ui/country-picker): update demo --- .../src/Views/Ui/components/FormWidgets/CountryPicker.tsx | 8 ++++---- packages/ui/src/FormWidgets/CountryPicker/index.tsx | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/demo/src/Views/Ui/components/FormWidgets/CountryPicker.tsx b/apps/demo/src/Views/Ui/components/FormWidgets/CountryPicker.tsx index cb18e05d1..c1666a27f 100644 --- a/apps/demo/src/Views/Ui/components/FormWidgets/CountryPicker.tsx +++ b/apps/demo/src/Views/Ui/components/FormWidgets/CountryPicker.tsx @@ -497,14 +497,14 @@ const selectedLocale = i18n.language; />