@comitor/ui 3.0.0 → 3.1.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 +5 -1
- package/dist/components/composite/confirm-dialog.js +56 -35
- package/dist/components/composite/confirm-dialog.js.map +1 -1
- package/dist/components/composite/search-filter-bar-constants.d.ts +3 -0
- package/dist/components/composite/search-filter-bar-constants.js.map +1 -1
- package/dist/components/composite/table-pagination-constants.d.ts +3 -1
- package/dist/components/composite/table-pagination-constants.js.map +1 -1
- package/dist/components/composite/table-pagination.js +10 -2
- package/dist/components/composite/table-pagination.js.map +1 -1
- package/dist/components/composite/text-utils.d.ts +4 -23
- package/dist/components/composite/text-utils.js +1 -11
- package/dist/components/composite/text-utils.js.map +1 -1
- package/dist/components/composite/toast.d.ts +2 -1
- package/dist/components/composite/toast.js +3 -9
- package/dist/components/composite/toast.js.map +1 -1
- package/dist/components/ui/action-bar.js +45 -1
- package/dist/components/ui/action-bar.js.map +1 -1
- package/dist/components/ui/banner.d.ts +8 -0
- package/dist/components/ui/banner.js +149 -35
- package/dist/components/ui/banner.js.map +1 -1
- package/dist/components/ui/circular-progress.js +10 -2
- package/dist/components/ui/circular-progress.js.map +1 -1
- package/dist/components/ui/kanban.js +9 -3
- package/dist/components/ui/kanban.js.map +1 -1
- package/dist/components/ui/key-value.js +70 -76
- package/dist/components/ui/key-value.js.map +1 -1
- package/dist/components/ui/mask-input-constants.d.ts +34 -2
- package/dist/components/ui/mask-input-constants.js +87 -76
- package/dist/components/ui/mask-input-constants.js.map +1 -1
- package/dist/components/ui/mask-input.d.ts +6 -5
- package/dist/components/ui/mask-input.js +23 -21
- package/dist/components/ui/mask-input.js.map +1 -1
- package/dist/components/ui/mention.d.ts +14 -2
- package/dist/components/ui/mention.js +33 -6
- package/dist/components/ui/mention.js.map +1 -1
- package/dist/components/ui/phone-input.d.ts +18 -8
- package/dist/components/ui/phone-input.js +125 -35
- package/dist/components/ui/phone-input.js.map +1 -1
- package/dist/components/ui/rating.js +4 -2
- package/dist/components/ui/rating.js.map +1 -1
- package/dist/components/ui/scroll-spy.js +46 -31
- package/dist/components/ui/scroll-spy.js.map +1 -1
- package/dist/components/ui/slider.d.ts +1 -1
- package/dist/components/ui/slider.js +15 -1
- package/dist/components/ui/slider.js.map +1 -1
- package/dist/components/ui/sonner.js +2 -0
- package/dist/components/ui/sonner.js.map +1 -1
- package/dist/components/ui/stepper.js +26 -3
- package/dist/components/ui/stepper.js.map +1 -1
- package/dist/components/ui/time-picker.d.ts +24 -4
- package/dist/components/ui/time-picker.js +425 -162
- package/dist/components/ui/time-picker.js.map +1 -1
- package/dist/components/ui/timeline.js +45 -9
- package/dist/components/ui/timeline.js.map +1 -1
- package/dist/components/ui/toggle-group.js +12 -1
- package/dist/components/ui/toggle-group.js.map +1 -1
- package/dist/components/ui/tour.js +3 -2
- package/dist/components/ui/tour.js.map +1 -1
- package/dist/data-grid/data-grid-cell-variants.js +4 -4
- package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.d.ts +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.js +6 -0
- package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -1
- package/dist/data-grid/data-grid-row.js +1 -1
- package/dist/data-grid/data-grid-row.js.map +1 -1
- package/dist/data-grid/data-grid-select-column.js +6 -2
- package/dist/data-grid/data-grid-select-column.js.map +1 -1
- package/dist/data-grid/data-grid-skeleton.d.ts +5 -0
- package/dist/data-grid/data-grid-skeleton.js +1 -4
- package/dist/data-grid/data-grid-skeleton.js.map +1 -1
- package/dist/data-grid/data-grid.d.ts +1 -1
- package/dist/data-grid/data-grid.js +3 -2
- package/dist/data-grid/data-grid.js.map +1 -1
- package/dist/data-grid/filters.js +3 -2
- package/dist/data-grid/filters.js.map +1 -1
- package/dist/data-grid/types.d.ts +7 -0
- package/dist/data-grid/use-data-grid.d.ts +1 -0
- package/dist/data-grid/use-data-grid.js +70 -24
- package/dist/data-grid/use-data-grid.js.map +1 -1
- package/dist/data-grid/utils.d.ts +7 -0
- package/dist/data-grid/utils.js +3 -1
- package/dist/data-grid/utils.js.map +1 -1
- package/dist/i18n/locale-provider.d.ts +18 -0
- package/dist/i18n/locale-provider.js.map +1 -1
- package/dist/i18n/namespaces/rating.js +2 -1
- package/dist/i18n/namespaces/rating.js.map +1 -1
- package/dist/i18n/namespaces/search-filter-bar.js +8 -6
- package/dist/i18n/namespaces/search-filter-bar.js.map +1 -1
- package/dist/i18n/namespaces/shell.d.ts +4 -0
- package/dist/i18n/namespaces/shell.js +1 -1
- package/dist/i18n/namespaces/shell.js.map +1 -1
- package/dist/i18n/namespaces/table-pagination.js +6 -4
- package/dist/i18n/namespaces/table-pagination.js.map +1 -1
- package/dist/i18n/namespaces/toast.d.ts +3 -2
- package/dist/i18n/namespaces/toast.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/lib/collect-item-elements.d.ts +47 -0
- package/dist/lib/collect-item-elements.js +22 -0
- package/dist/lib/collect-item-elements.js.map +1 -0
- package/dist/lib/text-search.d.ts +32 -0
- package/dist/lib/text-search.js +17 -0
- package/dist/lib/text-search.js.map +1 -0
- package/dist/lib/toast-language.d.ts +8 -0
- package/dist/lib/toast-language.js +19 -0
- package/dist/lib/toast-language.js.map +1 -0
- package/dist/shell/app-shell.d.ts +1 -0
- package/dist/shell/index.d.ts +2 -1
- package/dist/shell/shell-context.d.ts +1 -0
- package/dist/shell/utils.d.ts +2 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/phone-input.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/phone-input) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { defaultFilter } from \"cmdk\";\nimport { Check, ChevronDown, Globe } from \"lucide-react\";\nimport * as React from \"react\";\nimport { useComitorLabels, useComitorLocale } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { VisuallyHiddenInput } from \"../../lib/visually-hidden-input.js\";\nimport { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from \"./command.js\";\nimport { Input } from \"./input.js\";\nimport type { PhoneInputCountry as Country, PhoneInputLabels } from \"./phone-input-constants.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover.js\";\n\nconst ROOT_NAME = \"PhoneInput\";\nconst COUNTRY_SELECT_NAME = \"PhoneInputCountrySelect\";\nconst FIELD_NAME = \"PhoneInputField\";\n\n/*\n * Quốc gia mặc định: KHÔNG CÓ — như thượng nguồn (nút chọn hiện quả địa cầu, chưa chọn gì). Nước\n * là thiết lập của VÙNG, không phải của ngôn ngữ (xem `src/i18n/locale.ts`): app Comitor truyền\n * `defaultCountry` / `country` từ cài đặt workspace. Trước `3.0.0` mặc định cứng là `\"VN\"`.\n *\n * ⚠ Khác thượng nguồn: tên quốc gia theo `locale` của `ComitorLocaleProvider` (prop `locale` đè)\n * thay vì ghim tiếng Anh. Trước `3.0.0` mặc định cứng là `\"vi\"`.\n */\n\n/**\n * Bảng mã quay số theo quốc gia (≈250 nước), dạng `[iso2, mã quay số]`.\n * @see https://github.com/mukeshsoni/country-telephone-data/blob/master/country_telephone_data.js\n * @format [iso2, dialCode]\n */\nconst COUNTRY_DATA: [string, string][] = [\n [\"af\", \"93\"],\n [\"ax\", \"358\"],\n [\"al\", \"355\"],\n [\"dz\", \"213\"],\n [\"as\", \"1684\"],\n [\"ad\", \"376\"],\n [\"ao\", \"244\"],\n [\"ai\", \"1264\"],\n [\"ag\", \"1268\"],\n [\"ar\", \"54\"],\n [\"am\", \"374\"],\n [\"aw\", \"297\"],\n [\"au\", \"61\"],\n [\"at\", \"43\"],\n [\"az\", \"994\"],\n [\"bs\", \"1242\"],\n [\"bh\", \"973\"],\n [\"bd\", \"880\"],\n [\"bb\", \"1246\"],\n [\"by\", \"375\"],\n [\"be\", \"32\"],\n [\"bz\", \"501\"],\n [\"bj\", \"229\"],\n [\"bm\", \"1441\"],\n [\"bt\", \"975\"],\n [\"bo\", \"591\"],\n [\"ba\", \"387\"],\n [\"bw\", \"267\"],\n [\"br\", \"55\"],\n [\"io\", \"246\"],\n [\"vg\", \"1284\"],\n [\"bn\", \"673\"],\n [\"bg\", \"359\"],\n [\"bf\", \"226\"],\n [\"bi\", \"257\"],\n [\"kh\", \"855\"],\n [\"cm\", \"237\"],\n [\"ca\", \"1\"],\n [\"cv\", \"238\"],\n [\"bq\", \"599\"],\n [\"ky\", \"1345\"],\n [\"cf\", \"236\"],\n [\"td\", \"235\"],\n [\"cl\", \"56\"],\n [\"cn\", \"86\"],\n [\"co\", \"57\"],\n [\"km\", \"269\"],\n [\"cd\", \"243\"],\n [\"cg\", \"242\"],\n [\"ck\", \"682\"],\n [\"cr\", \"506\"],\n [\"ci\", \"225\"],\n [\"hr\", \"385\"],\n [\"cu\", \"53\"],\n [\"cw\", \"599\"],\n [\"cy\", \"357\"],\n [\"cz\", \"420\"],\n [\"dk\", \"45\"],\n [\"dj\", \"253\"],\n [\"dm\", \"1767\"],\n [\"do\", \"1\"],\n [\"ec\", \"593\"],\n [\"eg\", \"20\"],\n [\"sv\", \"503\"],\n [\"gq\", \"240\"],\n [\"er\", \"291\"],\n [\"ee\", \"372\"],\n [\"et\", \"251\"],\n [\"fk\", \"500\"],\n [\"fo\", \"298\"],\n [\"fj\", \"679\"],\n [\"fi\", \"358\"],\n [\"fr\", \"33\"],\n [\"gf\", \"594\"],\n [\"pf\", \"689\"],\n [\"ga\", \"241\"],\n [\"gm\", \"220\"],\n [\"ge\", \"995\"],\n [\"de\", \"49\"],\n [\"gh\", \"233\"],\n [\"gi\", \"350\"],\n [\"gr\", \"30\"],\n [\"gl\", \"299\"],\n [\"gd\", \"1473\"],\n [\"gp\", \"590\"],\n [\"gu\", \"1671\"],\n [\"gt\", \"502\"],\n [\"gg\", \"44\"],\n [\"gn\", \"224\"],\n [\"gw\", \"245\"],\n [\"gy\", \"592\"],\n [\"ht\", \"509\"],\n [\"hn\", \"504\"],\n [\"hk\", \"852\"],\n [\"hu\", \"36\"],\n [\"is\", \"354\"],\n [\"in\", \"91\"],\n [\"id\", \"62\"],\n [\"ir\", \"98\"],\n [\"iq\", \"964\"],\n [\"ie\", \"353\"],\n [\"im\", \"44\"],\n [\"il\", \"972\"],\n [\"it\", \"39\"],\n [\"jm\", \"1876\"],\n [\"jp\", \"81\"],\n [\"je\", \"44\"],\n [\"jo\", \"962\"],\n [\"kz\", \"7\"],\n [\"ke\", \"254\"],\n [\"ki\", \"686\"],\n [\"xk\", \"383\"],\n [\"kw\", \"965\"],\n [\"kg\", \"996\"],\n [\"la\", \"856\"],\n [\"lv\", \"371\"],\n [\"lb\", \"961\"],\n [\"ls\", \"266\"],\n [\"lr\", \"231\"],\n [\"ly\", \"218\"],\n [\"li\", \"423\"],\n [\"lt\", \"370\"],\n [\"lu\", \"352\"],\n [\"mo\", \"853\"],\n [\"mk\", \"389\"],\n [\"mg\", \"261\"],\n [\"mw\", \"265\"],\n [\"my\", \"60\"],\n [\"mv\", \"960\"],\n [\"ml\", \"223\"],\n [\"mt\", \"356\"],\n [\"mh\", \"692\"],\n [\"mq\", \"596\"],\n [\"mr\", \"222\"],\n [\"mu\", \"230\"],\n [\"mx\", \"52\"],\n [\"fm\", \"691\"],\n [\"md\", \"373\"],\n [\"mc\", \"377\"],\n [\"mn\", \"976\"],\n [\"me\", \"382\"],\n [\"ms\", \"1664\"],\n [\"ma\", \"212\"],\n [\"mz\", \"258\"],\n [\"mm\", \"95\"],\n [\"na\", \"264\"],\n [\"nr\", \"674\"],\n [\"np\", \"977\"],\n [\"nl\", \"31\"],\n [\"nc\", \"687\"],\n [\"nz\", \"64\"],\n [\"ni\", \"505\"],\n [\"ne\", \"227\"],\n [\"ng\", \"234\"],\n [\"nu\", \"683\"],\n [\"nf\", \"672\"],\n [\"kp\", \"850\"],\n [\"mp\", \"1670\"],\n [\"no\", \"47\"],\n [\"om\", \"968\"],\n [\"pk\", \"92\"],\n [\"pw\", \"680\"],\n [\"ps\", \"970\"],\n [\"pa\", \"507\"],\n [\"pg\", \"675\"],\n [\"py\", \"595\"],\n [\"pe\", \"51\"],\n [\"ph\", \"63\"],\n [\"pl\", \"48\"],\n [\"pt\", \"351\"],\n [\"pr\", \"1\"],\n [\"qa\", \"974\"],\n [\"re\", \"262\"],\n [\"ro\", \"40\"],\n [\"ru\", \"7\"],\n [\"rw\", \"250\"],\n [\"bl\", \"590\"],\n [\"sh\", \"290\"],\n [\"kn\", \"1869\"],\n [\"lc\", \"1758\"],\n [\"mf\", \"590\"],\n [\"pm\", \"508\"],\n [\"vc\", \"1784\"],\n [\"ws\", \"685\"],\n [\"sm\", \"378\"],\n [\"st\", \"239\"],\n [\"sa\", \"966\"],\n [\"sn\", \"221\"],\n [\"rs\", \"381\"],\n [\"sc\", \"248\"],\n [\"sl\", \"232\"],\n [\"sg\", \"65\"],\n [\"sx\", \"1721\"],\n [\"sk\", \"421\"],\n [\"si\", \"386\"],\n [\"sb\", \"677\"],\n [\"so\", \"252\"],\n [\"za\", \"27\"],\n [\"kr\", \"82\"],\n [\"ss\", \"211\"],\n [\"es\", \"34\"],\n [\"lk\", \"94\"],\n [\"sd\", \"249\"],\n [\"sr\", \"597\"],\n [\"sz\", \"268\"],\n [\"se\", \"46\"],\n [\"ch\", \"41\"],\n [\"sy\", \"963\"],\n [\"tw\", \"886\"],\n [\"tj\", \"992\"],\n [\"tz\", \"255\"],\n [\"th\", \"66\"],\n [\"tl\", \"670\"],\n [\"tg\", \"228\"],\n [\"tk\", \"690\"],\n [\"to\", \"676\"],\n [\"tt\", \"1868\"],\n [\"tn\", \"216\"],\n [\"tr\", \"90\"],\n [\"tm\", \"993\"],\n [\"tc\", \"1649\"],\n [\"tv\", \"688\"],\n [\"vi\", \"1340\"],\n [\"ug\", \"256\"],\n [\"ua\", \"380\"],\n [\"ae\", \"971\"],\n [\"gb\", \"44\"],\n [\"us\", \"1\"],\n [\"uy\", \"598\"],\n [\"uz\", \"998\"],\n [\"vu\", \"678\"],\n [\"va\", \"39\"],\n [\"ve\", \"58\"],\n [\"vn\", \"84\"],\n [\"wf\", \"681\"],\n [\"eh\", \"212\"],\n [\"ye\", \"967\"],\n [\"zm\", \"260\"],\n [\"zw\", \"263\"]\n];\n\nfunction getCountryName(countryCode: string, regionNames: Intl.DisplayNames | undefined): string {\n try {\n return regionNames?.of(countryCode) ?? countryCode;\n } catch {\n return countryCode;\n }\n}\n\nfunction getFlagEmoji(countryCode: string): string {\n const codePoints = countryCode\n .toUpperCase()\n .split(\"\")\n .map((char) => 127397 + char.charCodeAt(0));\n return String.fromCodePoint(...codePoints);\n}\n\n/*\n * ⚠ Khác thượng nguồn, ba chỗ:\n * 1. Tên theo `locale` (mặc định: `locale` của `ComitorLocaleProvider`) thay vì ghim \"en\".\n * 2. `Intl.DisplayNames` + `Intl.Collator` dựng MỘT lần cho cả danh sách. Thượng nguồn dựng\n * `DisplayNames` cho từng nước (≈250 lần) và gọi hàm này làm giá trị mặc định của prop, tức\n * MỖI LƯỢT RENDER — mỗi phím gõ vào ô số là dựng lại cả danh sách.\n * 3. Sắp xếp bằng collator của đúng `locale` đó (\"Đan Mạch\" sau \"Dominica\" như từ điển tiếng\n * Việt), không theo locale mặc định của máy chạy — server và trình duyệt mới ra cùng thứ tự.\n */\nfunction getCountries(locale: string): Country[] {\n let regionNames: Intl.DisplayNames | undefined;\n let collator: Intl.Collator | undefined;\n try {\n regionNames = new Intl.DisplayNames([locale], { type: \"region\" });\n collator = new Intl.Collator(locale);\n } catch {\n // `locale` không hợp lệ → tên rơi về mã nước, thứ tự theo `localeCompare` mặc định.\n }\n\n return COUNTRY_DATA.map(([iso2, dialCode]): Country => {\n const code = iso2.toUpperCase();\n return {\n code,\n name: getCountryName(code, regionNames),\n dialCode: `+${dialCode}`,\n flag: getFlagEmoji(code)\n };\n }).sort((a, b) => (collator ? collator.compare(a.name, b.name) : a.name.localeCompare(b.name)));\n}\n\n/*\n * ⚠ Khác thượng nguồn: tìm quốc gia KHÔNG DẤU — gõ \"viet nam\" ra \"Việt Nam\", \"duc\" ra \"Đức\".\n * Vẫn dùng `defaultFilter` của cmdk (giữ cách chấm điểm/xếp hạng của thượng nguồn), chỉ bỏ dấu\n * hai vế trước khi so. Chuẩn hoá viết tại chỗ vì hàm bỏ dấu của gói (`removeVietnameseTones`) nằm\n * ở tầng composite, mà tầng primitive không được nhập ngược lên.\n */\nfunction removeDiacritics(text: string): string {\n return text\n .normalize(\"NFD\")\n .replace(/\\p{Diacritic}/gu, \"\")\n .replace(/đ/g, \"d\")\n .replace(/Đ/g, \"D\");\n}\n\nfunction filterCountries(value: string, search: string, keywords?: string[]): number {\n return defaultFilter(removeDiacritics(value), removeDiacritics(search), keywords?.map(removeDiacritics));\n}\n\n/*\n * ⚠ Khác thượng nguồn: 8 mã quay số trong `COUNTRY_DATA` là của CHUNG nhiều nước. Thượng nguồn chỉ\n * xử lý riêng +1 → US; mã còn lại rơi vào nước đứng TRƯỚC theo thứ tự chữ cái của TÊN, tức phụ\n * thuộc ngôn ngữ hiển thị. Đo được (ICU của Node 24): tên tiếng Anh cho +7 → Kazakhstan, +44 →\n * Guernsey, +358 → Quần đảo Åland, +599 → Ca-ri-bê Hà Lan; tên tiếng Việt cho +7 → Kazakhstan,\n * +44 → Đảo Man, +599 → Ca-ri-bê Hà Lan. Bảng này ghim nước chính của từng mã, bất kể ngôn ngữ.\n */\nconst PRIMARY_COUNTRY_BY_DIAL_CODE: Record<string, string> = {\n \"+1\": \"US\",\n \"+7\": \"RU\",\n \"+39\": \"IT\",\n \"+44\": \"GB\",\n \"+212\": \"MA\",\n \"+358\": \"FI\",\n \"+590\": \"GP\",\n \"+599\": \"CW\"\n};\n\nfunction detectCountryFromNumber(value: string, countries: Country[], currentCode?: string): Country | undefined {\n if (!value?.startsWith(\"+\")) return undefined;\n\n const digits = value.slice(1).replace(/\\D/g, \"\");\n if (!digits) return undefined;\n\n const sorted = [...countries].sort((a, b) => b.dialCode.length - a.dialCode.length);\n\n const matches: Country[] = [];\n for (const country of sorted) {\n const dialCode = country.dialCode.slice(1);\n if (digits.startsWith(dialCode)) {\n matches.push(country);\n }\n }\n\n const best = matches[0];\n if (!best) return undefined;\n\n /*\n * ⚠ Khác thượng nguồn: nhiều nước cùng khớp mã DÀI NHẤT → ưu tiên nước ĐANG CHỌN nếu nó nằm trong\n * số đó, rồi mới tới nước chính của mã. Thượng nguồn luôn trả US cho +1, nên người dùng chọn\n * \"Canada\" rồi gõ \"+1 604…\" bị lật cờ sang Hoa Kỳ ngay phím đầu tiên.\n */\n const tied = matches.filter((c) => c.dialCode === best.dialCode);\n if (tied.length > 1) {\n const current = tied.find((c) => c.code === currentCode);\n if (current) return current;\n const primary = tied.find((c) => c.code === PRIMARY_COUNTRY_BY_DIAL_CODE[best.dialCode]);\n if (primary) return primary;\n }\n\n return best;\n}\n\nfunction formatPhoneNumber(value: string, countries: Country[]): string {\n if (!value) return \"\";\n\n const normalized = value.startsWith(\"+\") ? value : `+${value}`;\n\n const digits = normalized.slice(1).replace(/\\D/g, \"\");\n if (!digits) return \"+\";\n\n const detected = detectCountryFromNumber(`+${digits}`, countries);\n const dialCodeLength = detected ? detected.dialCode.slice(1).length : Math.min(digits.length, 3);\n\n const countryCode = digits.slice(0, dialCodeLength);\n const rest = digits.slice(dialCodeLength);\n\n let formatted = `+${countryCode}`;\n\n if (rest) {\n formatted += \" \";\n for (let i = 0; i < rest.length; i++) {\n if (i > 0 && i % 3 === 0) {\n formatted += \" \";\n }\n formatted += rest[i];\n }\n }\n\n return formatted;\n}\n\n/*\n * ⚠ Khác thượng nguồn — SỐ NỘI ĐỊA. CRM/HR phải lưu số dạng E.164 (`+84912345678`), mà người Việt\n * gõ số của mình kèm số 0 đầu (`0912 345 678`). Thượng nguồn coi chữ số đầu tiên luôn là mã quốc\n * gia nên lưu ra `+0912345678` — một số không tồn tại. Luật ở đây: chuỗi gõ vào KHÔNG bắt đầu bằng\n * `+` và đang có quốc gia được chọn → đó là số NỘI ĐỊA của nước ấy: bỏ MỘT số 0 đầu (tiền tố trung\n * kế) rồi ghép mã quay số của nước đang chọn. Bắt đầu bằng `+` → như thượng nguồn (nước suy từ mã).\n * Không có quốc gia nào được chọn → như thượng nguồn. Từ `3.0.0` đó là trạng thái MẶC ĐỊNH (không\n * còn `\"VN\"` ngầm định): luật nội địa chỉ chạy khi app truyền `defaultCountry`/`country` hoặc\n * người dùng chọn nước trước khi gõ.\n *\n * `COUNTRY_DATA` không có thông tin tiền tố trung kế, nên số 0 đầu mặc định được coi là tiền tố —\n * TRỪ các nước trong bảng dưới: không có tiền tố trung kế mà số thật lại bắt đầu bằng 0 (máy bàn Ý\n * `06 …` → `+39 06 …`, cả San Marino và Vatican dùng chung luật đánh số đó). Nước có tiền tố trung\n * kế KHÁC 0 (Nga/Kazakhstan `8`, Bắc Mỹ `1`) chưa được xử lý: gõ kèm tiền tố ấy thì nó lọt vào số.\n */\nconst NO_TRUNK_PREFIX_COUNTRIES = new Set([\"IT\", \"SM\", \"VA\"]);\n\n/** Ký tự bị gạt khỏi ô khi gõ số nội địa — giữ chữ số và các dấu ngăn cách quen tay. */\nconst NATIONAL_INPUT_DISALLOWED = /[^\\d\\s().-]/g;\n\nfunction nationalToE164(nationalInput: string, country: Country): string {\n let digits = nationalInput.replace(/\\D/g, \"\");\n if (digits.startsWith(\"0\") && !NO_TRUNK_PREFIX_COUNTRIES.has(country.code)) {\n digits = digits.slice(1);\n }\n return digits ? `${country.dialCode}${digits}` : \"\";\n}\n\n/**\n * Chuỗi nội địa người dùng đang gõ — CHỈ khi nó còn khớp giá trị hiện tại. App đặt lại `value` từ\n * ngoài (reset form, nạp bản ghi khác) thì chuỗi cũ hết đúng, ô quay về dạng quốc tế đã tách nhóm.\n */\nfunction getNationalInput(state: StoreState, countries: Country[]): string | null {\n const { nationalInput, country, value } = state;\n if (nationalInput === null) return null;\n const selected = countries.find((c) => c.code === country);\n if (!selected || nationalToE164(nationalInput, selected) !== value) return null;\n return nationalInput;\n}\n\ntype RootElement = React.ComponentRef<typeof PhoneInput>;\n\ninterface StoreState {\n value: string;\n country: string;\n open: boolean;\n startsWithPlus: boolean;\n /**\n * ⚠ Thêm so với thượng nguồn: chữ người dùng gõ ở chế độ số nội địa, đúng như gõ (đã gạt ký tự\n * lạ), để ô hiện lại nguyên văn thay vì dạng `+84 …`. `null` = chế độ quốc tế của thượng nguồn.\n */\n nationalInput: string | null;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: <K extends keyof StoreState>(key: K, value: StoreState[K]) => void;\n notify: () => void;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nfunction useStore<T>(selector: (state: StoreState) => T, ogStore?: Store | null): T {\n const contextStore = React.useContext(StoreContext);\n\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`usePhoneInput\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ninterface PhoneInputContextValue {\n rootId: string;\n countries: Country[];\n placeholder: string;\n labels: PhoneInputLabels;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n invalid?: boolean;\n showFlag: boolean;\n inputRef: React.RefObject<HTMLInputElement | null>;\n}\n\nconst PhoneInputContext = React.createContext<PhoneInputContextValue | null>(null);\n\nfunction usePhoneInputContext(consumerName: string) {\n const context = React.useContext(PhoneInputContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\n/**\n * Ô nhập số điện thoại quốc tế: nút chọn quốc gia (`PhoneInputCountrySelect`) + ô số\n * (`PhoneInputField`). Giá trị (`value` / `onValueChange` / input ẩn khi submit form) luôn là E.164\n * chỉ gồm chữ số: `\"+84912345678\"`. Người dùng gõ được theo HAI cách:\n *\n * - **Số nội địa** — chuỗi KHÔNG bắt đầu bằng `+`, và đang có quốc gia được chọn (`defaultCountry`\n * / `country`, hoặc người dùng chọn): bỏ một số 0 đầu rồi ghép mã quay số của nước đang chọn. Ô hiện NGUYÊN VĂN chữ đã gõ\n * (chỉ gạt ký tự không phải số hay `space ( ) . -`), con trỏ không nhảy; đổi quốc gia thì giá trị\n * ghép lại theo mã mới, còn chữ trên ô giữ nguyên.\n * Nước là Việt Nam, gõ `0912 345 678` → ô hiện `0912 345 678`, `onValueChange(\"+84912345678\")`.\n * ⚠ Khác thượng nguồn — bản gốc ra `+0912345678`. Ý, San Marino, Vatican giữ số 0 đầu (máy bàn\n * `06 …` → `+39 06 …`).\n * - **Số quốc tế** — chuỗi bắt đầu bằng `+` (như thượng nguồn): ô hiện tách nhóm\n * (`+84 912 345 678`), quốc gia tự nhận theo mã quay số.\n * Gõ `+84 912 345 678` → `onValueChange(\"+84912345678\")`, cờ chuyển sang Việt Nam.\n *\n * Giá trị nạp từ ngoài (`value`/`defaultValue`) luôn hiện ở dạng quốc tế. Không có quốc gia nào\n * được chọn — MẶC ĐỊNH từ `3.0.0` — thì mọi chữ số đầu bị coi là mã quốc gia, như thượng nguồn:\n * gõ `0912 345 678` ra `+0912345678`, gõ `84 912 345 678` ra `+84912345678` và cờ tự nhận Việt Nam.\n *\n * Gốc là `role=\"group\"` chưa có tên: đặt `aria-label` (vd \"Phone number\") hoặc `aria-labelledby`\n * cho chính `PhoneInput`.\n */\ninterface PhoneInputProps extends React.ComponentProps<\"div\"> {\n defaultValue?: string;\n value?: string;\n onValueChange?: (value: string) => void;\n /**\n * Quốc gia ban đầu (mã ISO alpha-2, viết HOA). Mặc định: KHÔNG CÓ, như thượng nguồn — nước là\n * thiết lập VÙNG, không suy từ ngôn ngữ; app Comitor truyền từ cài đặt workspace.\n *\n * ⚠ Không có quốc gia thì chế độ số NỘI ĐỊA tắt (xem JSDoc của `PhoneInput`). Trước `3.0.0`\n * mặc định cứng là `\"VN\"`.\n */\n defaultCountry?: string;\n country?: string;\n onCountryChange?: (country: string) => void;\n countries?: Country[];\n name?: string;\n /** Placeholder ô nhập số — thắng khoá `labels.placeholder` (namespace `phoneInput`). */\n placeholder?: string;\n /**\n * Locale BCP 47 để gọi tên quốc gia (`Intl.DisplayNames`) và sắp xếp danh sách. Không truyền thì\n * theo `locale` của `ComitorLocaleProvider` (không có provider → `\"en\"`; trước `3.0.0` mặc định\n * cứng là `\"vi\"`). Bỏ qua khi app truyền `countries` riêng (tên lấy nguyên từ đó).\n *\n * ⚠ Thêm so với thượng nguồn — bản gốc ghim tên tiếng Anh.\n */\n locale?: string;\n /**\n * Chuỗi hiển thị/đọc màn hình (phần chọn quốc gia + placeholder ô số) — override từng khoá. Không\n * truyền thì theo namespace `phoneInput` của `ComitorLocaleProvider` (mặc định tiếng Anh).\n */\n labels?: Partial<PhoneInputLabels>;\n asChild?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n invalid?: boolean;\n showFlag?: boolean;\n}\n\nfunction PhoneInput(props: PhoneInputProps) {\n const {\n value: valueProp,\n defaultValue,\n defaultCountry,\n country: countryProp,\n onValueChange,\n onCountryChange,\n countries: countriesProp,\n name,\n placeholder: placeholderProp,\n locale: localeProp,\n labels: labelsProp,\n asChild,\n disabled,\n required,\n readOnly,\n invalid,\n showFlag = true,\n className,\n id,\n ref,\n ...rootProps\n } = props;\n\n const { locale: providerLocale } = useComitorLocale();\n const locale = localeProp ?? providerLocale;\n const labels = useComitorLabels(\"phoneInput\", labelsProp);\n const placeholder = placeholderProp ?? labels.placeholder;\n\n const instanceId = React.useId();\n const rootId = id ?? instanceId;\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n // ⚠ Khác thượng nguồn: ghi nhớ danh sách (thượng nguồn dựng lại mỗi lượt render — xem `getCountries`).\n const countries = React.useMemo(() => countriesProp ?? getCountries(locale), [countriesProp, locale]);\n\n const [formTrigger, setFormTrigger] = React.useState<RootElement | null>(null);\n const composedRef = useComposedRefs(ref, (node) => setFormTrigger(node));\n const isFormControl = formTrigger ? !!formTrigger.closest(\"form\") : true;\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<StoreState>(() => {\n const initialValue = valueProp ?? defaultValue ?? \"\";\n const initialCountry = countryProp ?? defaultCountry ?? \"\";\n\n return {\n value: initialValue,\n country: initialCountry,\n open: false,\n startsWithPlus: initialValue.startsWith(\"+\"),\n nationalInput: null\n };\n });\n\n const propsRef = useAsRef({\n onValueChange,\n onCountryChange,\n countries\n });\n\n const store = React.useMemo<Store>(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n if (key === \"value\" && typeof value === \"string\") {\n stateRef.current.value = value;\n propsRef.current.onValueChange?.(value);\n } else if (key === \"country\" && typeof value === \"string\") {\n // Đọc TRƯỚC khi đổi nước: chuỗi nội địa chỉ còn hiệu lực nếu khớp giá trị theo nước CŨ.\n const nationalInput = getNationalInput(stateRef.current, propsRef.current.countries);\n stateRef.current.country = value;\n propsRef.current.onCountryChange?.(value);\n\n /*\n * ⚠ Khác thượng nguồn: đang gõ số nội địa mà đổi quốc gia → chữ trên ô giờ là số nội địa\n * của nước MỚI, giá trị ghép lại mã quay số mới (ô giữ nguyên chữ). Nước mới không có\n * trong danh sách (bỏ chọn) → thôi chế độ nội địa, giữ nguyên giá trị E.164 đang có.\n */\n if (nationalInput !== null) {\n const selected = propsRef.current.countries.find((c) => c.code === value);\n if (selected) {\n const nextValue = nationalToE164(nationalInput, selected);\n if (nextValue !== stateRef.current.value) {\n stateRef.current.value = nextValue;\n propsRef.current.onValueChange?.(nextValue);\n }\n } else {\n stateRef.current.nationalInput = null;\n }\n }\n } else {\n stateRef.current[key] = value;\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n }\n };\n }, [listenersRef, stateRef, propsRef]);\n\n const value = useStore((state) => state.value, store);\n const country = useStore((state) => state.country, store);\n\n useIsomorphicLayoutEffect(() => {\n if (valueProp !== undefined) {\n store.setState(\"value\", valueProp);\n }\n }, [valueProp]);\n\n useIsomorphicLayoutEffect(() => {\n if (countryProp !== undefined) {\n store.setState(\"country\", countryProp);\n }\n }, [countryProp]);\n\n const startsWithPlus = useStore((state) => state.startsWithPlus, store);\n const nationalInput = useStore((state) => getNationalInput(state, countries), store);\n\n React.useEffect(() => {\n /*\n * ⚠ Khác thượng nguồn: đang gõ số nội địa thì quốc gia ĐANG CHỌN là nguồn sự thật — dò lại theo\n * mã quay số lúc này chỉ có thể sai: Hoa Kỳ + `340 555 1234` → `+13405551234` → dò ra Quần đảo\n * Virgin (+1340), rồi giá trị bị ghép lại theo mã mới thành số rác.\n */\n if (!value || nationalInput !== null) return;\n\n const digits = value.slice(1).replace(/\\D/g, \"\");\n const shouldDetect = startsWithPlus || digits.length >= 10;\n\n if (!shouldDetect) return;\n\n const detected = detectCountryFromNumber(value, countries, country);\n if (detected && detected.code !== country) {\n store.setState(\"country\", detected.code);\n }\n }, [value, countries, country, store, startsWithPlus, nationalInput]);\n\n const contextValue = React.useMemo<PhoneInputContextValue>(\n () => ({\n rootId,\n countries,\n placeholder,\n labels,\n disabled,\n readOnly,\n required,\n invalid,\n showFlag,\n inputRef\n }),\n [rootId, countries, placeholder, labels, disabled, required, readOnly, invalid, showFlag]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <PhoneInputContext.Provider value={contextValue}>\n <RootPrimitive\n role=\"group\"\n data-slot=\"phone-input\"\n data-disabled={disabled ? \"\" : undefined}\n data-invalid={invalid ? \"\" : undefined}\n data-readonly={readOnly ? \"\" : undefined}\n id={rootId}\n {...rootProps}\n ref={composedRef}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: khung mượn đúng vai trò màu của `Input` Comitor để đứng cạnh ô\n * nhập thường trong một form không lệch (cao `h-9` thay vì `h-10`, nền `bg-background`\n * thay vì `dark:bg-input/30` — viết thẳng thang màu thì bảng tương phản cao không đổi\n * được). Số đo từng vai trò: chú thích đầu `input.tsx`.\n *\n * Focus: thượng nguồn soi `[data-slot=input-group-control]` — slot KHÔNG tồn tại trong\n * component này, nên khung không bao giờ sáng. Ở đây soi đúng slot của ô số.\n *\n * Lỗi: HAI đường như `InputGroup` — `aria-invalid` trên ô số (prop `invalid`), hoặc\n * trên CHÍNH gốc khi `<FormControl>` của `@comitor/ui/form` dán nó vào con trực tiếp.\n * Viền lỗi là `--destructive-ink` (không phải `--destructive` — token TÔ NỀN).\n *\n * Vô hiệu: thượng nguồn làm mờ CẢ gốc (`data-disabled:opacity-50`) trong khi nút và ô\n * số bên trong cũng tự mờ theo `:disabled` → nội dung còn 25%. Ở đây gốc KHÔNG mờ (như\n * `InputGroup`); hai con tự mờ bằng `:disabled` gốc của HTML, gốc chỉ đổi nền theo ô số.\n * `data-disabled` còn không được cổng tương phản coi là trạng thái vô hiệu — nó không\n * chứng minh phần tử đã inert — còn `:disabled` thì có.\n */\n \"relative flex h-9 w-full items-center rounded-md border border-input bg-background transition-colors duration-150 ease-out hover:border-control-edge-strong\",\n \"has-[[data-slot=phone-input-field]:focus-visible]:border-primary-ink has-[[data-slot=phone-input-field]:focus-visible]:ring-2 has-[[data-slot=phone-input-field]:focus-visible]:ring-ring/50\",\n \"has-[[data-slot][aria-invalid=true]]:border-destructive-ink has-[[data-slot][aria-invalid=true]]:ring-destructive/30\",\n \"aria-invalid:border-destructive-ink aria-invalid:hover:border-destructive-ink aria-invalid:ring-destructive/30\",\n \"data-disabled:cursor-not-allowed has-[[data-slot=phone-input-field]:disabled]:bg-muted\",\n className\n )}\n />\n {isFormControl && (\n <VisuallyHiddenInput\n type=\"hidden\"\n control={formTrigger}\n name={name}\n value={value}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n />\n )}\n </PhoneInputContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface PhoneInputCountrySelectProps\n extends React.ComponentProps<typeof Popover>,\n Pick<React.ComponentProps<typeof PopoverTrigger>, \"disabled\" | \"className\"> {}\n\nfunction PhoneInputCountrySelect(props: PhoneInputCountrySelectProps) {\n const { disabled: disabledProp, className, children, onOpenChange: onOpenChangeProp, ...popoverProps } = props;\n\n const { countries, inputRef, disabled, showFlag, labels } = usePhoneInputContext(COUNTRY_SELECT_NAME);\n const store = useStoreContext(COUNTRY_SELECT_NAME);\n const country = useStore((state) => state.country);\n const open = useStore((state) => state.open);\n const onOpenChangeRef = useAsRef(onOpenChangeProp);\n\n const isDisabled = disabledProp || disabled;\n\n const countryContext = countries.find((c) => c.code === country);\n\n const onOpenChange = React.useCallback(\n (open: boolean) => {\n store.setState(\"open\", open);\n onOpenChangeRef.current?.(open);\n },\n [store, onOpenChangeRef]\n );\n\n return (\n <Popover open={open} onOpenChange={onOpenChange} {...popoverProps}>\n <PopoverTrigger\n data-slot=\"phone-input-country-select\"\n // ⚠ Khác thượng nguồn: bản gốc là một nút KHÔNG TÊN (chỉ có lá cờ emoji + mũi tên, hoặc\n // ô xám trống khi chưa chọn). Tên nói luôn giá trị hiện tại — xem `PhoneInputLabels`.\n aria-label={labels.countrySelect(countryContext)}\n disabled={isDisabled}\n className={cn(\n /*\n * Hover `bg-muted` như nút `ghost` của gói. Viền focus cùng khuôn `Button`\n * (`outline-ring`), nhưng THỤT VÀO trong (`-outline-offset-2`) vì nút nằm lọt trong khung\n * của ô — viền đẩy ra ngoài sẽ đè lên khung và lên ô số bên cạnh.\n */\n \"flex h-full shrink-0 items-center gap-2 rounded-l-md border-r border-input bg-transparent px-3 text-sm transition-colors duration-150 ease-out hover:bg-muted focus-visible:outline-2 focus-visible:outline-ring focus-visible:-outline-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n className\n )}\n >\n {/* `span` thay cho `div` của thượng nguồn: `<button>` chỉ nhận nội dung phrasing. */}\n {!countryContext ? (\n /*\n * ⚠ Khác thượng nguồn: bản gốc vẽ một ô `bg-muted/50` trống — 1,00:1 trên nền hover\n * `--muted`, tức biến mất đúng lúc người dùng rê chuột vào (cổng tương phản chặn). Quả\n * địa cầu nói được \"chưa chọn quốc gia\"; giữ bề rộng `w-6` của lá cờ để chọn xong không\n * xô lệch.\n */\n <span aria-hidden=\"true\" className=\"flex w-6 justify-center\">\n <Globe className=\"size-4 text-muted-foreground\" />\n </span>\n ) : (\n showFlag &&\n countryContext.flag && (\n <span aria-hidden=\"true\" className=\"w-6 text-lg leading-none\">\n {countryContext.flag}\n </span>\n )\n )}\n {/* Mũi tên chỉ trạng thái → ngưỡng 3:1; `text-muted-foreground` như chevron của `SelectTrigger`. */}\n <ChevronDown aria-hidden=\"true\" className=\"size-4 text-muted-foreground\" />\n </PopoverTrigger>\n <PopoverContent className=\"w-[300px] p-0\" align=\"start\">\n <Command filter={filterCountries}>\n <CommandInput placeholder={labels.searchPlaceholder} />\n <CommandList>\n <CommandEmpty>{labels.empty}</CommandEmpty>\n <CommandGroup>\n {countries.map((c) => (\n <CommandItem\n key={c.code}\n value={`${c.name} ${c.dialCode} ${c.code}`}\n onSelect={() => {\n store.setState(\"country\", c.code);\n store.setState(\"open\", false);\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n }}\n >\n {/* Cờ là trang trí — tên nước ngay bên cạnh đã nói đủ; không ẩn thì bị đọc hai lần. */}\n {showFlag && c.flag && (\n <span aria-hidden=\"true\" className=\"text-lg\">\n {c.flag}\n </span>\n )}\n <span className=\"flex-1\">{c.name}</span>\n <span className=\"text-muted-foreground\">{c.dialCode}</span>\n <Check\n aria-hidden=\"true\"\n className={cn(\"size-4\", country === c.code ? \"opacity-100\" : \"opacity-0\")}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n}\n\ntype PhoneInputFieldProps = React.ComponentProps<\"input\">;\n\nfunction PhoneInputField(props: PhoneInputFieldProps) {\n const {\n onChange: onChangeProp,\n className,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n required: requiredProp,\n placeholder: placeholderProp,\n ref,\n ...inputProps\n } = props;\n\n const { inputRef, disabled, invalid, readOnly, required, placeholder, countries } = usePhoneInputContext(FIELD_NAME);\n const store = useStoreContext(FIELD_NAME);\n const value = useStore((state) => state.value);\n const nationalInput = useStore((state) => getNationalInput(state, countries));\n\n const composedRef = useComposedRefs(ref, inputRef);\n\n const onChangeRef = useAsRef(onChangeProp);\n\n const isDisabled = disabledProp || disabled;\n const isReadOnly = readOnlyProp || readOnly;\n const isRequired = requiredProp || required;\n\n const onChange = React.useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n if (isDisabled || isReadOnly) return;\n\n onChangeRef.current?.(event);\n if (event.defaultPrevented) return;\n\n const inputValue = event.target.value;\n\n // ⚠ Khác thượng nguồn: bỏ khoảng trắng đầu trước khi xét dấu `+` — chuỗi dán vào hay kèm nó.\n const startsWithPlus = inputValue.trimStart().startsWith(\"+\");\n\n // ⚠ Khác thượng nguồn — số NỘI ĐỊA (luật và lý do: chú thích trên `nationalToE164`).\n const selectedCountry = startsWithPlus ? undefined : countries.find((c) => c.code === store.getState().country);\n\n if (selectedCountry) {\n const nextNationalInput = inputValue.replace(NATIONAL_INPUT_DISALLOWED, \"\");\n\n if (nextNationalInput !== inputValue) {\n // Gạt ký tự lạ NGAY trên DOM và đặt lại con trỏ tại chỗ: nhờ vậy lúc render React thấy\n // DOM đã đúng giá trị, không ghi đè — ghi đè là con trỏ nhảy về cuối ô.\n const target = event.target;\n const caret = target.selectionStart ?? inputValue.length;\n const nextCaret = inputValue.slice(0, caret).replace(NATIONAL_INPUT_DISALLOWED, \"\").length;\n target.value = nextNationalInput;\n target.setSelectionRange(nextCaret, nextCaret);\n }\n\n store.setState(\"startsWithPlus\", false);\n store.setState(\"nationalInput\", nextNationalInput);\n store.setState(\"value\", nationalToE164(nextNationalInput, selectedCountry));\n return;\n }\n\n const digits = inputValue.replace(/\\D/g, \"\");\n const newValue = digits ? `+${digits}` : startsWithPlus ? \"+\" : \"\";\n store.setState(\"startsWithPlus\", startsWithPlus);\n store.setState(\"nationalInput\", null);\n store.setState(\"value\", newValue);\n },\n [store, countries, onChangeRef, isDisabled, isReadOnly]\n );\n\n // Số nội địa hiện NGUYÊN VĂN chữ đã gõ (con trỏ không nhảy); số quốc tế tách nhóm như thượng nguồn.\n const displayValue = React.useMemo(() => {\n return nationalInput ?? formatPhoneNumber(value, countries);\n }, [nationalInput, value, countries]);\n\n return (\n <Input\n type=\"tel\"\n inputMode=\"tel\"\n aria-required={isRequired}\n aria-invalid={invalid}\n data-slot=\"phone-input-field\"\n disabled={isDisabled}\n readOnly={isReadOnly}\n required={isRequired}\n {...inputProps}\n ref={composedRef}\n className={cn(\n // Viền, quầng focus và nền (kể cả nền `--muted` lúc vô hiệu) đều do khung gốc vẽ; ô số\n // trong suốt và phẳng. `focus:ring-0` chứ không `focus-visible:` — `Input` vẽ quầng bằng `focus:`.\n \"h-full flex-1 rounded-l-none rounded-r-md border-0 bg-transparent focus:ring-0 disabled:bg-transparent\",\n className\n )}\n // ⚠ Khác thượng nguồn: bản gốc đặt placeholder của gốc SAU `{...inputProps}`, nên\n // `<PhoneInputField placeholder=\"…\" />` (chính demo của thượng nguồn) bị lờ đi.\n placeholder={placeholderProp ?? placeholder}\n value={displayValue}\n onChange={onChange}\n />\n );\n}\n\nexport {\n PhoneInput,\n PhoneInputCountrySelect,\n type PhoneInputCountrySelectProps,\n PhoneInputField,\n type PhoneInputFieldProps,\n type PhoneInputProps,\n useStore as usePhoneInput\n};\n"],"mappings":"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AAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,M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","names":["value","nationalInput","open"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/phone-input.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/phone-input) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { defaultFilter } from \"cmdk\";\nimport { Check, ChevronDown, Globe } from \"lucide-react\";\nimport * as React from \"react\";\nimport { useComitorLabels, useComitorLocale } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { removeVietnameseTones } from \"../../lib/text-search.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { VisuallyHiddenInput } from \"../../lib/visually-hidden-input.js\";\nimport { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from \"./command.js\";\nimport { Input } from \"./input.js\";\nimport type { PhoneInputCountry as Country, PhoneInputLabels } from \"./phone-input-constants.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover.js\";\n\nconst ROOT_NAME = \"PhoneInput\";\nconst COUNTRY_SELECT_NAME = \"PhoneInputCountrySelect\";\nconst FIELD_NAME = \"PhoneInputField\";\n\n/*\n * Quốc gia mặc định: KHÔNG CÓ — như thượng nguồn (nút chọn hiện quả địa cầu, chưa chọn gì). Nước\n * là thiết lập của VÙNG, không phải của ngôn ngữ (xem `src/i18n/locale.ts`): app Comitor truyền\n * `defaultCountry` / `country` từ cài đặt workspace. Trước `3.0.0` mặc định cứng là `\"VN\"`.\n *\n * ⚠ Khác thượng nguồn: tên quốc gia theo `locale` của `ComitorLocaleProvider` (prop `locale` đè)\n * thay vì ghim tiếng Anh. Trước `3.0.0` mặc định cứng là `\"vi\"`.\n */\n\n/**\n * Bảng mã quay số theo quốc gia (≈250 nước), dạng `[iso2, mã quay số]`.\n * @see https://github.com/mukeshsoni/country-telephone-data/blob/master/country_telephone_data.js\n * @format [iso2, dialCode]\n */\nconst COUNTRY_DATA: [string, string][] = [\n [\"af\", \"93\"],\n [\"ax\", \"358\"],\n [\"al\", \"355\"],\n [\"dz\", \"213\"],\n [\"as\", \"1684\"],\n [\"ad\", \"376\"],\n [\"ao\", \"244\"],\n [\"ai\", \"1264\"],\n [\"ag\", \"1268\"],\n [\"ar\", \"54\"],\n [\"am\", \"374\"],\n [\"aw\", \"297\"],\n [\"au\", \"61\"],\n [\"at\", \"43\"],\n [\"az\", \"994\"],\n [\"bs\", \"1242\"],\n [\"bh\", \"973\"],\n [\"bd\", \"880\"],\n [\"bb\", \"1246\"],\n [\"by\", \"375\"],\n [\"be\", \"32\"],\n [\"bz\", \"501\"],\n [\"bj\", \"229\"],\n [\"bm\", \"1441\"],\n [\"bt\", \"975\"],\n [\"bo\", \"591\"],\n [\"ba\", \"387\"],\n [\"bw\", \"267\"],\n [\"br\", \"55\"],\n [\"io\", \"246\"],\n [\"vg\", \"1284\"],\n [\"bn\", \"673\"],\n [\"bg\", \"359\"],\n [\"bf\", \"226\"],\n [\"bi\", \"257\"],\n [\"kh\", \"855\"],\n [\"cm\", \"237\"],\n [\"ca\", \"1\"],\n [\"cv\", \"238\"],\n [\"bq\", \"599\"],\n [\"ky\", \"1345\"],\n [\"cf\", \"236\"],\n [\"td\", \"235\"],\n [\"cl\", \"56\"],\n [\"cn\", \"86\"],\n [\"co\", \"57\"],\n [\"km\", \"269\"],\n [\"cd\", \"243\"],\n [\"cg\", \"242\"],\n [\"ck\", \"682\"],\n [\"cr\", \"506\"],\n [\"ci\", \"225\"],\n [\"hr\", \"385\"],\n [\"cu\", \"53\"],\n [\"cw\", \"599\"],\n [\"cy\", \"357\"],\n [\"cz\", \"420\"],\n [\"dk\", \"45\"],\n [\"dj\", \"253\"],\n [\"dm\", \"1767\"],\n [\"do\", \"1\"],\n [\"ec\", \"593\"],\n [\"eg\", \"20\"],\n [\"sv\", \"503\"],\n [\"gq\", \"240\"],\n [\"er\", \"291\"],\n [\"ee\", \"372\"],\n [\"et\", \"251\"],\n [\"fk\", \"500\"],\n [\"fo\", \"298\"],\n [\"fj\", \"679\"],\n [\"fi\", \"358\"],\n [\"fr\", \"33\"],\n [\"gf\", \"594\"],\n [\"pf\", \"689\"],\n [\"ga\", \"241\"],\n [\"gm\", \"220\"],\n [\"ge\", \"995\"],\n [\"de\", \"49\"],\n [\"gh\", \"233\"],\n [\"gi\", \"350\"],\n [\"gr\", \"30\"],\n [\"gl\", \"299\"],\n [\"gd\", \"1473\"],\n [\"gp\", \"590\"],\n [\"gu\", \"1671\"],\n [\"gt\", \"502\"],\n [\"gg\", \"44\"],\n [\"gn\", \"224\"],\n [\"gw\", \"245\"],\n [\"gy\", \"592\"],\n [\"ht\", \"509\"],\n [\"hn\", \"504\"],\n [\"hk\", \"852\"],\n [\"hu\", \"36\"],\n [\"is\", \"354\"],\n [\"in\", \"91\"],\n [\"id\", \"62\"],\n [\"ir\", \"98\"],\n [\"iq\", \"964\"],\n [\"ie\", \"353\"],\n [\"im\", \"44\"],\n [\"il\", \"972\"],\n [\"it\", \"39\"],\n [\"jm\", \"1876\"],\n [\"jp\", \"81\"],\n [\"je\", \"44\"],\n [\"jo\", \"962\"],\n [\"kz\", \"7\"],\n [\"ke\", \"254\"],\n [\"ki\", \"686\"],\n [\"xk\", \"383\"],\n [\"kw\", \"965\"],\n [\"kg\", \"996\"],\n [\"la\", \"856\"],\n [\"lv\", \"371\"],\n [\"lb\", \"961\"],\n [\"ls\", \"266\"],\n [\"lr\", \"231\"],\n [\"ly\", \"218\"],\n [\"li\", \"423\"],\n [\"lt\", \"370\"],\n [\"lu\", \"352\"],\n [\"mo\", \"853\"],\n [\"mk\", \"389\"],\n [\"mg\", \"261\"],\n [\"mw\", \"265\"],\n [\"my\", \"60\"],\n [\"mv\", \"960\"],\n [\"ml\", \"223\"],\n [\"mt\", \"356\"],\n [\"mh\", \"692\"],\n [\"mq\", \"596\"],\n [\"mr\", \"222\"],\n [\"mu\", \"230\"],\n [\"mx\", \"52\"],\n [\"fm\", \"691\"],\n [\"md\", \"373\"],\n [\"mc\", \"377\"],\n [\"mn\", \"976\"],\n [\"me\", \"382\"],\n [\"ms\", \"1664\"],\n [\"ma\", \"212\"],\n [\"mz\", \"258\"],\n [\"mm\", \"95\"],\n [\"na\", \"264\"],\n [\"nr\", \"674\"],\n [\"np\", \"977\"],\n [\"nl\", \"31\"],\n [\"nc\", \"687\"],\n [\"nz\", \"64\"],\n [\"ni\", \"505\"],\n [\"ne\", \"227\"],\n [\"ng\", \"234\"],\n [\"nu\", \"683\"],\n [\"nf\", \"672\"],\n [\"kp\", \"850\"],\n [\"mp\", \"1670\"],\n [\"no\", \"47\"],\n [\"om\", \"968\"],\n [\"pk\", \"92\"],\n [\"pw\", \"680\"],\n [\"ps\", \"970\"],\n [\"pa\", \"507\"],\n [\"pg\", \"675\"],\n [\"py\", \"595\"],\n [\"pe\", \"51\"],\n [\"ph\", \"63\"],\n [\"pl\", \"48\"],\n [\"pt\", \"351\"],\n [\"pr\", \"1\"],\n [\"qa\", \"974\"],\n [\"re\", \"262\"],\n [\"ro\", \"40\"],\n [\"ru\", \"7\"],\n [\"rw\", \"250\"],\n [\"bl\", \"590\"],\n [\"sh\", \"290\"],\n [\"kn\", \"1869\"],\n [\"lc\", \"1758\"],\n [\"mf\", \"590\"],\n [\"pm\", \"508\"],\n [\"vc\", \"1784\"],\n [\"ws\", \"685\"],\n [\"sm\", \"378\"],\n [\"st\", \"239\"],\n [\"sa\", \"966\"],\n [\"sn\", \"221\"],\n [\"rs\", \"381\"],\n [\"sc\", \"248\"],\n [\"sl\", \"232\"],\n [\"sg\", \"65\"],\n [\"sx\", \"1721\"],\n [\"sk\", \"421\"],\n [\"si\", \"386\"],\n [\"sb\", \"677\"],\n [\"so\", \"252\"],\n [\"za\", \"27\"],\n [\"kr\", \"82\"],\n [\"ss\", \"211\"],\n [\"es\", \"34\"],\n [\"lk\", \"94\"],\n [\"sd\", \"249\"],\n [\"sr\", \"597\"],\n [\"sz\", \"268\"],\n [\"se\", \"46\"],\n [\"ch\", \"41\"],\n [\"sy\", \"963\"],\n [\"tw\", \"886\"],\n [\"tj\", \"992\"],\n [\"tz\", \"255\"],\n [\"th\", \"66\"],\n [\"tl\", \"670\"],\n [\"tg\", \"228\"],\n [\"tk\", \"690\"],\n [\"to\", \"676\"],\n [\"tt\", \"1868\"],\n [\"tn\", \"216\"],\n [\"tr\", \"90\"],\n [\"tm\", \"993\"],\n [\"tc\", \"1649\"],\n [\"tv\", \"688\"],\n [\"vi\", \"1340\"],\n [\"ug\", \"256\"],\n [\"ua\", \"380\"],\n [\"ae\", \"971\"],\n [\"gb\", \"44\"],\n [\"us\", \"1\"],\n [\"uy\", \"598\"],\n [\"uz\", \"998\"],\n [\"vu\", \"678\"],\n [\"va\", \"39\"],\n [\"ve\", \"58\"],\n [\"vn\", \"84\"],\n [\"wf\", \"681\"],\n [\"eh\", \"212\"],\n [\"ye\", \"967\"],\n [\"zm\", \"260\"],\n [\"zw\", \"263\"]\n];\n\nfunction getCountryName(countryCode: string, regionNames: Intl.DisplayNames | undefined): string {\n try {\n return regionNames?.of(countryCode) ?? countryCode;\n } catch {\n return countryCode;\n }\n}\n\nfunction getFlagEmoji(countryCode: string): string {\n const codePoints = countryCode\n .toUpperCase()\n .split(\"\")\n .map((char) => 127397 + char.charCodeAt(0));\n return String.fromCodePoint(...codePoints);\n}\n\n/*\n * ⚠ Khác thượng nguồn, ba chỗ:\n * 1. Tên theo `locale` (mặc định: `locale` của `ComitorLocaleProvider`) thay vì ghim \"en\".\n * 2. `Intl.DisplayNames` + `Intl.Collator` dựng MỘT lần cho cả danh sách. Thượng nguồn dựng\n * `DisplayNames` cho từng nước (≈250 lần) và gọi hàm này làm giá trị mặc định của prop, tức\n * MỖI LƯỢT RENDER — mỗi phím gõ vào ô số là dựng lại cả danh sách.\n * 3. Sắp xếp bằng collator của đúng `locale` đó (\"Đan Mạch\" sau \"Dominica\" như từ điển tiếng\n * Việt), không theo locale mặc định của máy chạy — server và trình duyệt mới ra cùng thứ tự.\n */\nfunction getCountries(locale: string): Country[] {\n let regionNames: Intl.DisplayNames | undefined;\n let collator: Intl.Collator | undefined;\n try {\n regionNames = new Intl.DisplayNames([locale], { type: \"region\" });\n collator = new Intl.Collator(locale);\n } catch {\n // `locale` không hợp lệ → tên rơi về mã nước, thứ tự theo `localeCompare` mặc định.\n }\n\n return COUNTRY_DATA.map(([iso2, dialCode]): Country => {\n const code = iso2.toUpperCase();\n return {\n code,\n name: getCountryName(code, regionNames),\n dialCode: `+${dialCode}`,\n flag: getFlagEmoji(code)\n };\n }).sort((a, b) => (collator ? collator.compare(a.name, b.name) : a.name.localeCompare(b.name)));\n}\n\n/*\n * ⚠ Khác thượng nguồn: tìm quốc gia KHÔNG DẤU — gõ \"viet nam\" ra \"Việt Nam\", \"duc\" ra \"Đức\".\n * Vẫn dùng `defaultFilter` của cmdk (giữ cách chấm điểm/xếp hạng của thượng nguồn), chỉ bỏ dấu\n * hai vế trước khi so — bằng CHÍNH hàm bỏ dấu của gói (`lib/text-search.ts`; tới `3.0.1` file này\n * giữ một bản chép riêng vì hàm đó còn nằm ở tầng composite).\n */\nfunction filterCountries(value: string, search: string, keywords?: string[]): number {\n return defaultFilter(\n removeVietnameseTones(value),\n removeVietnameseTones(search),\n keywords?.map(removeVietnameseTones)\n );\n}\n\n/*\n * ⚠ Khác thượng nguồn: 8 mã quay số trong `COUNTRY_DATA` là của CHUNG nhiều nước. Thượng nguồn chỉ\n * xử lý riêng +1 → US; mã còn lại rơi vào nước đứng TRƯỚC theo thứ tự chữ cái của TÊN, tức phụ\n * thuộc ngôn ngữ hiển thị. Đo được (ICU của Node 24): tên tiếng Anh cho +7 → Kazakhstan, +44 →\n * Guernsey, +358 → Quần đảo Åland, +599 → Ca-ri-bê Hà Lan; tên tiếng Việt cho +7 → Kazakhstan,\n * +44 → Đảo Man, +599 → Ca-ri-bê Hà Lan. Bảng này ghim nước chính của từng mã, bất kể ngôn ngữ.\n */\nconst PRIMARY_COUNTRY_BY_DIAL_CODE: Record<string, string> = {\n \"+1\": \"US\",\n \"+7\": \"RU\",\n \"+39\": \"IT\",\n \"+44\": \"GB\",\n \"+212\": \"MA\",\n \"+358\": \"FI\",\n \"+590\": \"GP\",\n \"+599\": \"CW\"\n};\n\nfunction detectCountryFromNumber(value: string, countries: Country[], currentCode?: string): Country | undefined {\n if (!value?.startsWith(\"+\")) return undefined;\n\n const digits = value.slice(1).replace(/\\D/g, \"\");\n if (!digits) return undefined;\n\n const sorted = [...countries].sort((a, b) => b.dialCode.length - a.dialCode.length);\n\n const matches: Country[] = [];\n for (const country of sorted) {\n const dialCode = country.dialCode.slice(1);\n if (digits.startsWith(dialCode)) {\n matches.push(country);\n }\n }\n\n const best = matches[0];\n if (!best) return undefined;\n\n /*\n * ⚠ Khác thượng nguồn: nhiều nước cùng khớp mã DÀI NHẤT → ưu tiên nước ĐANG CHỌN nếu nó nằm trong\n * số đó, rồi mới tới nước chính của mã. Thượng nguồn luôn trả US cho +1, nên người dùng chọn\n * \"Canada\" rồi gõ \"+1 604…\" bị lật cờ sang Hoa Kỳ ngay phím đầu tiên.\n */\n const tied = matches.filter((c) => c.dialCode === best.dialCode);\n if (tied.length > 1) {\n const current = tied.find((c) => c.code === currentCode);\n if (current) return current;\n const primary = tied.find((c) => c.code === PRIMARY_COUNTRY_BY_DIAL_CODE[best.dialCode]);\n if (primary) return primary;\n }\n\n return best;\n}\n\nfunction formatPhoneNumber(value: string, countries: Country[]): string {\n if (!value) return \"\";\n\n const normalized = value.startsWith(\"+\") ? value : `+${value}`;\n\n const digits = normalized.slice(1).replace(/\\D/g, \"\");\n if (!digits) return \"+\";\n\n const detected = detectCountryFromNumber(`+${digits}`, countries);\n const dialCodeLength = detected ? detected.dialCode.slice(1).length : Math.min(digits.length, 3);\n\n const countryCode = digits.slice(0, dialCodeLength);\n const rest = digits.slice(dialCodeLength);\n\n let formatted = `+${countryCode}`;\n\n if (rest) {\n formatted += \" \";\n for (let i = 0; i < rest.length; i++) {\n if (i > 0 && i % 3 === 0) {\n formatted += \" \";\n }\n formatted += rest[i];\n }\n }\n\n return formatted;\n}\n\n/*\n * ⚠ Khác thượng nguồn — SỐ NỘI ĐỊA. CRM/HR phải lưu số dạng E.164 (`+84912345678`), mà người Việt\n * gõ số của mình kèm số 0 đầu (`0912 345 678`). Thượng nguồn coi chữ số đầu tiên luôn là mã quốc\n * gia nên lưu ra `+0912345678` — một số không tồn tại. Luật ở đây: chuỗi gõ vào KHÔNG bắt đầu bằng\n * `+` và đang có quốc gia được chọn → đó là số NỘI ĐỊA của nước ấy: bỏ tiền tố trung kế của nước đó\n * (`getTrunkPrefix`) rồi ghép mã quay số của nước đang chọn. Bắt đầu bằng `+` → như thượng nguồn\n * (nước suy từ mã). Không có quốc gia nào được chọn → như thượng nguồn. Từ `3.0.0` đó là trạng thái\n * MẶC ĐỊNH (không còn `\"VN\"` ngầm định): luật nội địa chỉ chạy khi app truyền\n * `defaultCountry`/`country` hoặc người dùng chọn nước trước khi gõ.\n *\n * ⚠ Khác thượng nguồn (3.1.0) — bốn luật cho MỌI cách gõ, cùng một mục đích: không để một số sai\n * lặng lẽ vào giá trị. Trước bản này cả bốn đều lọt:\n * 1. Tiền tố trung kế theo từng NƯỚC (`TRUNK_PREFIX_BY_COUNTRY`), không còn ghim `0`: Nga\n * `8 912 345 67 89` ra `+79123456789` (trước: `+789123456789`).\n * 2. Tiền tố trung kế gõ thừa ngay SAU mã quốc gia bị bỏ: `+84 0912 345 678` ra `+84912345678`\n * (trước: `+840912345678`) — trừ nước giữ số 0 ở dạng quốc tế (Ý…).\n * 3. Tiền tố gọi QUỐC TẾ đọc như `+`: `0044 20 7946 0958` ra `+442079460958` và cờ sang Anh\n * (trước: với Việt Nam đang chọn ra `+84044…`, số 0 đầu bị coi là tiền tố trung kế).\n * 4. Tối đa 15 chữ số — trần của E.164.\n *\n * KHÔNG làm: mã quốc gia gõ THIẾU `+` sau khi đã chọn nước (`84 912 345 678` với Việt Nam ra\n * `+8484912345678`). Muốn tách nó khỏi số nội địa thật phải biết độ dài và đầu số hợp lệ của từng\n * nước — chính Việt Nam là phản ví dụ: `0845 123 456` gõ thiếu số 0 cũng bắt đầu bằng `84`, và dừng\n * ở chữ số thứ 9 thì `849 123 456` là một số VinaPhone hợp lệ. Bắc Mỹ thì tự đúng nhờ luật 1 (`1`\n * vừa là mã quốc gia vừa là tiền tố trung kế). Kiểm ở server (vd libphonenumber).\n */\n\n/** ITU-T E.164: số quốc tế dài tối đa 15 chữ số, TÍNH CẢ mã quốc gia. */\nconst E164_MAX_DIGITS = 15;\n\n/** Tiền tố trung kế của phần lớn thế giới — Việt Nam, Anh, Đức, Pháp, Trung Quốc, Nhật, Úc… */\nconst DEFAULT_TRUNK_PREFIX = \"0\";\n\n/**\n * Tiền tố TRUNG KẾ — chữ số gõ trước số khi gọi trong nước và BỎ đi khi viết dạng quốc tế\n * (`0912 345 678` ⇄ `+84 912 345 678`). Bảng chỉ ghi NGOẠI LỆ của `DEFAULT_TRUNK_PREFIX` mà biết\n * CHẮC, theo mã ISO; nước chưa chắc để mặc định — tức giữ đúng hành vi của số nội địa trước `3.1.0`.\n * Bắc Mỹ không nằm ở đây mà nhận ra theo mã quay số (`isNanp`). Mọi nước dùng CHUNG một mã quay số\n * (+7, +39, +44…) có chung luật đánh số, nên chung một giá trị ở bảng này.\n *\n * `\"\"` = KHÔNG có tiền tố trung kế, và số thật BẮT ĐẦU bằng 0 — số 0 ấy giữ nguyên ở dạng quốc tế:\n * - Ý: máy bàn `0x` (Roma `06 …` → `+39 06 …`). San Marino (`0549 …` → `+378 0549 …`) và\n * Vatican (`06 698 …` → `+39 06 698 …`) đánh số theo cùng cách.\n * - Bờ Biển Ngà: từ 31.01.2021 mọi số có 10 chữ số, di động mở đầu `01`/`05`/`07`\n * (`07 07 12 34 56` → `+225 07 07 12 34 56`).\n * - Bénin: từ 30.11.2024 thêm `01` vào trước số 8 chữ số cũ (`01 97 12 34 56` → `+229 01 97 12 34 56`).\n * Nước không có tiền tố trung kế mà số không bao giờ bắt đầu bằng 0 (Tây Ban Nha, Bồ Đào Nha, Na Uy,\n * Đan Mạch, Singapore, Hồng Kông…) cứ để mặc định: bỏ một số 0 không ai gõ là vô hại.\n * ⚠ CHƯA ghi vì chưa kiểm chắc: Congo (+242), Gabon (+241) — số di động hay viết `06 …`/`07 …`, có\n * thể cũng giữ số 0 như Bờ Biển Ngà. Có nguồn chắc chắn thì thêm vào đây.\n *\n * Tiền tố KHÁC 0:\n * - Nga, Kazakhstan (+7): `8` — `8 912 345 67 89` → `+7 912 345 67 89`. Kèm luật độ dài, xem\n * `AMBIGUOUS_TRUNK_NATIONAL_LENGTH`.\n * - Hungary (+36): `06` — `06 1 234 5678` → `+36 1 234 5678`.\n */\nconst TRUNK_PREFIX_BY_COUNTRY: Record<string, string> = {\n IT: \"\",\n SM: \"\",\n VA: \"\",\n CI: \"\",\n BJ: \"\",\n RU: \"8\",\n KZ: \"8\",\n HU: \"06\"\n};\n\n/**\n * Nước mà tiền tố trung kế CŨNG là chữ số đầu hợp lệ của một số thật, kèm độ dài CỐ ĐỊNH của số\n * quốc gia. Số của +7 luôn đúng 10 chữ số và có thể mở đầu bằng 8 (St. Petersburg `812`, số miễn phí\n * `800`), nên `8` chỉ là tiền tố trung kế khi số THỪA một chữ số: `8 812 123 45 67` (11) →\n * `+7 812 123 45 67`, còn `812 123 45 67` (10) giữ nguyên → cũng `+7 812 123 45 67`. Bỏ số 8 vô\n * điều kiện thì chính số thứ hai hỏng thành `+7 12 123 45 67`. Cái giá: lúc đang gõ `8 912…`, giá\n * trị chỉ bỏ số 8 khi chữ số thứ 11 tới.\n */\nconst AMBIGUOUS_TRUNK_NATIONAL_LENGTH: Record<string, number> = {\n RU: 10,\n KZ: 10\n};\n\n/*\n * Bắc Mỹ (NANP — Hoa Kỳ, Canada và các nước Caribe; mọi mã quay số `+1…`). Số quốc gia luôn 10 chữ\n * số (mã vùng + 7), mã vùng và mã tổng đài không bao giờ mở đầu bằng 0 hay 1 — nên tiền tố trung kế\n * `1` và tiền tố quốc tế `011` không trùng đầu với số nào. `COUNTRY_DATA` ghi mã quay số của các nước\n * Caribe KÈM mã vùng (Jamaica `+1876`): 10 chữ số gõ vào đã chứa mã vùng, chỉ còn phải ghép `+1`.\n */\nconst NANP_TRUNK_PREFIX = \"1\";\nconst NANP_NATIONAL_LENGTH = 10;\n\nfunction isNanp(country: Pick<Country, \"dialCode\">): boolean {\n return country.dialCode.startsWith(\"+1\");\n}\n\nfunction getTrunkPrefix(country: Pick<Country, \"code\" | \"dialCode\">): string {\n if (isNanp(country)) return NANP_TRUNK_PREFIX;\n return TRUNK_PREFIX_BY_COUNTRY[country.code] ?? DEFAULT_TRUNK_PREFIX;\n}\n\n/** Bỏ tiền tố trung kế ở đầu phần số QUỐC GIA — cả chuỗi số nội địa, hoặc phần đứng sau mã quốc gia. */\nfunction stripTrunkPrefix(nationalDigits: string, country: Pick<Country, \"code\" | \"dialCode\">): string {\n const prefix = getTrunkPrefix(country);\n if (!prefix || !nationalDigits.startsWith(prefix)) return nationalDigits;\n const fixedLength = AMBIGUOUS_TRUNK_NATIONAL_LENGTH[country.code];\n if (fixedLength !== undefined && nationalDigits.length <= fixedLength) return nationalDigits;\n return nationalDigits.slice(prefix.length);\n}\n\n/**\n * Tiền tố gọi QUỐC TẾ — gõ ở chỗ của `+` thì hiểu như `+`. `00` là tiền tố ITU khuyến nghị, dùng ở\n * phần lớn thế giới (Việt Nam, châu Âu, Trung Quốc, Ấn Độ…). Nó không nuốt được số nội địa thật nào:\n * nước có tiền tố trung kế `0` thì số không mở đầu bằng 0, còn nước giữ số 0 ở bảng trên thì số mở\n * đầu bằng `0` + một chữ số KHÁC 0. Không chọn nước thì cũng vậy — mã quốc gia không bắt đầu bằng 0.\n *\n * Ngoại lệ biết chắc: Bắc Mỹ nhận thêm `011`. Úc `0011`, Nhật `010` THAY cho `00` — ở hai nước này\n * `00…` là mã chọn nhà mạng, và `0011` bắt đầu bằng `00`: đọc `00` trước thì không bao giờ tới được\n * `0011`.\n * ⚠ Nước quay số quốc tế bằng `00` + mã nhà mạng (Hàn Quốc `001`, Singapore `001`/`008`, Đài Loan\n * `002`…) CHƯA được hiểu: `001 44 …` đọc thành `+1 44 …`. Ở đó người dùng gõ `+`.\n */\nconst DEFAULT_EXIT_PREFIXES = [\"00\"];\nconst NANP_EXIT_PREFIXES = [\"011\", \"00\"];\nconst EXIT_PREFIXES_BY_COUNTRY: Record<string, string[]> = {\n AU: [\"0011\"],\n JP: [\"010\"]\n};\n\n/** Chữ số đứng SAU tiền tố quốc tế nếu `digits` mở đầu bằng một tiền tố như thế; không thì `null`. */\nfunction stripExitPrefix(digits: string, country: Pick<Country, \"code\" | \"dialCode\"> | undefined): string | null {\n const prefixes = !country\n ? DEFAULT_EXIT_PREFIXES\n : isNanp(country)\n ? NANP_EXIT_PREFIXES\n : (EXIT_PREFIXES_BY_COUNTRY[country.code] ?? DEFAULT_EXIT_PREFIXES);\n const prefix = prefixes.find((candidate) => digits.startsWith(candidate));\n return prefix === undefined ? null : digits.slice(prefix.length);\n}\n\n/**\n * Mã quay số khớp đầu `digits`, tra ở `COUNTRY_DATA` — KHÔNG ở prop `countries`: luật đánh số của\n * một số không đổi theo việc app cho chọn những nước nào. Mã quốc gia không mã nào là đầu của mã\n * khác (trừ Bắc Mỹ, mà `normalizeInternationalDigits` xử lý trước), nên khớp là khớp duy nhất.\n */\nfunction findCallingCode(digits: string): { code: string; dialCode: string } | undefined {\n const entry = COUNTRY_DATA.find(([, dialCode]) => digits.startsWith(dialCode));\n return entry ? { code: entry[0].toUpperCase(), dialCode: `+${entry[1]}` } : undefined;\n}\n\n/**\n * Chữ số của một số QUỐC TẾ (sau `+`, không kèm nó) → chữ số E.164: bỏ tiền tố trung kế gõ thừa\n * ngay sau mã quốc gia, rồi chặn ở 15 chữ số.\n */\nfunction normalizeInternationalDigits(digits: string): string {\n let normalized = digits;\n if (digits.startsWith(\"1\")) {\n // Bắc Mỹ: mã quốc gia là `1` kể cả khi bảng ghi `1876` — tiền tố trung kế đứng ngay sau `1`.\n if (digits.startsWith(NANP_TRUNK_PREFIX, 1)) normalized = `1${digits.slice(2)}`;\n } else {\n const callingCode = findCallingCode(digits);\n if (callingCode) {\n const countryCode = callingCode.dialCode.slice(1);\n normalized = `${countryCode}${stripTrunkPrefix(digits.slice(countryCode.length), callingCode)}`;\n }\n }\n return normalized.slice(0, E164_MAX_DIGITS);\n}\n\n/** Ký tự bị gạt khỏi ô khi gõ số nội địa — giữ chữ số và các dấu ngăn cách quen tay. */\nconst NATIONAL_INPUT_DISALLOWED = /[^\\d\\s().-]/g;\n\n/** Số NỘI ĐỊA của `country` → chữ số E.164, không `+` và CHƯA chặn độ dài. */\nfunction nationalToE164Digits(nationalInput: string, country: Country): string {\n const national = stripTrunkPrefix(nationalInput.replace(/\\D/g, \"\"), country);\n if (!national) return \"\";\n // Bắc Mỹ: 10 chữ số đã chứa mã vùng — Jamaica, gõ `876 555 1234` → `+1 876 555 1234`, không phải `+1876 876…`.\n const countryCode = isNanp(country) && national.length === NANP_NATIONAL_LENGTH ? \"1\" : country.dialCode.slice(1);\n return `${countryCode}${national}`;\n}\n\nfunction nationalToE164(nationalInput: string, country: Country): string {\n const digits = nationalToE164Digits(nationalInput, country);\n return digits ? `+${digits.slice(0, E164_MAX_DIGITS)}` : \"\";\n}\n\n/**\n * Cắt chuỗi nội địa ngay TRƯỚC chữ số đẩy số E.164 quá 15 chữ số (phần sau bỏ luôn). Ô hiện nguyên\n * văn chữ đã gõ, nên chữ số không vào được giá trị thì cũng không được nằm lại trên ô.\n */\nfunction limitNationalInput(nationalInput: string, country: Country): string {\n for (let i = 0; i < nationalInput.length; i++) {\n if (!/\\d/.test(nationalInput.charAt(i))) continue;\n if (nationalToE164Digits(nationalInput.slice(0, i + 1), country).length > E164_MAX_DIGITS) {\n return nationalInput.slice(0, i);\n }\n }\n return nationalInput;\n}\n\ninterface TypedNumber {\n value: string;\n /** Chữ nội địa để hiện NGUYÊN VĂN; `null` = dạng quốc tế (ô hiện giá trị đã tách nhóm). */\n nationalInput: string | null;\n /** Ô hiện dạng `+…` — lúc ấy quốc gia dò lại ngay theo mã quay số. */\n startsWithPlus: boolean;\n}\n\n/**\n * Chữ trên ô → trạng thái mới, dưới quốc gia `country` (`undefined` = chưa chọn). THUẦN: phần DOM\n * (gạt ký tự, giữ con trỏ) do `PhoneInputField` làm. Đổi quốc gia cũng đi qua đây — chữ nội địa đang\n * có được đọc lại như thể vừa gõ dưới nước mới.\n */\nfunction parseTypedNumber(inputValue: string, country: Country | undefined): TypedNumber {\n // ⚠ Khác thượng nguồn: bỏ khoảng trắng đầu trước khi xét dấu `+` — chuỗi dán vào hay kèm nó.\n const startsWithPlus = inputValue.trimStart().startsWith(\"+\");\n const digits = inputValue.replace(/\\D/g, \"\");\n // Sau `+` tiền tố quốc tế là gõ thừa (không mã quốc gia nào bắt đầu bằng 0): `+0044` → `+44`.\n const afterExitPrefix = stripExitPrefix(digits, country);\n\n if (!startsWithPlus && country && afterExitPrefix === null) {\n const nationalInput = limitNationalInput(inputValue.replace(NATIONAL_INPUT_DISALLOWED, \"\"), country);\n return { value: nationalToE164(nationalInput, country), nationalInput, startsWithPlus: false };\n }\n\n // Số quốc tế — hoặc chưa chọn nước: mọi chữ số đầu là mã quốc gia, như thượng nguồn.\n const international = startsWithPlus || afterExitPrefix !== null;\n const e164Digits = normalizeInternationalDigits(afterExitPrefix ?? digits);\n return {\n value: e164Digits ? `+${e164Digits}` : international ? \"+\" : \"\",\n nationalInput: null,\n startsWithPlus: international\n };\n}\n\n/**\n * Chuỗi nội địa người dùng đang gõ — CHỈ khi nó còn khớp giá trị hiện tại. App đặt lại `value` từ\n * ngoài (reset form, nạp bản ghi khác) thì chuỗi cũ hết đúng, ô quay về dạng quốc tế đã tách nhóm.\n */\nfunction getNationalInput(state: StoreState, countries: Country[]): string | null {\n const { nationalInput, country, value } = state;\n if (nationalInput === null) return null;\n const selected = countries.find((c) => c.code === country);\n if (!selected || nationalToE164(nationalInput, selected) !== value) return null;\n return nationalInput;\n}\n\ntype RootElement = React.ComponentRef<typeof PhoneInput>;\n\ninterface StoreState {\n value: string;\n country: string;\n open: boolean;\n startsWithPlus: boolean;\n /**\n * ⚠ Thêm so với thượng nguồn: chữ người dùng gõ ở chế độ số nội địa, đúng như gõ (đã gạt ký tự\n * lạ), để ô hiện lại nguyên văn thay vì dạng `+84 …`. `null` = chế độ quốc tế của thượng nguồn.\n */\n nationalInput: string | null;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: <K extends keyof StoreState>(key: K, value: StoreState[K]) => void;\n notify: () => void;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nfunction useStore<T>(selector: (state: StoreState) => T, ogStore?: Store | null): T {\n const contextStore = React.useContext(StoreContext);\n\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`usePhoneInput\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ninterface PhoneInputContextValue {\n rootId: string;\n countries: Country[];\n placeholder: string;\n labels: PhoneInputLabels;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n invalid?: boolean;\n showFlag: boolean;\n inputRef: React.RefObject<HTMLInputElement | null>;\n}\n\nconst PhoneInputContext = React.createContext<PhoneInputContextValue | null>(null);\n\nfunction usePhoneInputContext(consumerName: string) {\n const context = React.useContext(PhoneInputContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\n/**\n * Ô nhập số điện thoại quốc tế: nút chọn quốc gia (`PhoneInputCountrySelect`) + ô số\n * (`PhoneInputField`). Giá trị (`value` / `onValueChange` / input ẩn khi submit form) luôn là E.164\n * chỉ gồm chữ số: `\"+84912345678\"`. Người dùng gõ được theo HAI cách:\n *\n * - **Số nội địa** — chuỗi KHÔNG bắt đầu bằng `+`, và đang có quốc gia được chọn (`defaultCountry`\n * / `country`, hoặc người dùng chọn): bỏ tiền tố trung kế của nước đó rồi ghép mã quay số của nước\n * đang chọn. Ô hiện NGUYÊN VĂN chữ đã gõ (chỉ gạt ký tự không phải số hay `space ( ) . -`), con trỏ\n * không nhảy; đổi quốc gia thì giá trị ghép lại theo mã mới, còn chữ trên ô giữ nguyên.\n * Nước là Việt Nam, gõ `0912 345 678` → ô hiện `0912 345 678`, `onValueChange(\"+84912345678\")`.\n * ⚠ Khác thượng nguồn — bản gốc ra `+0912345678`. Tiền tố trung kế là `0` ở phần lớn các nước;\n * từ `3.1.0`: Nga/Kazakhstan `8` (`8 912 345 67 89` → `+79123456789`), Hungary `06`, Bắc Mỹ `1`\n * (`1 212 555 0123` → `+12125550123`). Ý, San Marino, Vatican, Bờ Biển Ngà, Bénin giữ số 0 đầu\n * (máy bàn Ý `06 …` → `+39 06 …`).\n * Mở đầu bằng tiền tố gọi quốc tế (`00`; Bắc Mỹ cả `011`; Úc `0011`; Nhật `010`) thì là số quốc\n * tế, như gõ `+` (`3.1.0`): `0044 20 7946 0958` → `+442079460958`, cờ chuyển sang Anh.\n * - **Số quốc tế** — chuỗi bắt đầu bằng `+` (như thượng nguồn): ô hiện tách nhóm\n * (`+84 912 345 678`), quốc gia tự nhận theo mã quay số.\n * Gõ `+84 912 345 678` → `onValueChange(\"+84912345678\")`, cờ chuyển sang Việt Nam.\n * ⚠ Khác thượng nguồn (3.1.0): tiền tố trung kế gõ thừa ngay sau mã bị bỏ — `+84 0912 345 678`\n * cũng ra `+84912345678` (nước giữ số 0 thì giữ: `+39 06 …`).\n *\n * Mọi cách gõ: tối đa 15 chữ số — trần của E.164 (`3.1.0`). Giá trị nạp từ ngoài\n * (`value`/`defaultValue`) luôn hiện ở dạng quốc tế và không bị sửa. Không có quốc gia nào được\n * chọn — MẶC ĐỊNH từ `3.0.0` — thì mọi chữ số đầu bị coi là mã quốc gia, như thượng nguồn: gõ\n * `0912 345 678` ra `+0912345678`, gõ `84 912 345 678` ra `+84912345678` và cờ tự nhận Việt Nam.\n *\n * ⚠ Gói KHÔNG kiểm số. Mã quốc gia gõ THIẾU `+` sau khi đã chọn nước vẫn là số nội địa (`84 912 345\n * 678` với Việt Nam ra `+8484912345678`), độ dài không được xét. Kiểm ở server (vd libphonenumber).\n *\n * Gốc là `role=\"group\"` chưa có tên: đặt `aria-label` (vd \"Phone number\") hoặc `aria-labelledby`\n * cho chính `PhoneInput`.\n */\ninterface PhoneInputProps extends React.ComponentProps<\"div\"> {\n defaultValue?: string;\n value?: string;\n onValueChange?: (value: string) => void;\n /**\n * Quốc gia ban đầu (mã ISO alpha-2, viết HOA). Mặc định: KHÔNG CÓ, như thượng nguồn — nước là\n * thiết lập VÙNG, không suy từ ngôn ngữ; app Comitor truyền từ cài đặt workspace.\n *\n * ⚠ Không có quốc gia thì chế độ số NỘI ĐỊA tắt (xem JSDoc của `PhoneInput`). Trước `3.0.0`\n * mặc định cứng là `\"VN\"`.\n */\n defaultCountry?: string;\n country?: string;\n onCountryChange?: (country: string) => void;\n countries?: Country[];\n name?: string;\n /** Placeholder ô nhập số — thắng khoá `labels.placeholder` (namespace `phoneInput`). */\n placeholder?: string;\n /**\n * Locale BCP 47 để gọi tên quốc gia (`Intl.DisplayNames`) và sắp xếp danh sách. Không truyền thì\n * theo `locale` của `ComitorLocaleProvider` (không có provider → `\"en\"`; trước `3.0.0` mặc định\n * cứng là `\"vi\"`). Bỏ qua khi app truyền `countries` riêng (tên lấy nguyên từ đó).\n *\n * ⚠ Thêm so với thượng nguồn — bản gốc ghim tên tiếng Anh.\n */\n locale?: string;\n /**\n * Chuỗi hiển thị/đọc màn hình (phần chọn quốc gia + placeholder ô số) — override từng khoá. Không\n * truyền thì theo namespace `phoneInput` của `ComitorLocaleProvider` (mặc định tiếng Anh).\n */\n labels?: Partial<PhoneInputLabels>;\n asChild?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n invalid?: boolean;\n showFlag?: boolean;\n}\n\nfunction PhoneInput(props: PhoneInputProps) {\n const {\n value: valueProp,\n defaultValue,\n defaultCountry,\n country: countryProp,\n onValueChange,\n onCountryChange,\n countries: countriesProp,\n name,\n placeholder: placeholderProp,\n locale: localeProp,\n labels: labelsProp,\n asChild,\n disabled,\n required,\n readOnly,\n invalid,\n showFlag = true,\n className,\n id,\n ref,\n ...rootProps\n } = props;\n\n const { locale: providerLocale } = useComitorLocale();\n const locale = localeProp ?? providerLocale;\n const labels = useComitorLabels(\"phoneInput\", labelsProp);\n const placeholder = placeholderProp ?? labels.placeholder;\n\n const instanceId = React.useId();\n const rootId = id ?? instanceId;\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n // ⚠ Khác thượng nguồn: ghi nhớ danh sách (thượng nguồn dựng lại mỗi lượt render — xem `getCountries`).\n const countries = React.useMemo(() => countriesProp ?? getCountries(locale), [countriesProp, locale]);\n\n const [formTrigger, setFormTrigger] = React.useState<RootElement | null>(null);\n const composedRef = useComposedRefs(ref, (node) => setFormTrigger(node));\n const isFormControl = formTrigger ? !!formTrigger.closest(\"form\") : true;\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<StoreState>(() => {\n const initialValue = valueProp ?? defaultValue ?? \"\";\n const initialCountry = countryProp ?? defaultCountry ?? \"\";\n\n return {\n value: initialValue,\n country: initialCountry,\n open: false,\n startsWithPlus: initialValue.startsWith(\"+\"),\n nationalInput: null\n };\n });\n\n const propsRef = useAsRef({\n onValueChange,\n onCountryChange,\n countries\n });\n\n const store = React.useMemo<Store>(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n if (key === \"value\" && typeof value === \"string\") {\n stateRef.current.value = value;\n propsRef.current.onValueChange?.(value);\n } else if (key === \"country\" && typeof value === \"string\") {\n // Đọc TRƯỚC khi đổi nước: chuỗi nội địa chỉ còn hiệu lực nếu khớp giá trị theo nước CŨ.\n const nationalInput = getNationalInput(stateRef.current, propsRef.current.countries);\n stateRef.current.country = value;\n propsRef.current.onCountryChange?.(value);\n\n /*\n * ⚠ Khác thượng nguồn: đang gõ số nội địa mà đổi quốc gia → chữ trên ô giờ là số nội địa\n * của nước MỚI, giá trị ghép lại mã quay số mới (ô giữ nguyên chữ). Nước mới không có\n * trong danh sách (bỏ chọn) → thôi chế độ nội địa, giữ nguyên giá trị E.164 đang có.\n * Từ `3.1.0` chữ ấy đọc lại qua đúng `parseTypedNumber` của ô, nên theo luật của nước mới:\n * tiền tố trung kế của nó, trần 15 chữ số (chữ số thừa rời khỏi ô), và tiền tố quốc tế của\n * nó (Việt Nam → Hoa Kỳ với `011 44…` trên ô: ô chuyển sang dạng quốc tế `+44…`).\n */\n if (nationalInput !== null) {\n const selected = propsRef.current.countries.find((c) => c.code === value);\n if (selected) {\n const next = parseTypedNumber(nationalInput, selected);\n stateRef.current.nationalInput = next.nationalInput;\n stateRef.current.startsWithPlus = next.startsWithPlus;\n if (next.value !== stateRef.current.value) {\n stateRef.current.value = next.value;\n propsRef.current.onValueChange?.(next.value);\n }\n } else {\n stateRef.current.nationalInput = null;\n }\n }\n } else {\n stateRef.current[key] = value;\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n }\n };\n }, [listenersRef, stateRef, propsRef]);\n\n const value = useStore((state) => state.value, store);\n const country = useStore((state) => state.country, store);\n\n useIsomorphicLayoutEffect(() => {\n if (valueProp !== undefined) {\n store.setState(\"value\", valueProp);\n }\n }, [valueProp]);\n\n useIsomorphicLayoutEffect(() => {\n if (countryProp !== undefined) {\n store.setState(\"country\", countryProp);\n }\n }, [countryProp]);\n\n const startsWithPlus = useStore((state) => state.startsWithPlus, store);\n const nationalInput = useStore((state) => getNationalInput(state, countries), store);\n\n React.useEffect(() => {\n /*\n * ⚠ Khác thượng nguồn: đang gõ số nội địa thì quốc gia ĐANG CHỌN là nguồn sự thật — dò lại theo\n * mã quay số lúc này chỉ có thể sai: Hoa Kỳ + `340 555 1234` → `+13405551234` → dò ra Quần đảo\n * Virgin (+1340), rồi giá trị bị ghép lại theo mã mới thành số rác.\n */\n if (!value || nationalInput !== null) return;\n\n const digits = value.slice(1).replace(/\\D/g, \"\");\n const shouldDetect = startsWithPlus || digits.length >= 10;\n\n if (!shouldDetect) return;\n\n const detected = detectCountryFromNumber(value, countries, country);\n if (detected && detected.code !== country) {\n store.setState(\"country\", detected.code);\n }\n }, [value, countries, country, store, startsWithPlus, nationalInput]);\n\n const contextValue = React.useMemo<PhoneInputContextValue>(\n () => ({\n rootId,\n countries,\n placeholder,\n labels,\n disabled,\n readOnly,\n required,\n invalid,\n showFlag,\n inputRef\n }),\n [rootId, countries, placeholder, labels, disabled, required, readOnly, invalid, showFlag]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <PhoneInputContext.Provider value={contextValue}>\n <RootPrimitive\n role=\"group\"\n data-slot=\"phone-input\"\n data-disabled={disabled ? \"\" : undefined}\n data-invalid={invalid ? \"\" : undefined}\n data-readonly={readOnly ? \"\" : undefined}\n id={rootId}\n {...rootProps}\n ref={composedRef}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: khung mượn đúng vai trò màu của `Input` Comitor để đứng cạnh ô\n * nhập thường trong một form không lệch (cao `h-9` thay vì `h-10`, nền `bg-background`\n * thay vì `dark:bg-input/30` — viết thẳng thang màu thì bảng tương phản cao không đổi\n * được). Số đo từng vai trò: chú thích đầu `input.tsx`.\n *\n * Focus: thượng nguồn soi `[data-slot=input-group-control]` — slot KHÔNG tồn tại trong\n * component này, nên khung không bao giờ sáng. Ở đây soi đúng slot của ô số.\n *\n * Lỗi: HAI đường như `InputGroup` — `aria-invalid` trên ô số (prop `invalid`), hoặc\n * trên CHÍNH gốc khi `<FormControl>` của `@comitor/ui/form` dán nó vào con trực tiếp.\n * Viền lỗi là `--destructive-ink` (không phải `--destructive` — token TÔ NỀN).\n *\n * Vô hiệu: thượng nguồn làm mờ CẢ gốc (`data-disabled:opacity-50`) trong khi nút và ô\n * số bên trong cũng tự mờ theo `:disabled` → nội dung còn 25%. Ở đây gốc KHÔNG mờ (như\n * `InputGroup`); hai con tự mờ bằng `:disabled` gốc của HTML, gốc chỉ đổi nền theo ô số.\n * `data-disabled` còn không được cổng tương phản coi là trạng thái vô hiệu — nó không\n * chứng minh phần tử đã inert — còn `:disabled` thì có.\n */\n \"relative flex h-9 w-full items-center rounded-md border border-input bg-background transition-colors duration-150 ease-out hover:border-control-edge-strong\",\n \"has-[[data-slot=phone-input-field]:focus-visible]:border-primary-ink has-[[data-slot=phone-input-field]:focus-visible]:ring-2 has-[[data-slot=phone-input-field]:focus-visible]:ring-ring/50\",\n \"has-[[data-slot][aria-invalid=true]]:border-destructive-ink has-[[data-slot][aria-invalid=true]]:ring-destructive/30\",\n \"aria-invalid:border-destructive-ink aria-invalid:hover:border-destructive-ink aria-invalid:ring-destructive/30\",\n \"data-disabled:cursor-not-allowed has-[[data-slot=phone-input-field]:disabled]:bg-muted\",\n className\n )}\n />\n {isFormControl && (\n <VisuallyHiddenInput\n type=\"hidden\"\n control={formTrigger}\n name={name}\n value={value}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n />\n )}\n </PhoneInputContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface PhoneInputCountrySelectProps\n extends React.ComponentProps<typeof Popover>,\n Pick<React.ComponentProps<typeof PopoverTrigger>, \"disabled\" | \"className\"> {}\n\nfunction PhoneInputCountrySelect(props: PhoneInputCountrySelectProps) {\n const { disabled: disabledProp, className, children, onOpenChange: onOpenChangeProp, ...popoverProps } = props;\n\n const { countries, inputRef, disabled, readOnly, showFlag, labels } = usePhoneInputContext(COUNTRY_SELECT_NAME);\n const store = useStoreContext(COUNTRY_SELECT_NAME);\n const country = useStore((state) => state.country);\n const open = useStore((state) => state.open);\n const onOpenChangeRef = useAsRef(onOpenChangeProp);\n\n const isDisabled = disabledProp || disabled;\n\n const countryContext = countries.find((c) => c.code === country);\n\n /*\n * ⚠ Khác thượng nguồn (3.0.1): `readOnly` khoá cả nút chọn nước. Trước đó chỉ ô số bị khoá, nút cờ\n * vẫn mở danh sách và đổi được nước — tức đổi được mã vùng, tức đổi được GIÁ TRỊ của một ô chỉ\n * đọc. Nút vẫn nhận focus (như ô `readOnly` bên cạnh) và vẫn đọc tên nước hiện tại, nhưng không\n * mở; `aria-disabled` nói với trình đọc màn hình rằng nó không thao tác được.\n */\n const onOpenChange = React.useCallback(\n (open: boolean) => {\n if (open && readOnly) return;\n store.setState(\"open\", open);\n onOpenChangeRef.current?.(open);\n },\n [store, onOpenChangeRef, readOnly]\n );\n\n return (\n <Popover open={open} onOpenChange={onOpenChange} {...popoverProps}>\n <PopoverTrigger\n data-slot=\"phone-input-country-select\"\n // ⚠ Khác thượng nguồn: bản gốc là một nút KHÔNG TÊN (chỉ có lá cờ emoji + mũi tên, hoặc\n // ô xám trống khi chưa chọn). Tên nói luôn giá trị hiện tại — xem `PhoneInputLabels`.\n aria-label={labels.countrySelect(countryContext)}\n aria-disabled={readOnly && !isDisabled ? true : undefined}\n data-readonly={readOnly ? \"\" : undefined}\n disabled={isDisabled}\n className={cn(\n /*\n * Hover `bg-muted` như nút `ghost` của gói. Viền focus cùng khuôn `Button`\n * (`outline-ring`), nhưng THỤT VÀO trong (`-outline-offset-2`) vì nút nằm lọt trong khung\n * của ô — viền đẩy ra ngoài sẽ đè lên khung và lên ô số bên cạnh.\n */\n \"flex h-full shrink-0 items-center gap-2 rounded-l-md border-r border-input bg-transparent px-3 text-sm transition-colors duration-150 ease-out hover:bg-muted focus-visible:outline-2 focus-visible:outline-ring focus-visible:-outline-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n className\n )}\n >\n {/* `span` thay cho `div` của thượng nguồn: `<button>` chỉ nhận nội dung phrasing. */}\n {!countryContext ? (\n /*\n * ⚠ Khác thượng nguồn: bản gốc vẽ một ô `bg-muted/50` trống — 1,00:1 trên nền hover\n * `--muted`, tức biến mất đúng lúc người dùng rê chuột vào (cổng tương phản chặn). Quả\n * địa cầu nói được \"chưa chọn quốc gia\"; giữ bề rộng `w-6` của lá cờ để chọn xong không\n * xô lệch.\n */\n <span aria-hidden=\"true\" className=\"flex w-6 justify-center\">\n <Globe className=\"size-4 text-muted-foreground\" />\n </span>\n ) : (\n showFlag &&\n countryContext.flag && (\n <span aria-hidden=\"true\" className=\"w-6 text-lg leading-none\">\n {countryContext.flag}\n </span>\n )\n )}\n {/* Mũi tên chỉ trạng thái → ngưỡng 3:1; `text-muted-foreground` như chevron của `SelectTrigger`. */}\n <ChevronDown aria-hidden=\"true\" className=\"size-4 text-muted-foreground\" />\n </PopoverTrigger>\n <PopoverContent className=\"w-[300px] p-0\" align=\"start\">\n <Command filter={filterCountries}>\n <CommandInput placeholder={labels.searchPlaceholder} />\n <CommandList>\n <CommandEmpty>{labels.empty}</CommandEmpty>\n <CommandGroup>\n {countries.map((c) => (\n <CommandItem\n key={c.code}\n value={`${c.name} ${c.dialCode} ${c.code}`}\n onSelect={() => {\n store.setState(\"country\", c.code);\n store.setState(\"open\", false);\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n }}\n >\n {/* Cờ là trang trí — tên nước ngay bên cạnh đã nói đủ; không ẩn thì bị đọc hai lần. */}\n {showFlag && c.flag && (\n <span aria-hidden=\"true\" className=\"text-lg\">\n {c.flag}\n </span>\n )}\n <span className=\"flex-1\">{c.name}</span>\n <span className=\"text-muted-foreground\">{c.dialCode}</span>\n <Check\n aria-hidden=\"true\"\n className={cn(\"size-4\", country === c.code ? \"opacity-100\" : \"opacity-0\")}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n}\n\ntype PhoneInputFieldProps = React.ComponentProps<\"input\">;\n\nfunction PhoneInputField(props: PhoneInputFieldProps) {\n const {\n onChange: onChangeProp,\n className,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n required: requiredProp,\n placeholder: placeholderProp,\n ref,\n ...inputProps\n } = props;\n\n const { inputRef, disabled, invalid, readOnly, required, placeholder, countries } = usePhoneInputContext(FIELD_NAME);\n const store = useStoreContext(FIELD_NAME);\n const value = useStore((state) => state.value);\n const nationalInput = useStore((state) => getNationalInput(state, countries));\n\n const composedRef = useComposedRefs(ref, inputRef);\n\n const onChangeRef = useAsRef(onChangeProp);\n\n const isDisabled = disabledProp || disabled;\n const isReadOnly = readOnlyProp || readOnly;\n const isRequired = requiredProp || required;\n\n const onChange = React.useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n if (isDisabled || isReadOnly) return;\n\n onChangeRef.current?.(event);\n if (event.defaultPrevented) return;\n\n const inputValue = event.target.value;\n\n // ⚠ Khác thượng nguồn — số NỘI ĐỊA, tiền tố trung kế/quốc tế, trần 15 chữ số (luật và lý do:\n // chú thích trên `E164_MAX_DIGITS`). Quốc gia đang chọn đi vào cả khi chuỗi bắt đầu bằng `+`:\n // tiền tố quốc tế gõ thừa sau `+` là tiền tố của nước ấy.\n const next = parseTypedNumber(\n inputValue,\n countries.find((c) => c.code === store.getState().country)\n );\n\n if (next.nationalInput !== null && next.nationalInput !== inputValue) {\n // Gạt ký tự lạ (và chữ số quá trần) NGAY trên DOM rồi đặt lại con trỏ tại chỗ: nhờ vậy lúc\n // render React thấy DOM đã đúng giá trị, không ghi đè — ghi đè là con trỏ nhảy về cuối ô.\n const target = event.target;\n const caret = target.selectionStart ?? inputValue.length;\n const nextCaret = Math.min(\n inputValue.slice(0, caret).replace(NATIONAL_INPUT_DISALLOWED, \"\").length,\n next.nationalInput.length\n );\n target.value = next.nationalInput;\n target.setSelectionRange(nextCaret, nextCaret);\n }\n\n store.setState(\"startsWithPlus\", next.startsWithPlus);\n store.setState(\"nationalInput\", next.nationalInput);\n store.setState(\"value\", next.value);\n },\n [store, countries, onChangeRef, isDisabled, isReadOnly]\n );\n\n // Số nội địa hiện NGUYÊN VĂN chữ đã gõ (con trỏ không nhảy); số quốc tế tách nhóm như thượng nguồn.\n const displayValue = React.useMemo(() => {\n return nationalInput ?? formatPhoneNumber(value, countries);\n }, [nationalInput, value, countries]);\n\n return (\n <Input\n type=\"tel\"\n inputMode=\"tel\"\n aria-required={isRequired}\n aria-invalid={invalid}\n data-slot=\"phone-input-field\"\n disabled={isDisabled}\n readOnly={isReadOnly}\n required={isRequired}\n {...inputProps}\n ref={composedRef}\n className={cn(\n // Viền, quầng focus và nền (kể cả nền `--muted` lúc vô hiệu) đều do khung gốc vẽ; ô số\n // trong suốt và phẳng. `focus:ring-0` chứ không `focus-visible:` — `Input` vẽ quầng bằng `focus:`.\n \"h-full flex-1 rounded-l-none rounded-r-md border-0 bg-transparent focus:ring-0 disabled:bg-transparent\",\n className\n )}\n // ⚠ Khác thượng nguồn: bản gốc đặt placeholder của gốc SAU `{...inputProps}`, nên\n // `<PhoneInputField placeholder=\"…\" />` (chính demo của thượng nguồn) bị lờ đi.\n placeholder={placeholderProp ?? placeholder}\n value={displayValue}\n onChange={onChange}\n />\n );\n}\n\nexport {\n PhoneInput,\n PhoneInputCountrySelect,\n type PhoneInputCountrySelectProps,\n PhoneInputField,\n type PhoneInputFieldProps,\n type PhoneInputProps,\n useStore as usePhoneInput\n};\n"],"mappings":";AAw9BM,SACE,KADF;AAj9BN,SAAS,YAAY;AACrB,SAAS,qBAAqB;AAC9B,SAAS,OAAO,aAAa,aAAa;AAC1C,YAAY,WAAW;AACvB,SAAS,kBAAkB,wBAAwB;AACnD,SAAS,UAAU;AACnB,SAAS,uBAAuB;AAChC,SAAS,6BAA6B;AACtC,SAAS,gBAAgB;AACzB,SAAS,iCAAiC;AAC1C,SAAS,kBAAkB;AAC3B,SAAS,2BAA2B;AACpC,SAAS,SAAS,cAAc,cAAc,cAAc,aAAa,mBAAmB;AAC5F,SAAS,aAAa;AAEtB,SAAS,SAAS,gBAAgB,sBAAsB;AAExD,MAAM,YAAY;AAClB,MAAM,sBAAsB;AAC5B,MAAM,aAAa;AAgBnB,MAAM,eAAmC;AAAA,EACvC,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,GAAG;AAAA,EACV,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,GAAG;AAAA,EACV,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,GAAG;AAAA,EACV,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,GAAG;AAAA,EACV,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,GAAG;AAAA,EACV,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,IAAI;AAAA,EACX,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAAK;AAAA,EACZ,CAAC,MAAM,MAAM;AAAA,EACb,CAAC,MAAM,KAA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","names":["value","nationalInput","open"]}
|
|
@@ -454,7 +454,9 @@ function RatingItem(props) {
|
|
|
454
454
|
if (event.defaultPrevented) return;
|
|
455
455
|
focusContext.onItemFocus(itemId);
|
|
456
456
|
const isKeyboardFocus = !isMouseClickRef.current;
|
|
457
|
-
|
|
457
|
+
const previous = event.relatedTarget;
|
|
458
|
+
const cameFromSibling = previous instanceof HTMLElement && previous !== event.currentTarget && previous.getAttribute("data-slot") === "rating-item" && previous.closest('[data-slot="rating"]') === event.currentTarget.closest('[data-slot="rating"]');
|
|
459
|
+
if (!isDisabled && !isReadOnly && activationMode !== "manual" && isKeyboardFocus && cameFromSibling) {
|
|
458
460
|
const isHalfStepValue = step < 1 && value === itemValue - step;
|
|
459
461
|
if (!isHalfStepValue) {
|
|
460
462
|
const newValue = clearable && value === itemValue ? 0 : itemValue;
|
|
@@ -603,7 +605,7 @@ function RatingItem(props) {
|
|
|
603
605
|
role: "radio",
|
|
604
606
|
type: "button",
|
|
605
607
|
id: itemId,
|
|
606
|
-
"aria-label": context.itemLabel(itemValue, context.max),
|
|
608
|
+
"aria-label": context.itemLabel(isChecked && value !== itemValue ? value : itemValue, context.max),
|
|
607
609
|
"aria-checked": isChecked,
|
|
608
610
|
"aria-posinset": itemValue,
|
|
609
611
|
"aria-setsize": context.max,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/rating.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/rating) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { Star } from \"lucide-react\";\nimport * as React from \"react\";\nimport { useComitorMessages } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { VisuallyHiddenInput } from \"../../lib/visually-hidden-input.js\";\n\ntype Direction = \"ltr\" | \"rtl\";\ntype Orientation = \"horizontal\" | \"vertical\";\ntype ActivationMode = \"automatic\" | \"manual\";\ntype Size = \"default\" | \"sm\" | \"lg\";\ntype Step = 0.5 | 1;\ntype DataState = \"full\" | \"partial\" | \"empty\";\ntype FocusIntent = \"first\" | \"last\" | \"prev\" | \"next\";\n\ntype RootElement = React.ComponentRef<typeof Rating>;\ntype ItemElement = React.ComponentRef<typeof RatingItem>;\n\nconst ROOT_NAME = \"Rating\";\nconst ITEM_NAME = \"RatingItem\";\n\nconst ENTRY_FOCUS = \"ratingFocusGroup.onEntryFocus\";\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\nfunction getItemId(id: string, value: number) {\n return `${id}-item-${value}`;\n}\n\nfunction getPartialFillGradientId(id: string, step: Step) {\n return `partial-fill-gradient-${id}-${step}`;\n}\n\nconst MAP_KEY_TO_FOCUS_INTENT: Record<string, FocusIntent> = {\n ArrowLeft: \"prev\",\n ArrowUp: \"prev\",\n ArrowRight: \"next\",\n ArrowDown: \"next\",\n Home: \"first\",\n End: \"last\"\n};\n\nfunction getDirectionAwareKey(key: string, dir?: Direction) {\n if (dir !== \"rtl\") return key;\n return key === \"ArrowLeft\" ? \"ArrowRight\" : key === \"ArrowRight\" ? \"ArrowLeft\" : key;\n}\n\nfunction getFocusIntent(event: React.KeyboardEvent<ItemElement>, dir?: Direction, orientation?: Orientation) {\n const key = getDirectionAwareKey(event.key, dir);\n if (orientation === \"horizontal\" && [\"ArrowUp\", \"ArrowDown\"].includes(key)) return undefined;\n if (orientation === \"vertical\" && [\"ArrowLeft\", \"ArrowRight\"].includes(key)) return undefined;\n return MAP_KEY_TO_FOCUS_INTENT[key];\n}\n\nfunction focusFirst(candidates: React.RefObject<ItemElement | null>[], preventScroll = false) {\n const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;\n for (const candidateRef of candidates) {\n const candidate = candidateRef.current;\n if (!candidate) continue;\n if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;\n candidate.focus({ preventScroll });\n if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;\n }\n}\n\ninterface StoreState {\n value: number;\n hoveredValue: number | null;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: <K extends keyof StoreState>(key: K, value: StoreState[K]) => void;\n notify: () => void;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nfunction useStore<T>(selector: (state: StoreState) => T, ogStore?: Store | null): T {\n const contextStore = React.useContext(StoreContext);\n\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`useRating\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ninterface ItemData {\n id: string;\n ref: React.RefObject<ItemElement | null>;\n value: number;\n disabled: boolean;\n}\n\ninterface RatingContextValue {\n rootId: string;\n dir: Direction;\n orientation: Orientation;\n activationMode: ActivationMode;\n size: Size;\n max: number;\n step: Step;\n clearable: boolean;\n disabled: boolean;\n readOnly: boolean;\n itemLabel: (value: number, max: number) => string;\n getAutoIndex: (instanceId: string) => number;\n}\n\nconst RatingContext = React.createContext<RatingContextValue | null>(null);\n\nfunction useRatingContext(consumerName: string) {\n const context = React.useContext(RatingContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface FocusContextValue {\n tabStopId: string | null;\n onItemFocus: (tabStopId: string) => void;\n onItemShiftTab: () => void;\n onFocusableItemAdd: () => void;\n onFocusableItemRemove: () => void;\n onItemRegister: (item: ItemData) => void;\n onItemUnregister: (id: string) => void;\n getItems: () => ItemData[];\n}\n\nconst FocusContext = React.createContext<FocusContextValue | null>(null);\n\nfunction useFocusContext(consumerName: string) {\n const context = React.useContext(FocusContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`FocusProvider\\``);\n }\n return context;\n}\n\ninterface RatingProps extends React.ComponentProps<\"div\"> {\n value?: number;\n defaultValue?: number;\n onValueChange?: (value: number) => void;\n onHover?: (value: number | null) => void;\n max?: number;\n activationMode?: ActivationMode;\n dir?: Direction;\n orientation?: Orientation;\n size?: Size;\n asChild?: boolean;\n step?: Step;\n clearable?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n name?: string;\n /**\n * Tên của TỪNG ngôi sao cho trình đọc màn hình — mặc định khoá `itemLabel` của namespace\n * `rating` (`ComitorLocaleProvider`).\n *\n * ⚠ Thêm so với thượng nguồn. Ở bản gốc mỗi `RatingItem` là một `role=\"radio\"` chỉ chứa một\n * `<svg>`, tức một nút KHÔNG TÊN: trình đọc màn hình đọc \"nút radio, 3 trên 5\" mà không nói 3\n * CÁI GÌ. Là HÀM chứ không phải chuỗi mẫu vì có số chèn vào giữa câu (README §5).\n *\n * Nhóm vẫn cần tên riêng: truyền `aria-label` (vd \"Mức hài lòng\") cho chính `Rating`.\n */\n itemLabel?: (value: number, max: number) => string;\n}\n\nfunction Rating(props: RatingProps) {\n const {\n value: valueProp,\n defaultValue = 0,\n onValueChange,\n onHover,\n onFocus: onFocusProp,\n onMouseDown: onMouseDownProp,\n dir: dirProp,\n orientation = \"horizontal\",\n activationMode = \"automatic\",\n size = \"default\",\n max = 5,\n step = 1,\n clearable = false,\n asChild,\n disabled = false,\n readOnly = false,\n required = false,\n itemLabel: itemLabelProp,\n className,\n children,\n id,\n name,\n ref,\n ...rootProps\n } = props;\n\n const t = useComitorMessages(\"rating\");\n const itemLabel = itemLabelProp ?? t.itemLabel;\n const dir = useDirection(dirProp);\n const instanceId = React.useId();\n const rootId = id ?? instanceId;\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<StoreState>(() => ({\n value: valueProp ?? defaultValue,\n hoveredValue: null\n }));\n\n const propsRef = useAsRef({\n onValueChange,\n onHover,\n onFocus: onFocusProp,\n onMouseDown: onMouseDownProp,\n step\n });\n\n const store = React.useMemo<Store>(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n if (key === \"value\" && typeof value === \"number\") {\n stateRef.current.value = value;\n propsRef.current.onValueChange?.(value);\n } else if (key === \"hoveredValue\") {\n stateRef.current.hoveredValue = value as number | null;\n propsRef.current.onHover?.(value as number | null);\n } else {\n stateRef.current[key] = value;\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n }\n };\n }, [listenersRef, stateRef, propsRef]);\n\n useIsomorphicLayoutEffect(() => {\n if (valueProp !== undefined) {\n store.setState(\"value\", valueProp);\n }\n }, [valueProp]);\n\n const value = useStore((state) => state.value, store);\n\n const [formTrigger, setFormTrigger] = React.useState<RootElement | null>(null);\n const composedRef = useComposedRefs(ref, (node) => setFormTrigger(node));\n const isFormControl = formTrigger ? !!formTrigger.closest(\"form\") : true;\n\n const [tabStopId, setTabStopId] = React.useState<string | null>(null);\n const [isTabbingBackOut, setIsTabbingBackOut] = React.useState(false);\n const [focusableItemCount, setFocusableItemCount] = React.useState(0);\n const isClickFocusRef = React.useRef(false);\n const itemsRef = React.useRef<Map<string, ItemData>>(new Map());\n\n const autoIndexMapRef = React.useRef(new Map<string, number>());\n const nextAutoIndexRef = React.useRef(0);\n\n const getAutoIndex = React.useCallback((instanceId: string) => {\n const existingIndex = autoIndexMapRef.current.get(instanceId);\n if (existingIndex !== undefined) {\n return existingIndex;\n }\n\n const newIndex = nextAutoIndexRef.current++;\n autoIndexMapRef.current.set(instanceId, newIndex);\n return newIndex;\n }, []);\n\n const onItemFocus = React.useCallback((tabStopId: string) => {\n setTabStopId(tabStopId);\n }, []);\n\n const onItemShiftTab = React.useCallback(() => {\n setIsTabbingBackOut(true);\n }, []);\n\n const onFocusableItemAdd = React.useCallback(() => {\n setFocusableItemCount((prevCount) => prevCount + 1);\n }, []);\n\n const onFocusableItemRemove = React.useCallback(() => {\n setFocusableItemCount((prevCount) => prevCount - 1);\n }, []);\n\n const onItemRegister = React.useCallback((item: ItemData) => {\n itemsRef.current.set(item.id, item);\n }, []);\n\n const onItemUnregister = React.useCallback((id: string) => {\n itemsRef.current.delete(id);\n }, []);\n\n const getItems = React.useCallback(() => {\n return Array.from(itemsRef.current.values())\n .filter((item) => item.ref.current)\n .sort((a, b) => {\n const elementA = a.ref.current;\n const elementB = b.ref.current;\n if (!elementA || !elementB) return 0;\n const position = elementA.compareDocumentPosition(elementB);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) {\n return -1;\n }\n if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n return 1;\n }\n return 0;\n });\n }, []);\n\n const onBlur = React.useCallback(\n (event: React.FocusEvent<HTMLDivElement>) => {\n rootProps.onBlur?.(event);\n if (event.defaultPrevented) return;\n\n setIsTabbingBackOut(false);\n },\n [rootProps.onBlur]\n );\n\n const onFocus = React.useCallback(\n (event: React.FocusEvent<HTMLDivElement>) => {\n propsRef.current.onFocus?.(event);\n if (event.defaultPrevented) return;\n\n const isKeyboardFocus = !isClickFocusRef.current;\n if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {\n const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);\n event.currentTarget.dispatchEvent(entryFocusEvent);\n\n if (!entryFocusEvent.defaultPrevented) {\n const items = Array.from(itemsRef.current.values()).filter((item) => !item.disabled);\n // Nửa sao: tìm mục đại diện cho giá trị đang chọn bằng giá trị TRẦN (3,5 → mục 4).\n const selectedItem =\n propsRef.current.step < 1\n ? items.find((item) => item.value === Math.ceil(value))\n : items.find((item) => item.value === value);\n const currentItem = items.find((item) => item.id === tabStopId);\n\n const candidateItems = [selectedItem, currentItem, ...items].filter(Boolean) as ItemData[];\n const candidateRefs = candidateItems.map((item) => item.ref);\n focusFirst(candidateRefs, false);\n }\n }\n isClickFocusRef.current = false;\n },\n [propsRef, isTabbingBackOut, value, tabStopId]\n );\n\n const onMouseDown = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n propsRef.current.onMouseDown?.(event);\n\n if (event.defaultPrevented) return;\n\n isClickFocusRef.current = true;\n },\n [propsRef]\n );\n\n const contextValue = React.useMemo<RatingContextValue>(\n () => ({\n rootId,\n dir,\n orientation,\n activationMode,\n disabled,\n readOnly,\n size,\n max,\n step,\n clearable,\n itemLabel,\n getAutoIndex\n }),\n [rootId, dir, orientation, activationMode, disabled, readOnly, size, max, step, clearable, itemLabel, getAutoIndex]\n );\n\n const focusContextValue = React.useMemo<FocusContextValue>(\n () => ({\n tabStopId,\n onItemFocus,\n onItemShiftTab,\n onFocusableItemAdd,\n onFocusableItemRemove,\n onItemRegister,\n onItemUnregister,\n getItems\n }),\n [\n tabStopId,\n onItemFocus,\n onItemShiftTab,\n onFocusableItemAdd,\n onFocusableItemRemove,\n onItemRegister,\n onItemUnregister,\n getItems\n ]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n /*\n * ⚠ Khác thượng nguồn: gradient của NỬA SAO phải nằm BÊN TRONG phần tử gốc. Trong SVG,\n * `stopColor=\"currentColor\"` lấy `color` tính ở chỗ gradient được KHAI, không phải ở chỗ nó được\n * dùng — bản gốc đặt `<svg>` này làm anh em của phần tử gốc, nên nửa sao ăn màu chữ của trang\n * (đo trên trình duyệt: #0E1116 ở light, #F7F7F8 ở dark) thay vì màu sao `text-primary-ink`.\n * Với `asChild` thì Slot không nhận thêm con được, nên gradient đành đứng ngoài như bản gốc —\n * khi đó app phải tự đặt màu chữ cho phần tử BAO NGOÀI.\n */\n const partialFillGradient = (\n <svg width=\"0\" height=\"0\" aria-hidden=\"true\" focusable=\"false\" style={{ position: \"absolute\" }}>\n <defs>\n <linearGradient id={getPartialFillGradientId(rootId, step)}>\n {dir === \"rtl\" ? (\n <>\n <stop offset=\"50%\" stopColor=\"transparent\" />\n <stop offset=\"50%\" stopColor=\"currentColor\" />\n </>\n ) : (\n <>\n <stop offset=\"50%\" stopColor=\"currentColor\" />\n <stop offset=\"50%\" stopColor=\"transparent\" />\n </>\n )}\n </linearGradient>\n </defs>\n </svg>\n );\n\n return (\n <StoreContext.Provider value={store}>\n <RatingContext.Provider value={contextValue}>\n <FocusContext.Provider value={focusContextValue}>\n <RootPrimitive\n id={rootId}\n role=\"radiogroup\"\n aria-orientation={orientation}\n aria-disabled={disabled || undefined}\n aria-readonly={readOnly || undefined}\n aria-required={required || undefined}\n data-disabled={disabled ? \"\" : undefined}\n data-readonly={readOnly ? \"\" : undefined}\n data-orientation={orientation}\n data-slot=\"rating\"\n dir={dir}\n tabIndex={isTabbingBackOut || focusableItemCount === 0 ? -1 : 0}\n {...rootProps}\n ref={composedRef}\n className={cn(\n /*\n * Ngôi sao là thành phần PHI VĂN BẢN mang nghĩa (nó LÀ giá trị) → màu đi qua bậc\n * `-ink` của tone, không phải token tô nền. Bản gốc `text-primary` đọc thẳng màu\n * TÔ NỀN; ở bảng mặc định hai token trùng nhau (`--primary-ink: var(--primary)`),\n * nhưng bảng tương phản cao kéo `--primary-ink` xuống bậc tối — và chỉ `-ink` mới\n * được đổi theo. Hợp đồng §1 của docs/hop-dong-mau.md.\n */\n \"flex gap-1 text-primary-ink outline-none\",\n orientation === \"horizontal\" ? \"flex-row items-center\" : \"flex-col items-start\",\n className\n )}\n onBlur={onBlur}\n onFocus={onFocus}\n onMouseDown={onMouseDown}\n >\n {asChild ? (\n children\n ) : (\n <>\n {children}\n {partialFillGradient}\n </>\n )}\n </RootPrimitive>\n {asChild ? partialFillGradient : null}\n {isFormControl && (\n <VisuallyHiddenInput\n type=\"hidden\"\n control={formTrigger}\n name={name}\n value={value}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n />\n )}\n </FocusContext.Provider>\n </RatingContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface RatingItemProps extends Omit<React.ComponentProps<\"button\">, \"children\"> {\n index?: number;\n asChild?: boolean;\n children?: React.ReactNode | ((dataState: DataState) => React.ReactNode);\n}\n\nfunction RatingItem(props: RatingItemProps) {\n const {\n index,\n asChild,\n onClick: onClickProp,\n onFocus: onFocusProp,\n onKeyDown: onKeyDownProp,\n onMouseDown: onMouseDownProp,\n onMouseEnter: onMouseEnterProp,\n onMouseMove: onMouseMoveProp,\n onMouseLeave: onMouseLeaveProp,\n disabled,\n className,\n children,\n ref,\n ...itemProps\n } = props;\n\n const itemRef = React.useRef<ItemElement>(null);\n const composedRef = useComposedRefs(ref, itemRef);\n\n const context = useRatingContext(ITEM_NAME);\n\n const instanceId = React.useId();\n\n const actualIndex = React.useMemo(() => {\n if (index !== undefined) {\n return index;\n }\n\n return context.getAutoIndex(instanceId);\n }, [index, context, instanceId]);\n\n const itemValue = actualIndex + 1;\n const store = useStoreContext(ITEM_NAME);\n const focusContext = useFocusContext(ITEM_NAME);\n const value = useStore((state) => state.value);\n const hoveredValue = useStore((state) => state.hoveredValue);\n const clearable = context.clearable;\n const step = context.step;\n const activationMode = context.activationMode;\n\n const itemId = getItemId(context.rootId, itemValue);\n const isDisabled = context.disabled || disabled;\n const isReadOnly = context.readOnly;\n const isTabStop = focusContext.tabStopId === itemId;\n\n const displayValue = hoveredValue ?? value;\n const isFilled = displayValue >= itemValue;\n const isPartiallyFilled = step < 1 && displayValue >= itemValue - step && displayValue < itemValue;\n const isHovered = hoveredValue !== null && hoveredValue < itemValue;\n /*\n * ⚠ Khác thượng nguồn: bản gốc đặt `aria-checked={isFilled}`, tức chọn 4 sao thì BỐN nút radio\n * cùng báo \"đã chọn\" — một radiogroup có nhiều radio được chọn là trạng thái không tồn tại với\n * trình đọc màn hình. Ở đây chỉ đúng MỘT mục được chọn: mục chứa giá trị (3,5 → mục 4), và đọc\n * theo `value` thật chứ không theo sao đang được rê chuột (`displayValue`).\n */\n const isChecked = value > 0 && Math.ceil(value) === itemValue;\n\n const isMouseClickRef = React.useRef(false);\n\n const propsRef = useAsRef({\n onClick: onClickProp,\n onFocus: onFocusProp,\n onKeyDown: onKeyDownProp,\n onMouseDown: onMouseDownProp,\n onMouseEnter: onMouseEnterProp,\n onMouseMove: onMouseMoveProp,\n onMouseLeave: onMouseLeaveProp\n });\n\n useIsomorphicLayoutEffect(() => {\n focusContext.onItemRegister({\n id: itemId,\n ref: itemRef,\n value: itemValue,\n disabled: !!isDisabled\n });\n\n if (!isDisabled) {\n focusContext.onFocusableItemAdd();\n }\n\n return () => {\n focusContext.onItemUnregister(itemId);\n if (!isDisabled) {\n focusContext.onFocusableItemRemove();\n }\n };\n }, [focusContext, itemId, itemValue, isDisabled]);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onClick?.(event);\n if (event.defaultPrevented) return;\n\n if (!isDisabled && !isReadOnly) {\n let newValue = itemValue;\n\n if (step < 1) {\n const rect = event.currentTarget.getBoundingClientRect();\n const clickX = event.clientX - rect.left;\n const isLeftHalf = clickX < rect.width / 2;\n\n if (context.dir === \"rtl\") {\n if (!isLeftHalf) {\n newValue = itemValue - step;\n }\n } else {\n if (isLeftHalf) {\n newValue = itemValue - step;\n }\n }\n }\n\n if (clearable && value === newValue) {\n newValue = 0;\n }\n\n store.setState(\"value\", newValue);\n }\n },\n [isDisabled, isReadOnly, clearable, step, value, itemValue, store, context.dir, propsRef]\n );\n\n const onFocus = React.useCallback(\n (event: React.FocusEvent<ItemElement>) => {\n propsRef.current.onFocus?.(event);\n if (event.defaultPrevented) return;\n\n focusContext.onItemFocus(itemId);\n\n const isKeyboardFocus = !isMouseClickRef.current;\n\n if (!isDisabled && !isReadOnly && activationMode !== \"manual\" && isKeyboardFocus) {\n // Nửa sao: nếu giá trị đang là nửa-bậc THUỘC mục này (3,5 khi mục là 4) thì đừng đổi nó.\n const isHalfStepValue = step < 1 && value === itemValue - step;\n\n if (!isHalfStepValue) {\n const newValue = clearable && value === itemValue ? 0 : itemValue;\n store.setState(\"value\", newValue);\n }\n }\n\n isMouseClickRef.current = false;\n },\n [focusContext, itemId, activationMode, isDisabled, isReadOnly, clearable, value, itemValue, step, store, propsRef]\n );\n\n const onKeyDown = React.useCallback(\n (event: React.KeyboardEvent<ItemElement>) => {\n propsRef.current.onKeyDown?.(event);\n if (event.defaultPrevented) return;\n\n if ((event.key === \"Enter\" || event.key === \" \") && activationMode === \"manual\") {\n event.preventDefault();\n if (!isDisabled && !isReadOnly && itemRef.current) {\n itemRef.current.click();\n }\n return;\n }\n\n if (event.key === \"Tab\" && event.shiftKey) {\n focusContext.onItemShiftTab();\n return;\n }\n\n if (event.target !== event.currentTarget) return;\n\n const focusIntent = getFocusIntent(event, context.dir, context.orientation);\n\n if (focusIntent !== undefined) {\n if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;\n event.preventDefault();\n\n // Nửa sao: mũi tên tăng/giảm đúng một `step` thay vì nhảy sang mục kế.\n if (step < 1 && (focusIntent === \"prev\" || focusIntent === \"next\")) {\n if (!isDisabled && !isReadOnly) {\n let newValue = value;\n\n if (focusIntent === \"next\") {\n newValue = Math.min(value + step, context.max);\n } else {\n newValue = Math.max(value - step, 0);\n }\n\n store.setState(\"value\", newValue);\n\n // Đưa focus tới mục đại diện cho giá trị mới.\n const items = focusContext.getItems().filter((item) => !item.disabled);\n const targetItem = items.find((item) => item.value === Math.ceil(newValue));\n if (targetItem?.ref.current) {\n queueMicrotask(() => targetItem.ref.current?.focus());\n }\n }\n return;\n }\n\n // Bậc nguyên, hoặc Home/End: điều hướng như thường.\n const items = focusContext.getItems().filter((item) => !item.disabled);\n let candidateRefs = items.map((item) => item.ref);\n\n if (focusIntent === \"last\") {\n candidateRefs.reverse();\n } else if (focusIntent === \"prev\" || focusIntent === \"next\") {\n if (focusIntent === \"prev\") candidateRefs.reverse();\n const currentIndex = candidateRefs.findIndex((ref) => ref.current === event.currentTarget);\n candidateRefs = candidateRefs.slice(currentIndex + 1);\n }\n\n queueMicrotask(() => focusFirst(candidateRefs));\n }\n },\n [\n focusContext,\n context.dir,\n context.orientation,\n activationMode,\n isDisabled,\n isReadOnly,\n step,\n value,\n context.max,\n store,\n propsRef\n ]\n );\n\n const onMouseDown = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onMouseDown?.(event);\n if (event.defaultPrevented) return;\n\n isMouseClickRef.current = true;\n\n if (isDisabled) {\n event.preventDefault();\n } else {\n focusContext.onItemFocus(itemId);\n }\n },\n [focusContext, itemId, isDisabled, propsRef]\n );\n\n const onMouseEnter = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onMouseEnter?.(event);\n if (event.defaultPrevented) return;\n\n if (!isDisabled && !isReadOnly) {\n let hoverValue = itemValue;\n\n if (step < 1) {\n const rect = event.currentTarget.getBoundingClientRect();\n const mouseX = event.clientX - rect.left;\n const isLeftHalf = mouseX < rect.width / 2;\n\n if (context.dir === \"rtl\") {\n if (!isLeftHalf) {\n hoverValue = itemValue - step;\n }\n } else {\n if (isLeftHalf) {\n hoverValue = itemValue - step;\n }\n }\n }\n\n store.setState(\"hoveredValue\", hoverValue);\n }\n },\n [isDisabled, isReadOnly, step, itemValue, store, context.dir, propsRef]\n );\n\n const onMouseLeave = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onMouseLeave?.(event);\n if (event.defaultPrevented) return;\n\n if (!isDisabled && !isReadOnly) {\n store.setState(\"hoveredValue\", null);\n }\n },\n [isDisabled, isReadOnly, store, propsRef]\n );\n\n const onMouseMove = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onMouseMove?.(event);\n if (event.defaultPrevented) return;\n\n if (!isDisabled && !isReadOnly && step < 1) {\n const rect = event.currentTarget.getBoundingClientRect();\n const mouseX = event.clientX - rect.left;\n const isLeftHalf = mouseX < rect.width / 2;\n\n let hoverValue = itemValue;\n if (context.dir === \"rtl\") {\n hoverValue = !isLeftHalf ? itemValue - step : itemValue;\n } else {\n hoverValue = isLeftHalf ? itemValue - step : itemValue;\n }\n\n store.setState(\"hoveredValue\", hoverValue);\n }\n },\n [isDisabled, isReadOnly, step, itemValue, store, context.dir, propsRef]\n );\n\n const dataState: DataState = isFilled ? \"full\" : isPartiallyFilled ? \"partial\" : \"empty\";\n\n const ItemPrimitive = asChild ? Slot : \"button\";\n\n return (\n <ItemPrimitive\n role=\"radio\"\n type=\"button\"\n id={itemId}\n aria-label={context.itemLabel(itemValue, context.max)}\n aria-checked={isChecked}\n aria-posinset={itemValue}\n aria-setsize={context.max}\n data-disabled={isDisabled ? \"\" : undefined}\n data-readonly={isReadOnly ? \"\" : undefined}\n data-state={dataState}\n data-hovered={isHovered ? \"\" : undefined}\n data-slot=\"rating-item\"\n disabled={isDisabled}\n tabIndex={isTabStop ? 0 : -1}\n {...itemProps}\n ref={composedRef}\n style={{\n ...itemProps.style,\n ...(isPartiallyFilled && {\n \"--partial-fill\": `url(#${getPartialFillGradientId(context.rootId, step)})`\n })\n }}\n className={cn(\n // Viền focus cùng khuôn với `Checkbox`/`RadioGroup` của gói.\n \"inline-flex items-center justify-center rounded transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:transition-colors [&_svg]:duration-200 data-[state=empty]:[&_svg]:fill-transparent data-[state=full]:[&_svg]:fill-current data-[state=partial]:[&_svg]:fill-(--partial-fill) [&_svg:not([class*='size-'])]:size-full\",\n context.size === \"sm\" ? \"size-4\" : context.size === \"lg\" ? \"size-6\" : \"size-5\",\n className\n )}\n onClick={onClick}\n onFocus={onFocus}\n onKeyDown={onKeyDown}\n onMouseDown={onMouseDown}\n onMouseEnter={onMouseEnter}\n onMouseMove={onMouseMove}\n onMouseLeave={onMouseLeave}\n >\n {typeof children === \"function\" ? children(dataState) : (children ?? <Star aria-hidden=\"true\" />)}\n </ItemPrimitive>\n );\n}\n\nexport { Rating, RatingItem, type RatingItemProps, type RatingProps, useStore as useRating };\n"],"mappings":"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","names":["value","instanceId","tabStopId","id","items","ref"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/rating.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/rating) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { Star } from \"lucide-react\";\nimport * as React from \"react\";\nimport { useComitorMessages } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { VisuallyHiddenInput } from \"../../lib/visually-hidden-input.js\";\n\ntype Direction = \"ltr\" | \"rtl\";\ntype Orientation = \"horizontal\" | \"vertical\";\ntype ActivationMode = \"automatic\" | \"manual\";\ntype Size = \"default\" | \"sm\" | \"lg\";\ntype Step = 0.5 | 1;\ntype DataState = \"full\" | \"partial\" | \"empty\";\ntype FocusIntent = \"first\" | \"last\" | \"prev\" | \"next\";\n\ntype RootElement = React.ComponentRef<typeof Rating>;\ntype ItemElement = React.ComponentRef<typeof RatingItem>;\n\nconst ROOT_NAME = \"Rating\";\nconst ITEM_NAME = \"RatingItem\";\n\nconst ENTRY_FOCUS = \"ratingFocusGroup.onEntryFocus\";\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\nfunction getItemId(id: string, value: number) {\n return `${id}-item-${value}`;\n}\n\nfunction getPartialFillGradientId(id: string, step: Step) {\n return `partial-fill-gradient-${id}-${step}`;\n}\n\nconst MAP_KEY_TO_FOCUS_INTENT: Record<string, FocusIntent> = {\n ArrowLeft: \"prev\",\n ArrowUp: \"prev\",\n ArrowRight: \"next\",\n ArrowDown: \"next\",\n Home: \"first\",\n End: \"last\"\n};\n\nfunction getDirectionAwareKey(key: string, dir?: Direction) {\n if (dir !== \"rtl\") return key;\n return key === \"ArrowLeft\" ? \"ArrowRight\" : key === \"ArrowRight\" ? \"ArrowLeft\" : key;\n}\n\nfunction getFocusIntent(event: React.KeyboardEvent<ItemElement>, dir?: Direction, orientation?: Orientation) {\n const key = getDirectionAwareKey(event.key, dir);\n if (orientation === \"horizontal\" && [\"ArrowUp\", \"ArrowDown\"].includes(key)) return undefined;\n if (orientation === \"vertical\" && [\"ArrowLeft\", \"ArrowRight\"].includes(key)) return undefined;\n return MAP_KEY_TO_FOCUS_INTENT[key];\n}\n\nfunction focusFirst(candidates: React.RefObject<ItemElement | null>[], preventScroll = false) {\n const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;\n for (const candidateRef of candidates) {\n const candidate = candidateRef.current;\n if (!candidate) continue;\n if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;\n candidate.focus({ preventScroll });\n if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;\n }\n}\n\ninterface StoreState {\n value: number;\n hoveredValue: number | null;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: <K extends keyof StoreState>(key: K, value: StoreState[K]) => void;\n notify: () => void;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nfunction useStore<T>(selector: (state: StoreState) => T, ogStore?: Store | null): T {\n const contextStore = React.useContext(StoreContext);\n\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`useRating\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ninterface ItemData {\n id: string;\n ref: React.RefObject<ItemElement | null>;\n value: number;\n disabled: boolean;\n}\n\ninterface RatingContextValue {\n rootId: string;\n dir: Direction;\n orientation: Orientation;\n activationMode: ActivationMode;\n size: Size;\n max: number;\n step: Step;\n clearable: boolean;\n disabled: boolean;\n readOnly: boolean;\n itemLabel: (value: number, max: number) => string;\n getAutoIndex: (instanceId: string) => number;\n}\n\nconst RatingContext = React.createContext<RatingContextValue | null>(null);\n\nfunction useRatingContext(consumerName: string) {\n const context = React.useContext(RatingContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface FocusContextValue {\n tabStopId: string | null;\n onItemFocus: (tabStopId: string) => void;\n onItemShiftTab: () => void;\n onFocusableItemAdd: () => void;\n onFocusableItemRemove: () => void;\n onItemRegister: (item: ItemData) => void;\n onItemUnregister: (id: string) => void;\n getItems: () => ItemData[];\n}\n\nconst FocusContext = React.createContext<FocusContextValue | null>(null);\n\nfunction useFocusContext(consumerName: string) {\n const context = React.useContext(FocusContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`FocusProvider\\``);\n }\n return context;\n}\n\ninterface RatingProps extends React.ComponentProps<\"div\"> {\n value?: number;\n defaultValue?: number;\n onValueChange?: (value: number) => void;\n onHover?: (value: number | null) => void;\n max?: number;\n activationMode?: ActivationMode;\n dir?: Direction;\n orientation?: Orientation;\n size?: Size;\n asChild?: boolean;\n step?: Step;\n clearable?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n name?: string;\n /**\n * Tên của TỪNG ngôi sao cho trình đọc màn hình — mặc định khoá `itemLabel` của namespace\n * `rating` (`ComitorLocaleProvider`).\n *\n * ⚠ Thêm so với thượng nguồn. Ở bản gốc mỗi `RatingItem` là một `role=\"radio\"` chỉ chứa một\n * `<svg>`, tức một nút KHÔNG TÊN: trình đọc màn hình đọc \"nút radio, 3 trên 5\" mà không nói 3\n * CÁI GÌ. Là HÀM chứ không phải chuỗi mẫu vì có số chèn vào giữa câu (README §5).\n *\n * Nhóm vẫn cần tên riêng: truyền `aria-label` (vd \"Mức hài lòng\") cho chính `Rating`.\n */\n itemLabel?: (value: number, max: number) => string;\n}\n\nfunction Rating(props: RatingProps) {\n const {\n value: valueProp,\n defaultValue = 0,\n onValueChange,\n onHover,\n onFocus: onFocusProp,\n onMouseDown: onMouseDownProp,\n dir: dirProp,\n orientation = \"horizontal\",\n activationMode = \"automatic\",\n size = \"default\",\n max = 5,\n step = 1,\n clearable = false,\n asChild,\n disabled = false,\n readOnly = false,\n required = false,\n itemLabel: itemLabelProp,\n className,\n children,\n id,\n name,\n ref,\n ...rootProps\n } = props;\n\n const t = useComitorMessages(\"rating\");\n const itemLabel = itemLabelProp ?? t.itemLabel;\n const dir = useDirection(dirProp);\n const instanceId = React.useId();\n const rootId = id ?? instanceId;\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<StoreState>(() => ({\n value: valueProp ?? defaultValue,\n hoveredValue: null\n }));\n\n const propsRef = useAsRef({\n onValueChange,\n onHover,\n onFocus: onFocusProp,\n onMouseDown: onMouseDownProp,\n step\n });\n\n const store = React.useMemo<Store>(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n if (key === \"value\" && typeof value === \"number\") {\n stateRef.current.value = value;\n propsRef.current.onValueChange?.(value);\n } else if (key === \"hoveredValue\") {\n stateRef.current.hoveredValue = value as number | null;\n propsRef.current.onHover?.(value as number | null);\n } else {\n stateRef.current[key] = value;\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n }\n };\n }, [listenersRef, stateRef, propsRef]);\n\n useIsomorphicLayoutEffect(() => {\n if (valueProp !== undefined) {\n store.setState(\"value\", valueProp);\n }\n }, [valueProp]);\n\n const value = useStore((state) => state.value, store);\n\n const [formTrigger, setFormTrigger] = React.useState<RootElement | null>(null);\n const composedRef = useComposedRefs(ref, (node) => setFormTrigger(node));\n const isFormControl = formTrigger ? !!formTrigger.closest(\"form\") : true;\n\n const [tabStopId, setTabStopId] = React.useState<string | null>(null);\n const [isTabbingBackOut, setIsTabbingBackOut] = React.useState(false);\n const [focusableItemCount, setFocusableItemCount] = React.useState(0);\n const isClickFocusRef = React.useRef(false);\n const itemsRef = React.useRef<Map<string, ItemData>>(new Map());\n\n const autoIndexMapRef = React.useRef(new Map<string, number>());\n const nextAutoIndexRef = React.useRef(0);\n\n const getAutoIndex = React.useCallback((instanceId: string) => {\n const existingIndex = autoIndexMapRef.current.get(instanceId);\n if (existingIndex !== undefined) {\n return existingIndex;\n }\n\n const newIndex = nextAutoIndexRef.current++;\n autoIndexMapRef.current.set(instanceId, newIndex);\n return newIndex;\n }, []);\n\n const onItemFocus = React.useCallback((tabStopId: string) => {\n setTabStopId(tabStopId);\n }, []);\n\n const onItemShiftTab = React.useCallback(() => {\n setIsTabbingBackOut(true);\n }, []);\n\n const onFocusableItemAdd = React.useCallback(() => {\n setFocusableItemCount((prevCount) => prevCount + 1);\n }, []);\n\n const onFocusableItemRemove = React.useCallback(() => {\n setFocusableItemCount((prevCount) => prevCount - 1);\n }, []);\n\n const onItemRegister = React.useCallback((item: ItemData) => {\n itemsRef.current.set(item.id, item);\n }, []);\n\n const onItemUnregister = React.useCallback((id: string) => {\n itemsRef.current.delete(id);\n }, []);\n\n const getItems = React.useCallback(() => {\n return Array.from(itemsRef.current.values())\n .filter((item) => item.ref.current)\n .sort((a, b) => {\n const elementA = a.ref.current;\n const elementB = b.ref.current;\n if (!elementA || !elementB) return 0;\n const position = elementA.compareDocumentPosition(elementB);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) {\n return -1;\n }\n if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n return 1;\n }\n return 0;\n });\n }, []);\n\n const onBlur = React.useCallback(\n (event: React.FocusEvent<HTMLDivElement>) => {\n rootProps.onBlur?.(event);\n if (event.defaultPrevented) return;\n\n setIsTabbingBackOut(false);\n },\n [rootProps.onBlur]\n );\n\n const onFocus = React.useCallback(\n (event: React.FocusEvent<HTMLDivElement>) => {\n propsRef.current.onFocus?.(event);\n if (event.defaultPrevented) return;\n\n const isKeyboardFocus = !isClickFocusRef.current;\n if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {\n const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);\n event.currentTarget.dispatchEvent(entryFocusEvent);\n\n if (!entryFocusEvent.defaultPrevented) {\n const items = Array.from(itemsRef.current.values()).filter((item) => !item.disabled);\n // Nửa sao: tìm mục đại diện cho giá trị đang chọn bằng giá trị TRẦN (3,5 → mục 4).\n const selectedItem =\n propsRef.current.step < 1\n ? items.find((item) => item.value === Math.ceil(value))\n : items.find((item) => item.value === value);\n const currentItem = items.find((item) => item.id === tabStopId);\n\n const candidateItems = [selectedItem, currentItem, ...items].filter(Boolean) as ItemData[];\n const candidateRefs = candidateItems.map((item) => item.ref);\n focusFirst(candidateRefs, false);\n }\n }\n isClickFocusRef.current = false;\n },\n [propsRef, isTabbingBackOut, value, tabStopId]\n );\n\n const onMouseDown = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n propsRef.current.onMouseDown?.(event);\n\n if (event.defaultPrevented) return;\n\n isClickFocusRef.current = true;\n },\n [propsRef]\n );\n\n const contextValue = React.useMemo<RatingContextValue>(\n () => ({\n rootId,\n dir,\n orientation,\n activationMode,\n disabled,\n readOnly,\n size,\n max,\n step,\n clearable,\n itemLabel,\n getAutoIndex\n }),\n [rootId, dir, orientation, activationMode, disabled, readOnly, size, max, step, clearable, itemLabel, getAutoIndex]\n );\n\n const focusContextValue = React.useMemo<FocusContextValue>(\n () => ({\n tabStopId,\n onItemFocus,\n onItemShiftTab,\n onFocusableItemAdd,\n onFocusableItemRemove,\n onItemRegister,\n onItemUnregister,\n getItems\n }),\n [\n tabStopId,\n onItemFocus,\n onItemShiftTab,\n onFocusableItemAdd,\n onFocusableItemRemove,\n onItemRegister,\n onItemUnregister,\n getItems\n ]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n /*\n * ⚠ Khác thượng nguồn: gradient của NỬA SAO phải nằm BÊN TRONG phần tử gốc. Trong SVG,\n * `stopColor=\"currentColor\"` lấy `color` tính ở chỗ gradient được KHAI, không phải ở chỗ nó được\n * dùng — bản gốc đặt `<svg>` này làm anh em của phần tử gốc, nên nửa sao ăn màu chữ của trang\n * (đo trên trình duyệt: #0E1116 ở light, #F7F7F8 ở dark) thay vì màu sao `text-primary-ink`.\n * Với `asChild` thì Slot không nhận thêm con được, nên gradient đành đứng ngoài như bản gốc —\n * khi đó app phải tự đặt màu chữ cho phần tử BAO NGOÀI.\n */\n const partialFillGradient = (\n <svg width=\"0\" height=\"0\" aria-hidden=\"true\" focusable=\"false\" style={{ position: \"absolute\" }}>\n <defs>\n <linearGradient id={getPartialFillGradientId(rootId, step)}>\n {dir === \"rtl\" ? (\n <>\n <stop offset=\"50%\" stopColor=\"transparent\" />\n <stop offset=\"50%\" stopColor=\"currentColor\" />\n </>\n ) : (\n <>\n <stop offset=\"50%\" stopColor=\"currentColor\" />\n <stop offset=\"50%\" stopColor=\"transparent\" />\n </>\n )}\n </linearGradient>\n </defs>\n </svg>\n );\n\n return (\n <StoreContext.Provider value={store}>\n <RatingContext.Provider value={contextValue}>\n <FocusContext.Provider value={focusContextValue}>\n <RootPrimitive\n id={rootId}\n role=\"radiogroup\"\n aria-orientation={orientation}\n aria-disabled={disabled || undefined}\n aria-readonly={readOnly || undefined}\n aria-required={required || undefined}\n data-disabled={disabled ? \"\" : undefined}\n data-readonly={readOnly ? \"\" : undefined}\n data-orientation={orientation}\n data-slot=\"rating\"\n dir={dir}\n tabIndex={isTabbingBackOut || focusableItemCount === 0 ? -1 : 0}\n {...rootProps}\n ref={composedRef}\n className={cn(\n /*\n * Ngôi sao là thành phần PHI VĂN BẢN mang nghĩa (nó LÀ giá trị) → màu đi qua bậc\n * `-ink` của tone, không phải token tô nền. Bản gốc `text-primary` đọc thẳng màu\n * TÔ NỀN; ở bảng mặc định hai token trùng nhau (`--primary-ink: var(--primary)`),\n * nhưng bảng tương phản cao kéo `--primary-ink` xuống bậc tối — và chỉ `-ink` mới\n * được đổi theo. Hợp đồng §1 của docs/hop-dong-mau.md.\n */\n \"flex gap-1 text-primary-ink outline-none\",\n orientation === \"horizontal\" ? \"flex-row items-center\" : \"flex-col items-start\",\n className\n )}\n onBlur={onBlur}\n onFocus={onFocus}\n onMouseDown={onMouseDown}\n >\n {asChild ? (\n children\n ) : (\n <>\n {children}\n {partialFillGradient}\n </>\n )}\n </RootPrimitive>\n {asChild ? partialFillGradient : null}\n {isFormControl && (\n <VisuallyHiddenInput\n type=\"hidden\"\n control={formTrigger}\n name={name}\n value={value}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n />\n )}\n </FocusContext.Provider>\n </RatingContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface RatingItemProps extends Omit<React.ComponentProps<\"button\">, \"children\"> {\n index?: number;\n asChild?: boolean;\n children?: React.ReactNode | ((dataState: DataState) => React.ReactNode);\n}\n\nfunction RatingItem(props: RatingItemProps) {\n const {\n index,\n asChild,\n onClick: onClickProp,\n onFocus: onFocusProp,\n onKeyDown: onKeyDownProp,\n onMouseDown: onMouseDownProp,\n onMouseEnter: onMouseEnterProp,\n onMouseMove: onMouseMoveProp,\n onMouseLeave: onMouseLeaveProp,\n disabled,\n className,\n children,\n ref,\n ...itemProps\n } = props;\n\n const itemRef = React.useRef<ItemElement>(null);\n const composedRef = useComposedRefs(ref, itemRef);\n\n const context = useRatingContext(ITEM_NAME);\n\n const instanceId = React.useId();\n\n const actualIndex = React.useMemo(() => {\n if (index !== undefined) {\n return index;\n }\n\n return context.getAutoIndex(instanceId);\n }, [index, context, instanceId]);\n\n const itemValue = actualIndex + 1;\n const store = useStoreContext(ITEM_NAME);\n const focusContext = useFocusContext(ITEM_NAME);\n const value = useStore((state) => state.value);\n const hoveredValue = useStore((state) => state.hoveredValue);\n const clearable = context.clearable;\n const step = context.step;\n const activationMode = context.activationMode;\n\n const itemId = getItemId(context.rootId, itemValue);\n const isDisabled = context.disabled || disabled;\n const isReadOnly = context.readOnly;\n const isTabStop = focusContext.tabStopId === itemId;\n\n const displayValue = hoveredValue ?? value;\n const isFilled = displayValue >= itemValue;\n const isPartiallyFilled = step < 1 && displayValue >= itemValue - step && displayValue < itemValue;\n const isHovered = hoveredValue !== null && hoveredValue < itemValue;\n /*\n * ⚠ Khác thượng nguồn: bản gốc đặt `aria-checked={isFilled}`, tức chọn 4 sao thì BỐN nút radio\n * cùng báo \"đã chọn\" — một radiogroup có nhiều radio được chọn là trạng thái không tồn tại với\n * trình đọc màn hình. Ở đây chỉ đúng MỘT mục được chọn: mục chứa giá trị (3,5 → mục 4), và đọc\n * theo `value` thật chứ không theo sao đang được rê chuột (`displayValue`).\n */\n const isChecked = value > 0 && Math.ceil(value) === itemValue;\n\n const isMouseClickRef = React.useRef(false);\n\n const propsRef = useAsRef({\n onClick: onClickProp,\n onFocus: onFocusProp,\n onKeyDown: onKeyDownProp,\n onMouseDown: onMouseDownProp,\n onMouseEnter: onMouseEnterProp,\n onMouseMove: onMouseMoveProp,\n onMouseLeave: onMouseLeaveProp\n });\n\n useIsomorphicLayoutEffect(() => {\n focusContext.onItemRegister({\n id: itemId,\n ref: itemRef,\n value: itemValue,\n disabled: !!isDisabled\n });\n\n if (!isDisabled) {\n focusContext.onFocusableItemAdd();\n }\n\n return () => {\n focusContext.onItemUnregister(itemId);\n if (!isDisabled) {\n focusContext.onFocusableItemRemove();\n }\n };\n }, [focusContext, itemId, itemValue, isDisabled]);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onClick?.(event);\n if (event.defaultPrevented) return;\n\n if (!isDisabled && !isReadOnly) {\n let newValue = itemValue;\n\n if (step < 1) {\n const rect = event.currentTarget.getBoundingClientRect();\n const clickX = event.clientX - rect.left;\n const isLeftHalf = clickX < rect.width / 2;\n\n if (context.dir === \"rtl\") {\n if (!isLeftHalf) {\n newValue = itemValue - step;\n }\n } else {\n if (isLeftHalf) {\n newValue = itemValue - step;\n }\n }\n }\n\n if (clearable && value === newValue) {\n newValue = 0;\n }\n\n store.setState(\"value\", newValue);\n }\n },\n [isDisabled, isReadOnly, clearable, step, value, itemValue, store, context.dir, propsRef]\n );\n\n const onFocus = React.useCallback(\n (event: React.FocusEvent<ItemElement>) => {\n propsRef.current.onFocus?.(event);\n if (event.defaultPrevented) return;\n\n focusContext.onItemFocus(itemId);\n\n const isKeyboardFocus = !isMouseClickRef.current;\n\n /*\n * ⚠ Khác thượng nguồn (3.0.1): chỉ CHỌN khi focus tới từ một mục khác của CÙNG nhóm — tức\n * người dùng đang đi bằng phím mũi tên. Bản gốc chọn ở mọi lần focus bằng bàn phím, kể cả lúc\n * Tab ĐI NGANG QUA: nhóm chưa chấm thành 1 sao chỉ vì người dùng Tab qua một biểu mẫu, còn\n * với `clearable` thì Tab vào một nhóm đã chấm lại XOÁ điểm (focus rơi đúng mục đang chọn,\n * và chọn lại mục đang chọn là xoá). Radio group gốc của trình duyệt và mẫu WAI-ARIA đều thế\n * này: Tab vào nhóm chỉ đưa focus tới, mũi tên mới chọn.\n * Tab vào nhóm thì focus đi từ `Rating` gốc (có `tabIndex`) sang một mục, nên `relatedTarget`\n * là chính gốc — không phải một mục khác.\n */\n const previous = event.relatedTarget;\n const cameFromSibling =\n previous instanceof HTMLElement &&\n previous !== event.currentTarget &&\n previous.getAttribute(\"data-slot\") === \"rating-item\" &&\n previous.closest('[data-slot=\"rating\"]') === event.currentTarget.closest('[data-slot=\"rating\"]');\n\n if (!isDisabled && !isReadOnly && activationMode !== \"manual\" && isKeyboardFocus && cameFromSibling) {\n // Nửa sao: nếu giá trị đang là nửa-bậc THUỘC mục này (3,5 khi mục là 4) thì đừng đổi nó.\n const isHalfStepValue = step < 1 && value === itemValue - step;\n\n if (!isHalfStepValue) {\n const newValue = clearable && value === itemValue ? 0 : itemValue;\n store.setState(\"value\", newValue);\n }\n }\n\n isMouseClickRef.current = false;\n },\n [focusContext, itemId, activationMode, isDisabled, isReadOnly, clearable, value, itemValue, step, store, propsRef]\n );\n\n const onKeyDown = React.useCallback(\n (event: React.KeyboardEvent<ItemElement>) => {\n propsRef.current.onKeyDown?.(event);\n if (event.defaultPrevented) return;\n\n if ((event.key === \"Enter\" || event.key === \" \") && activationMode === \"manual\") {\n event.preventDefault();\n if (!isDisabled && !isReadOnly && itemRef.current) {\n itemRef.current.click();\n }\n return;\n }\n\n if (event.key === \"Tab\" && event.shiftKey) {\n focusContext.onItemShiftTab();\n return;\n }\n\n if (event.target !== event.currentTarget) return;\n\n const focusIntent = getFocusIntent(event, context.dir, context.orientation);\n\n if (focusIntent !== undefined) {\n if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;\n event.preventDefault();\n\n // Nửa sao: mũi tên tăng/giảm đúng một `step` thay vì nhảy sang mục kế.\n if (step < 1 && (focusIntent === \"prev\" || focusIntent === \"next\")) {\n if (!isDisabled && !isReadOnly) {\n let newValue = value;\n\n if (focusIntent === \"next\") {\n newValue = Math.min(value + step, context.max);\n } else {\n newValue = Math.max(value - step, 0);\n }\n\n store.setState(\"value\", newValue);\n\n // Đưa focus tới mục đại diện cho giá trị mới.\n const items = focusContext.getItems().filter((item) => !item.disabled);\n const targetItem = items.find((item) => item.value === Math.ceil(newValue));\n if (targetItem?.ref.current) {\n queueMicrotask(() => targetItem.ref.current?.focus());\n }\n }\n return;\n }\n\n // Bậc nguyên, hoặc Home/End: điều hướng như thường.\n const items = focusContext.getItems().filter((item) => !item.disabled);\n let candidateRefs = items.map((item) => item.ref);\n\n if (focusIntent === \"last\") {\n candidateRefs.reverse();\n } else if (focusIntent === \"prev\" || focusIntent === \"next\") {\n if (focusIntent === \"prev\") candidateRefs.reverse();\n const currentIndex = candidateRefs.findIndex((ref) => ref.current === event.currentTarget);\n candidateRefs = candidateRefs.slice(currentIndex + 1);\n }\n\n queueMicrotask(() => focusFirst(candidateRefs));\n }\n },\n [\n focusContext,\n context.dir,\n context.orientation,\n activationMode,\n isDisabled,\n isReadOnly,\n step,\n value,\n context.max,\n store,\n propsRef\n ]\n );\n\n const onMouseDown = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onMouseDown?.(event);\n if (event.defaultPrevented) return;\n\n isMouseClickRef.current = true;\n\n if (isDisabled) {\n event.preventDefault();\n } else {\n focusContext.onItemFocus(itemId);\n }\n },\n [focusContext, itemId, isDisabled, propsRef]\n );\n\n const onMouseEnter = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onMouseEnter?.(event);\n if (event.defaultPrevented) return;\n\n if (!isDisabled && !isReadOnly) {\n let hoverValue = itemValue;\n\n if (step < 1) {\n const rect = event.currentTarget.getBoundingClientRect();\n const mouseX = event.clientX - rect.left;\n const isLeftHalf = mouseX < rect.width / 2;\n\n if (context.dir === \"rtl\") {\n if (!isLeftHalf) {\n hoverValue = itemValue - step;\n }\n } else {\n if (isLeftHalf) {\n hoverValue = itemValue - step;\n }\n }\n }\n\n store.setState(\"hoveredValue\", hoverValue);\n }\n },\n [isDisabled, isReadOnly, step, itemValue, store, context.dir, propsRef]\n );\n\n const onMouseLeave = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onMouseLeave?.(event);\n if (event.defaultPrevented) return;\n\n if (!isDisabled && !isReadOnly) {\n store.setState(\"hoveredValue\", null);\n }\n },\n [isDisabled, isReadOnly, store, propsRef]\n );\n\n const onMouseMove = React.useCallback(\n (event: React.MouseEvent<ItemElement>) => {\n propsRef.current.onMouseMove?.(event);\n if (event.defaultPrevented) return;\n\n if (!isDisabled && !isReadOnly && step < 1) {\n const rect = event.currentTarget.getBoundingClientRect();\n const mouseX = event.clientX - rect.left;\n const isLeftHalf = mouseX < rect.width / 2;\n\n let hoverValue = itemValue;\n if (context.dir === \"rtl\") {\n hoverValue = !isLeftHalf ? itemValue - step : itemValue;\n } else {\n hoverValue = isLeftHalf ? itemValue - step : itemValue;\n }\n\n store.setState(\"hoveredValue\", hoverValue);\n }\n },\n [isDisabled, isReadOnly, step, itemValue, store, context.dir, propsRef]\n );\n\n const dataState: DataState = isFilled ? \"full\" : isPartiallyFilled ? \"partial\" : \"empty\";\n\n const ItemPrimitive = asChild ? Slot : \"button\";\n\n return (\n <ItemPrimitive\n role=\"radio\"\n type=\"button\"\n id={itemId}\n /*\n * ⚠ Khác thượng nguồn (3.0.1): mục ĐANG CHỌN của một giá trị lẻ (4,5 → mục 5) mang tên theo giá\n * trị thật. Trước đó trình đọc màn hình nghe \"5 stars, checked\" cho điểm trung bình 4,5 — mục\n * được chọn là mục trần của giá trị, còn tên thì đọc số thứ tự của mục.\n */\n aria-label={context.itemLabel(isChecked && value !== itemValue ? value : itemValue, context.max)}\n aria-checked={isChecked}\n aria-posinset={itemValue}\n aria-setsize={context.max}\n data-disabled={isDisabled ? \"\" : undefined}\n data-readonly={isReadOnly ? \"\" : undefined}\n data-state={dataState}\n data-hovered={isHovered ? \"\" : undefined}\n data-slot=\"rating-item\"\n disabled={isDisabled}\n tabIndex={isTabStop ? 0 : -1}\n {...itemProps}\n ref={composedRef}\n style={{\n ...itemProps.style,\n ...(isPartiallyFilled && {\n \"--partial-fill\": `url(#${getPartialFillGradientId(context.rootId, step)})`\n })\n }}\n className={cn(\n // Viền focus cùng khuôn với `Checkbox`/`RadioGroup` của gói.\n \"inline-flex items-center justify-center rounded transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:transition-colors [&_svg]:duration-200 data-[state=empty]:[&_svg]:fill-transparent data-[state=full]:[&_svg]:fill-current data-[state=partial]:[&_svg]:fill-(--partial-fill) [&_svg:not([class*='size-'])]:size-full\",\n context.size === \"sm\" ? \"size-4\" : context.size === \"lg\" ? \"size-6\" : \"size-5\",\n className\n )}\n onClick={onClick}\n onFocus={onFocus}\n onKeyDown={onKeyDown}\n onMouseDown={onMouseDown}\n onMouseEnter={onMouseEnter}\n onMouseMove={onMouseMove}\n onMouseLeave={onMouseLeave}\n >\n {typeof children === \"function\" ? children(dataState) : (children ?? <Star aria-hidden=\"true\" />)}\n </ItemPrimitive>\n );\n}\n\nexport { Rating, RatingItem, type RatingItemProps, type RatingProps, useStore as useRating };\n"],"mappings":"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","names":["value","instanceId","tabStopId","id","items","ref"]}
|