@comitor/ui 3.0.1 → 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.
Files changed (76) hide show
  1. package/dist/components/composite/confirm-dialog.js +56 -35
  2. package/dist/components/composite/confirm-dialog.js.map +1 -1
  3. package/dist/components/composite/search-filter-bar-constants.d.ts +3 -0
  4. package/dist/components/composite/search-filter-bar-constants.js.map +1 -1
  5. package/dist/components/composite/table-pagination-constants.d.ts +3 -1
  6. package/dist/components/composite/table-pagination-constants.js.map +1 -1
  7. package/dist/components/composite/table-pagination.js +10 -2
  8. package/dist/components/composite/table-pagination.js.map +1 -1
  9. package/dist/components/composite/text-utils.d.ts +4 -23
  10. package/dist/components/composite/text-utils.js +1 -11
  11. package/dist/components/composite/text-utils.js.map +1 -1
  12. package/dist/components/ui/banner.d.ts +8 -0
  13. package/dist/components/ui/banner.js +149 -35
  14. package/dist/components/ui/banner.js.map +1 -1
  15. package/dist/components/ui/mask-input-constants.d.ts +34 -2
  16. package/dist/components/ui/mask-input-constants.js +56 -5
  17. package/dist/components/ui/mask-input-constants.js.map +1 -1
  18. package/dist/components/ui/mask-input.d.ts +6 -5
  19. package/dist/components/ui/mask-input.js +5 -1
  20. package/dist/components/ui/mask-input.js.map +1 -1
  21. package/dist/components/ui/mention.d.ts +14 -2
  22. package/dist/components/ui/mention.js +33 -6
  23. package/dist/components/ui/mention.js.map +1 -1
  24. package/dist/components/ui/phone-input.d.ts +18 -8
  25. package/dist/components/ui/phone-input.js +120 -33
  26. package/dist/components/ui/phone-input.js.map +1 -1
  27. package/dist/components/ui/scroll-spy.js +46 -31
  28. package/dist/components/ui/scroll-spy.js.map +1 -1
  29. package/dist/components/ui/stepper.js +26 -3
  30. package/dist/components/ui/stepper.js.map +1 -1
  31. package/dist/components/ui/time-picker.d.ts +24 -4
  32. package/dist/components/ui/time-picker.js +425 -162
  33. package/dist/components/ui/time-picker.js.map +1 -1
  34. package/dist/components/ui/timeline.js +45 -9
  35. package/dist/components/ui/timeline.js.map +1 -1
  36. package/dist/data-grid/data-grid-cell-variants.js +4 -4
  37. package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
  38. package/dist/data-grid/data-grid-cell-wrapper.d.ts +1 -1
  39. package/dist/data-grid/data-grid-cell-wrapper.js +6 -0
  40. package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -1
  41. package/dist/data-grid/data-grid-row.js +1 -1
  42. package/dist/data-grid/data-grid-row.js.map +1 -1
  43. package/dist/data-grid/data-grid-select-column.js +6 -2
  44. package/dist/data-grid/data-grid-select-column.js.map +1 -1
  45. package/dist/data-grid/data-grid-skeleton.d.ts +5 -0
  46. package/dist/data-grid/data-grid-skeleton.js +1 -4
  47. package/dist/data-grid/data-grid-skeleton.js.map +1 -1
  48. package/dist/data-grid/data-grid.d.ts +1 -1
  49. package/dist/data-grid/data-grid.js +3 -2
  50. package/dist/data-grid/data-grid.js.map +1 -1
  51. package/dist/data-grid/filters.js +3 -2
  52. package/dist/data-grid/filters.js.map +1 -1
  53. package/dist/data-grid/types.d.ts +7 -0
  54. package/dist/data-grid/use-data-grid.d.ts +3 -2
  55. package/dist/data-grid/use-data-grid.js +70 -24
  56. package/dist/data-grid/use-data-grid.js.map +1 -1
  57. package/dist/data-grid/utils.d.ts +7 -0
  58. package/dist/data-grid/utils.js +3 -1
  59. package/dist/data-grid/utils.js.map +1 -1
  60. package/dist/i18n/namespaces/search-filter-bar.js +8 -6
  61. package/dist/i18n/namespaces/search-filter-bar.js.map +1 -1
  62. package/dist/i18n/namespaces/table-pagination.js +6 -4
  63. package/dist/i18n/namespaces/table-pagination.js.map +1 -1
  64. package/dist/index.d.ts +2 -1
  65. package/dist/lib/collect-item-elements.d.ts +47 -0
  66. package/dist/lib/collect-item-elements.js +22 -0
  67. package/dist/lib/collect-item-elements.js.map +1 -0
  68. package/dist/lib/text-search.d.ts +32 -0
  69. package/dist/lib/text-search.js +17 -0
  70. package/dist/lib/text-search.js.map +1 -0
  71. package/dist/shell/app-shell.d.ts +1 -0
  72. package/dist/shell/display-axis-provider.d.ts +1 -1
  73. package/dist/shell/index.d.ts +2 -1
  74. package/dist/shell/shell-context.d.ts +1 -0
  75. package/dist/shell/utils.d.ts +2 -1
  76. 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, 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: 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"]}
@@ -89,15 +89,19 @@ function ScrollSpy(props) {
89
89
  };
90
90
  }, [listenersRef, stateRef, onValueChangeRef]);
91
91
  const sectionMapRef = React.useRef(/* @__PURE__ */ new Map());
92
+ const sectionObserverRef = React.useRef(null);
92
93
  const isScrollingRef = React.useRef(false);
93
94
  const rafIdRef = React.useRef(null);
94
95
  const isMountedRef = React.useRef(false);
95
96
  const scrollTimeoutRef = React.useRef(null);
96
97
  const onSectionRegister = React.useCallback((id, element) => {
97
98
  sectionMapRef.current.set(id, element);
99
+ sectionObserverRef.current?.observe(element);
98
100
  }, []);
99
- const onSectionUnregister = React.useCallback((id) => {
100
- sectionMapRef.current.delete(id);
101
+ const onSectionUnregister = React.useCallback((id, element) => {
102
+ const sectionMap = sectionMapRef.current;
103
+ if (sectionMap.get(id) === element) sectionMap.delete(id);
104
+ sectionObserverRef.current?.unobserve(element);
101
105
  }, []);
102
106
  const onScrollToSection = React.useCallback(
103
107
  (sectionId) => {
@@ -151,45 +155,57 @@ function ScrollSpy(props) {
151
155
  }, [value, store, onScrollToSectionRef]);
152
156
  useIsomorphicLayoutEffect(() => {
153
157
  const sectionMap = sectionMapRef.current;
154
- if (sectionMap.size === 0) return;
155
158
  const observerRootMargin = rootMargin ?? `${-offset}px 0px -70% 0px`;
156
- const observer = new IntersectionObserver(
157
- (entries) => {
158
- if (isScrollingRef.current) return;
159
- if (rafIdRef.current !== null) {
160
- cancelAnimationFrame(rafIdRef.current);
159
+ let observer = null;
160
+ const onIntersect = (entries) => {
161
+ if (isScrollingRef.current) return;
162
+ if (rafIdRef.current !== null) {
163
+ cancelAnimationFrame(rafIdRef.current);
164
+ }
165
+ rafIdRef.current = requestAnimationFrame(() => {
166
+ const intersecting = entries.filter((entry) => entry.isIntersecting);
167
+ if (intersecting.length === 0) return;
168
+ const topmost = intersecting.reduce((prev, curr) => {
169
+ return curr.boundingClientRect.top < prev.boundingClientRect.top ? curr : prev;
170
+ });
171
+ const id = topmost.target.id;
172
+ if (id && sectionMap.has(id)) {
173
+ store.setState("value", id);
161
174
  }
162
- rafIdRef.current = requestAnimationFrame(() => {
163
- const intersecting = entries.filter((entry) => entry.isIntersecting);
164
- if (intersecting.length === 0) return;
165
- const topmost = intersecting.reduce((prev, curr) => {
166
- return curr.boundingClientRect.top < prev.boundingClientRect.top ? curr : prev;
167
- });
168
- const id = topmost.target.id;
169
- if (id && sectionMap.has(id)) {
170
- store.setState("value", id);
171
- }
175
+ });
176
+ };
177
+ const sectionObserver = {
178
+ observe: (element) => {
179
+ observer ??= new IntersectionObserver(onIntersect, {
180
+ root: scrollContainer,
181
+ rootMargin: observerRootMargin,
182
+ threshold
172
183
  });
184
+ observer.observe(element);
173
185
  },
174
- {
175
- root: scrollContainer,
176
- rootMargin: observerRootMargin,
177
- threshold
186
+ unobserve: (element) => {
187
+ observer?.unobserve(element);
178
188
  }
179
- );
189
+ };
190
+ sectionObserverRef.current = sectionObserver;
180
191
  for (const element of sectionMap.values()) {
181
- observer.observe(element);
192
+ sectionObserver.observe(element);
182
193
  }
183
194
  return () => {
184
- observer.disconnect();
195
+ sectionObserverRef.current = null;
196
+ observer?.disconnect();
185
197
  if (rafIdRef.current !== null) {
186
198
  cancelAnimationFrame(rafIdRef.current);
187
199
  }
200
+ };
201
+ }, [offset, rootMargin, threshold, scrollContainer]);
202
+ React.useEffect(() => {
203
+ return () => {
188
204
  if (scrollTimeoutRef.current !== null) {
189
205
  clearTimeout(scrollTimeoutRef.current);
190
206
  }
191
207
  };
192
- }, [offset, rootMargin, threshold, scrollContainer]);
208
+ }, []);
193
209
  const contextValue = React.useMemo(
194
210
  () => ({
195
211
  dir,
@@ -304,16 +320,15 @@ function ScrollSpyViewport(props) {
304
320
  function ScrollSpySection(props) {
305
321
  const { asChild, ref, value, ...sectionProps } = props;
306
322
  const { orientation, onSectionRegister, onSectionUnregister } = useScrollSpyContext(SECTION_NAME);
307
- const sectionRef = React.useRef(null);
308
- const composedRef = useComposedRefs(ref, sectionRef);
323
+ const [element, setElement] = React.useState(null);
324
+ const composedRef = useComposedRefs(ref, setElement);
309
325
  useIsomorphicLayoutEffect(() => {
310
- const element = sectionRef.current;
311
326
  if (!element || !value) return;
312
327
  onSectionRegister(value, element);
313
328
  return () => {
314
- onSectionUnregister(value);
329
+ onSectionUnregister(value, element);
315
330
  };
316
- }, [value, onSectionRegister, onSectionUnregister]);
331
+ }, [element, value, onSectionRegister, onSectionUnregister]);
317
332
  const SectionPrimitive = asChild ? Slot : "div";
318
333
  return /* @__PURE__ */ jsx(
319
334
  SectionPrimitive,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/ui/scroll-spy.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/scroll-spy) — 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 * Dùng ở Comitor: trang cài đặt dài và trang chi tiết bản ghi (các mục của một liên hệ CRM) có\n * mục lục điều hướng trong trang.\n *\n * ⚠ `orientation` giữ NGHĨA của thượng nguồn — nó nói về hướng xếp của KHUNG, không phải của danh\n * sách link: `horizontal` (mặc định) = mục lục đứng bên cạnh nội dung, link xếp DỌC; `vertical` =\n * mục lục nằm trên nội dung, link xếp NGANG.\n */\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Slot } from \"@radix-ui/react-slot\";\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\";\n\nconst ROOT_NAME = \"ScrollSpy\";\nconst NAV_NAME = \"ScrollSpyNav\";\nconst LINK_NAME = \"ScrollSpyLink\";\nconst VIEWPORT_NAME = \"ScrollSpyViewport\";\nconst SECTION_NAME = \"ScrollSpySection\";\n\ntype Direction = \"ltr\" | \"rtl\";\ntype Orientation = \"horizontal\" | \"vertical\";\n\ntype LinkElement = React.ComponentRef<typeof ScrollSpyLink>;\ntype SectionElement = React.ComponentRef<typeof ScrollSpySection>;\n\nfunction getDefaultScrollBehavior(): ScrollBehavior {\n if (typeof window === \"undefined\") return \"smooth\";\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\";\n}\n\ninterface StoreState {\n value: string;\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 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(`\\`useStore\\` 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 ScrollSpyContextValue {\n offset: number;\n scrollBehavior: ScrollBehavior | undefined;\n dir: Direction;\n orientation: Orientation;\n scrollContainer: HTMLElement | null;\n isScrollingRef: React.RefObject<boolean>;\n onSectionRegister: (id: string, element: SectionElement) => void;\n onSectionUnregister: (id: string) => void;\n onScrollToSection: (sectionId: string) => void;\n}\n\nconst ScrollSpyContext = React.createContext<ScrollSpyContextValue | null>(null);\n\nfunction useScrollSpyContext(consumerName: string) {\n const context = React.useContext(ScrollSpyContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface ScrollSpyProps extends React.ComponentProps<\"div\"> {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n rootMargin?: string;\n threshold?: number | number[];\n offset?: number;\n /**\n * Kiểu cuộn khi bấm link. Không truyền thì `\"smooth\"`, hoặc `\"auto\"` nếu người dùng bật giảm\n * chuyển động (`prefers-reduced-motion`).\n */\n scrollBehavior?: ScrollBehavior;\n scrollContainer?: HTMLElement | null;\n dir?: Direction;\n orientation?: Orientation;\n asChild?: boolean;\n}\n\nfunction ScrollSpy(props: ScrollSpyProps) {\n const {\n value,\n defaultValue,\n onValueChange,\n rootMargin,\n threshold = 0.1,\n offset = 0,\n /*\n * ⚠ Khác thượng nguồn: bản gốc tính mặc định NGAY TRONG render (`scrollBehavior =\n * getDefaultScrollBehavior()` → `window.matchMedia` mỗi lượt render). Ở đây để `undefined` và\n * chỉ phân giải lúc cuộn thật — không chạm `window` khi render, và đọc đúng thiết lập giảm\n * chuyển động TẠI THỜI ĐIỂM bấm chứ không phải lúc render gần nhất.\n */\n scrollBehavior,\n scrollContainer = null,\n dir: dirProp,\n orientation = \"horizontal\",\n asChild,\n className,\n ...rootProps\n } = props;\n\n const dir = useDirection(dirProp);\n\n const stateRef = useLazyRef<StoreState>(() => ({\n value: value ?? defaultValue ?? \"\"\n }));\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const onValueChangeRef = useAsRef(onValueChange);\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: () => {\n return stateRef.current;\n },\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n stateRef.current[key] = value;\n\n if (key === \"value\" && value) {\n onValueChangeRef.current?.(value);\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n }\n };\n }, [listenersRef, stateRef, onValueChangeRef]);\n\n const sectionMapRef = React.useRef(new Map<string, Element>());\n const isScrollingRef = React.useRef(false);\n const rafIdRef = React.useRef<number | null>(null);\n const isMountedRef = React.useRef(false);\n const scrollTimeoutRef = React.useRef<number | null>(null);\n\n const onSectionRegister = React.useCallback((id: string, element: SectionElement) => {\n sectionMapRef.current.set(id, element);\n }, []);\n\n const onSectionUnregister = React.useCallback((id: string) => {\n sectionMapRef.current.delete(id);\n }, []);\n\n const onScrollToSection = React.useCallback(\n (sectionId: string) => {\n /*\n * ⚠ Khác thượng nguồn: `CSS.escape` quanh id. Bản gốc ghép thẳng `#${sectionId}` vào\n * `querySelector`, nên id bắt đầu bằng chữ số (\"2024-hop-dong\") hay chứa ký tự đặc biệt\n * (id của `useId()` như \":r1:\") làm nó THROW `SyntaxError` ngay khi bấm link.\n */\n const section = scrollContainer\n ? scrollContainer.querySelector(`#${CSS.escape(sectionId)}`)\n : document.getElementById(sectionId);\n\n if (!section) {\n store.setState(\"value\", sectionId);\n return;\n }\n\n // Bật cờ để observer không ghi đè giá trị trong lúc đang cuộn theo lệnh.\n isScrollingRef.current = true;\n store.setState(\"value\", sectionId);\n\n const behavior = scrollBehavior ?? getDefaultScrollBehavior();\n\n if (scrollContainer) {\n const containerRect = scrollContainer.getBoundingClientRect();\n const sectionRect = section.getBoundingClientRect();\n const scrollTop = scrollContainer.scrollTop;\n const offsetPosition = sectionRect.top - containerRect.top + scrollTop - offset;\n\n scrollContainer.scrollTo({\n top: offsetPosition,\n behavior\n });\n } else {\n const sectionPosition = section.getBoundingClientRect().top;\n const offsetPosition = sectionPosition + window.scrollY - offset;\n\n window.scrollTo({\n top: offsetPosition,\n behavior\n });\n }\n\n if (scrollTimeoutRef.current !== null) {\n clearTimeout(scrollTimeoutRef.current);\n }\n\n scrollTimeoutRef.current = window.setTimeout(() => {\n isScrollingRef.current = false;\n }, 500);\n },\n [scrollContainer, offset, scrollBehavior, store]\n );\n\n /*\n * ⚠ Khác thượng nguồn: chỉ cuộn theo lệnh khi `value` đổi TỪ BÊN NGOÀI. Bản gốc cuộn mỗi khi\n * effect chạy lại sau lần đầu, với hai hệ quả đã đo trên trình duyệt:\n * · StrictMode chạy effect hai lần lúc mount → lần hai cuộn luôn CẢ TRANG tới mục (scrollY\n * 0 → ~5050) vì `scrollContainer` của app lúc đó còn `null`. Next dev bật StrictMode sẵn.\n * · Chế độ controlled tự kéo giật: observer đặt giá trị → `onValueChange` → app trả về prop\n * `value` → effect cuộn tới ĐẦU mục đó, ngay giữa lúc người dùng đang cuộn.\n * Luật mới: lúc mount không cuộn (đúng ý nhánh mount của bản gốc); về sau, `value` trùng với giá\n * trị store đang giữ nghĩa là nó chỉ là tiếng vọng của chính observer/link → không cuộn.\n * `defaultValue` đã vào store từ lúc khởi tạo (`stateRef`), không cần đồng bộ thêm.\n */\n const prevValuePropRef = React.useRef<string | undefined>(undefined);\n const onScrollToSectionRef = useAsRef(onScrollToSection);\n\n useIsomorphicLayoutEffect(() => {\n const previous = prevValuePropRef.current;\n prevValuePropRef.current = value;\n if (value === undefined || value === previous) return;\n\n if (previous === undefined || !isMountedRef.current) {\n isMountedRef.current = true;\n store.setState(\"value\", value);\n return;\n }\n\n if (value === store.getState().value) return;\n onScrollToSectionRef.current(value);\n }, [value, store, onScrollToSectionRef]);\n\n useIsomorphicLayoutEffect(() => {\n const sectionMap = sectionMapRef.current;\n if (sectionMap.size === 0) return;\n\n const observerRootMargin = rootMargin ?? `${-offset}px 0px -70% 0px`;\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (isScrollingRef.current) return;\n\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n }\n\n rafIdRef.current = requestAnimationFrame(() => {\n const intersecting = entries.filter((entry) => entry.isIntersecting);\n\n if (intersecting.length === 0) return;\n\n const topmost = intersecting.reduce((prev, curr) => {\n return curr.boundingClientRect.top < prev.boundingClientRect.top ? curr : prev;\n });\n\n const id = topmost.target.id;\n if (id && sectionMap.has(id)) {\n store.setState(\"value\", id);\n }\n });\n },\n {\n root: scrollContainer,\n rootMargin: observerRootMargin,\n threshold\n }\n );\n\n for (const element of sectionMap.values()) {\n observer.observe(element);\n }\n\n return () => {\n observer.disconnect();\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n }\n if (scrollTimeoutRef.current !== null) {\n clearTimeout(scrollTimeoutRef.current);\n }\n };\n }, [offset, rootMargin, threshold, scrollContainer]);\n\n const contextValue = React.useMemo<ScrollSpyContextValue>(\n () => ({\n dir,\n orientation,\n offset,\n scrollBehavior,\n scrollContainer,\n isScrollingRef,\n onSectionRegister,\n onSectionUnregister,\n onScrollToSection\n }),\n [\n dir,\n orientation,\n offset,\n scrollBehavior,\n scrollContainer,\n onSectionRegister,\n onSectionUnregister,\n onScrollToSection\n ]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <ScrollSpyContext.Provider value={contextValue}>\n <RootPrimitive\n data-orientation={orientation}\n data-slot=\"scroll-spy\"\n dir={dir}\n {...rootProps}\n className={cn(\"flex\", orientation === \"horizontal\" ? \"flex-row\" : \"flex-col\", className)}\n />\n </ScrollSpyContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface ScrollSpyNavProps extends React.ComponentProps<\"nav\"> {\n asChild?: boolean;\n}\n\nfunction ScrollSpyNav(props: ScrollSpyNavProps) {\n const { asChild, className, ...navProps } = props;\n\n const { dir, orientation } = useScrollSpyContext(NAV_NAME);\n const t = useComitorMessages(\"scrollSpy\");\n\n const NavPrimitive = asChild ? Slot : \"nav\";\n\n return (\n <NavPrimitive\n /*\n * ⚠ Khác thượng nguồn: `<nav>` có tên mặc định (khoá `navLabel` của namespace `scrollSpy`,\n * theo `ComitorLocaleProvider`). Trong khung app Comitor đã có ít nhất MỘT landmark\n * `navigation` (sidebar), nên một `<nav>` thứ hai không tên là hai landmark trùng loại không\n * phân biệt được trong danh sách landmark của trình đọc màn hình. Ghi đè bằng chính prop\n * `aria-label` (cùng khuôn `Breadcrumb`/`Pagination` của gói).\n */\n aria-label={t.navLabel}\n data-orientation={orientation}\n data-slot=\"scroll-spy-nav\"\n dir={dir}\n {...navProps}\n className={cn(\"flex gap-2\", orientation === \"horizontal\" ? \"flex-col\" : \"flex-row\", className)}\n />\n );\n}\n\ninterface ScrollSpyLinkProps extends React.ComponentProps<\"a\"> {\n value: string;\n asChild?: boolean;\n}\n\nfunction ScrollSpyLink(props: ScrollSpyLinkProps) {\n const { value: linkValue, asChild, onClick, className, ...linkProps } = props;\n\n const { orientation, onScrollToSection } = useScrollSpyContext(LINK_NAME);\n const value = useStore((state) => state.value);\n const isActive = value === linkValue;\n\n const onLinkClick = React.useCallback(\n (event: React.MouseEvent<LinkElement>) => {\n event.preventDefault();\n onClick?.(event);\n onScrollToSection(linkValue);\n },\n [linkValue, onClick, onScrollToSection]\n );\n\n const LinkPrimitive = asChild ? Slot : \"a\";\n\n return (\n <LinkPrimitive\n /*\n * ⚠ Khác thượng nguồn: bản gốc chỉ đặt `data-state=\"active\"` — thuộc tính mà trình đọc màn\n * hình KHÔNG đọc, nên mục đang xem chỉ được báo bằng hình. `aria-current=\"location\"` là giá\n * trị ARIA dành cho \"vị trí hiện tại\" trong một ngữ cảnh — ở đây là mục đang xem của trang.\n * Không dùng `\"page\"`: link trỏ tới một mục TRONG trang, không phải tới một trang khác.\n */\n aria-current={isActive ? \"location\" : undefined}\n data-orientation={orientation}\n data-slot=\"scroll-spy-link\"\n data-state={isActive ? \"active\" : \"inactive\"}\n {...linkProps}\n href={asChild ? undefined : `#${linkValue}`}\n className={cn(\n \"px-3 py-1.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground data-[state=active]:bg-accent data-[state=active]:text-foreground\",\n /*\n * ⚠ Khác thượng nguồn: thêm VẠCH ACTIVE. Bản gốc báo mục đang xem chỉ bằng `bg-accent` —\n * #FBF5DC trên nền trắng là 1,09:1 (dark: 1,17:1), không đủ làm chỉ báo (WCAG 1.4.11 đòi\n * 3:1 cho thành phần phi văn bản mang nghĩa) — cộng đổi màu chữ, mà màu không được là tín\n * hiệu DUY NHẤT (1.4.1). Vạch 2px `border-primary-ink` là đúng khuôn `Tabs` biến thể\n * `default` (tabs-variants.ts): bậc `-ink` vì nó đi lên nền TRANG, và bảng tương phản cao\n * chỉ đổi được nó qua token này. Đặt ở cạnh ĐẦU (dọc) hoặc cạnh DƯỚI (ngang) theo hướng\n * xếp link; `border-s`/`rounded-e` là thuộc tính logic nên đúng cả RTL.\n */\n \"border-transparent data-[state=active]:border-primary-ink\",\n orientation === \"horizontal\" ? \"rounded-e-md border-s-2\" : \"rounded-t-md border-b-2\",\n // Vòng focus cùng khuôn `Tabs` của gói (TABS_TRIGGER_BASE).\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n className\n )}\n onClick={onLinkClick}\n />\n );\n}\n\ninterface ScrollSpyViewportProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\nfunction ScrollSpyViewport(props: ScrollSpyViewportProps) {\n const { asChild, className, ...viewportProps } = props;\n\n const { dir, orientation } = useScrollSpyContext(VIEWPORT_NAME);\n\n const ViewportPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ViewportPrimitive\n data-orientation={orientation}\n data-slot=\"scroll-spy-viewport\"\n dir={dir}\n {...viewportProps}\n className={cn(\"flex flex-1 flex-col gap-8\", className)}\n />\n );\n}\n\ninterface ScrollSpySectionProps extends React.ComponentProps<\"div\"> {\n value: string;\n asChild?: boolean;\n}\n\nfunction ScrollSpySection(props: ScrollSpySectionProps) {\n const { asChild, ref, value, ...sectionProps } = props;\n\n const { orientation, onSectionRegister, onSectionUnregister } = useScrollSpyContext(SECTION_NAME);\n const sectionRef = React.useRef<SectionElement>(null);\n const composedRef = useComposedRefs(ref, sectionRef);\n\n useIsomorphicLayoutEffect(() => {\n const element = sectionRef.current;\n if (!element || !value) return;\n\n onSectionRegister(value, element);\n\n return () => {\n onSectionUnregister(value);\n };\n }, [value, onSectionRegister, onSectionUnregister]);\n\n const SectionPrimitive = asChild ? Slot : \"div\";\n\n return (\n <SectionPrimitive\n data-orientation={orientation}\n data-slot=\"scroll-spy-section\"\n {...sectionProps}\n id={value}\n ref={composedRef}\n />\n );\n}\n\nexport {\n ScrollSpy,\n ScrollSpyLink,\n type ScrollSpyLinkProps,\n ScrollSpyNav,\n type ScrollSpyNavProps,\n type ScrollSpyProps,\n ScrollSpySection,\n type ScrollSpySectionProps,\n ScrollSpyViewport,\n type ScrollSpyViewportProps\n};\n"],"mappings":"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","names":["value"]}
1
+ {"version":3,"sources":["../../../src/components/ui/scroll-spy.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/scroll-spy) — 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 * Dùng ở Comitor: trang cài đặt dài và trang chi tiết bản ghi (các mục của một liên hệ CRM) có\n * mục lục điều hướng trong trang.\n *\n * ⚠ `orientation` giữ NGHĨA của thượng nguồn — nó nói về hướng xếp của KHUNG, không phải của danh\n * sách link: `horizontal` (mặc định) = mục lục đứng bên cạnh nội dung, link xếp DỌC; `vertical` =\n * mục lục nằm trên nội dung, link xếp NGANG.\n */\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Slot } from \"@radix-ui/react-slot\";\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\";\n\nconst ROOT_NAME = \"ScrollSpy\";\nconst NAV_NAME = \"ScrollSpyNav\";\nconst LINK_NAME = \"ScrollSpyLink\";\nconst VIEWPORT_NAME = \"ScrollSpyViewport\";\nconst SECTION_NAME = \"ScrollSpySection\";\n\ntype Direction = \"ltr\" | \"rtl\";\ntype Orientation = \"horizontal\" | \"vertical\";\n\ntype LinkElement = React.ComponentRef<typeof ScrollSpyLink>;\ntype SectionElement = React.ComponentRef<typeof ScrollSpySection>;\n\nfunction getDefaultScrollBehavior(): ScrollBehavior {\n if (typeof window === \"undefined\") return \"smooth\";\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\";\n}\n\ninterface StoreState {\n value: string;\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 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(`\\`useStore\\` 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 ScrollSpyContextValue {\n offset: number;\n scrollBehavior: ScrollBehavior | undefined;\n dir: Direction;\n orientation: Orientation;\n scrollContainer: HTMLElement | null;\n isScrollingRef: React.RefObject<boolean>;\n onSectionRegister: (id: string, element: SectionElement) => void;\n onSectionUnregister: (id: string, element: SectionElement) => void;\n onScrollToSection: (sectionId: string) => void;\n}\n\n/** Cửa vào IntersectionObserver đang sống của `ScrollSpy` — xem effect dựng observer. */\ninterface SectionObserver {\n observe: (element: Element) => void;\n unobserve: (element: Element) => void;\n}\n\nconst ScrollSpyContext = React.createContext<ScrollSpyContextValue | null>(null);\n\nfunction useScrollSpyContext(consumerName: string) {\n const context = React.useContext(ScrollSpyContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface ScrollSpyProps extends React.ComponentProps<\"div\"> {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n rootMargin?: string;\n threshold?: number | number[];\n offset?: number;\n /**\n * Kiểu cuộn khi bấm link. Không truyền thì `\"smooth\"`, hoặc `\"auto\"` nếu người dùng bật giảm\n * chuyển động (`prefers-reduced-motion`).\n */\n scrollBehavior?: ScrollBehavior;\n scrollContainer?: HTMLElement | null;\n dir?: Direction;\n orientation?: Orientation;\n asChild?: boolean;\n}\n\nfunction ScrollSpy(props: ScrollSpyProps) {\n const {\n value,\n defaultValue,\n onValueChange,\n rootMargin,\n threshold = 0.1,\n offset = 0,\n /*\n * ⚠ Khác thượng nguồn: bản gốc tính mặc định NGAY TRONG render (`scrollBehavior =\n * getDefaultScrollBehavior()` → `window.matchMedia` mỗi lượt render). Ở đây để `undefined` và\n * chỉ phân giải lúc cuộn thật — không chạm `window` khi render, và đọc đúng thiết lập giảm\n * chuyển động TẠI THỜI ĐIỂM bấm chứ không phải lúc render gần nhất.\n */\n scrollBehavior,\n scrollContainer = null,\n dir: dirProp,\n orientation = \"horizontal\",\n asChild,\n className,\n ...rootProps\n } = props;\n\n const dir = useDirection(dirProp);\n\n const stateRef = useLazyRef<StoreState>(() => ({\n value: value ?? defaultValue ?? \"\"\n }));\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const onValueChangeRef = useAsRef(onValueChange);\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: () => {\n return stateRef.current;\n },\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n stateRef.current[key] = value;\n\n if (key === \"value\" && value) {\n onValueChangeRef.current?.(value);\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n }\n };\n }, [listenersRef, stateRef, onValueChangeRef]);\n\n const sectionMapRef = React.useRef(new Map<string, Element>());\n const sectionObserverRef = React.useRef<SectionObserver | null>(null);\n const isScrollingRef = React.useRef(false);\n const rafIdRef = React.useRef<number | null>(null);\n const isMountedRef = React.useRef(false);\n const scrollTimeoutRef = React.useRef<number | null>(null);\n\n /*\n * ⚠ Khác thượng nguồn (3.1.0): đăng ký/huỷ một mục là observe/unobserve NGAY trên observer đang\n * sống (nếu đã có) — xem effect dựng observer bên dưới. Bản gốc chỉ ghi vào `sectionMap`.\n */\n const onSectionRegister = React.useCallback((id: string, element: SectionElement) => {\n sectionMapRef.current.set(id, element);\n sectionObserverRef.current?.observe(element);\n }, []);\n\n const onSectionUnregister = React.useCallback((id: string, element: SectionElement) => {\n const sectionMap = sectionMapRef.current;\n // Chỉ gỡ khoá khi nó còn trỏ đúng phần tử này: hai mục trùng `value` (lỗi của app — id trùng\n // trên trang) thì mục rời đi không kéo mục còn lại ra khỏi bảng.\n if (sectionMap.get(id) === element) sectionMap.delete(id);\n sectionObserverRef.current?.unobserve(element);\n }, []);\n\n const onScrollToSection = React.useCallback(\n (sectionId: string) => {\n /*\n * ⚠ Khác thượng nguồn: `CSS.escape` quanh id. Bản gốc ghép thẳng `#${sectionId}` vào\n * `querySelector`, nên id bắt đầu bằng chữ số (\"2024-hop-dong\") hay chứa ký tự đặc biệt\n * (id của `useId()` như \":r1:\") làm nó THROW `SyntaxError` ngay khi bấm link.\n */\n const section = scrollContainer\n ? scrollContainer.querySelector(`#${CSS.escape(sectionId)}`)\n : document.getElementById(sectionId);\n\n if (!section) {\n store.setState(\"value\", sectionId);\n return;\n }\n\n // Bật cờ để observer không ghi đè giá trị trong lúc đang cuộn theo lệnh.\n isScrollingRef.current = true;\n store.setState(\"value\", sectionId);\n\n const behavior = scrollBehavior ?? getDefaultScrollBehavior();\n\n if (scrollContainer) {\n const containerRect = scrollContainer.getBoundingClientRect();\n const sectionRect = section.getBoundingClientRect();\n const scrollTop = scrollContainer.scrollTop;\n const offsetPosition = sectionRect.top - containerRect.top + scrollTop - offset;\n\n scrollContainer.scrollTo({\n top: offsetPosition,\n behavior\n });\n } else {\n const sectionPosition = section.getBoundingClientRect().top;\n const offsetPosition = sectionPosition + window.scrollY - offset;\n\n window.scrollTo({\n top: offsetPosition,\n behavior\n });\n }\n\n if (scrollTimeoutRef.current !== null) {\n clearTimeout(scrollTimeoutRef.current);\n }\n\n scrollTimeoutRef.current = window.setTimeout(() => {\n isScrollingRef.current = false;\n }, 500);\n },\n [scrollContainer, offset, scrollBehavior, store]\n );\n\n /*\n * ⚠ Khác thượng nguồn: chỉ cuộn theo lệnh khi `value` đổi TỪ BÊN NGOÀI. Bản gốc cuộn mỗi khi\n * effect chạy lại sau lần đầu, với hai hệ quả đã đo trên trình duyệt:\n * · StrictMode chạy effect hai lần lúc mount → lần hai cuộn luôn CẢ TRANG tới mục (scrollY\n * 0 → ~5050) vì `scrollContainer` của app lúc đó còn `null`. Next dev bật StrictMode sẵn.\n * · Chế độ controlled tự kéo giật: observer đặt giá trị → `onValueChange` → app trả về prop\n * `value` → effect cuộn tới ĐẦU mục đó, ngay giữa lúc người dùng đang cuộn.\n * Luật mới: lúc mount không cuộn (đúng ý nhánh mount của bản gốc); về sau, `value` trùng với giá\n * trị store đang giữ nghĩa là nó chỉ là tiếng vọng của chính observer/link → không cuộn.\n * `defaultValue` đã vào store từ lúc khởi tạo (`stateRef`), không cần đồng bộ thêm.\n */\n const prevValuePropRef = React.useRef<string | undefined>(undefined);\n const onScrollToSectionRef = useAsRef(onScrollToSection);\n\n useIsomorphicLayoutEffect(() => {\n const previous = prevValuePropRef.current;\n prevValuePropRef.current = value;\n if (value === undefined || value === previous) return;\n\n if (previous === undefined || !isMountedRef.current) {\n isMountedRef.current = true;\n store.setState(\"value\", value);\n return;\n }\n\n if (value === store.getState().value) return;\n onScrollToSectionRef.current(value);\n }, [value, store, onScrollToSectionRef]);\n\n /*\n * ⚠ Khác thượng nguồn (3.1.0): observer theo dõi mục THEO LÚC chúng đăng ký/huỷ. Bản gốc chỉ\n * `observe` những mục có mặt lúc effect này chạy, mà effect chỉ chạy lại khi `offset` /\n * `rootMargin` / `threshold` / `scrollContainer` đổi — nên mục mount SAU (dữ liệu tải chậm: phần\n * Deals của một liên hệ CRM) không bao giờ được theo dõi, và spy mount trước mọi mục thì không\n * dựng observer nào. Nay effect đặt vào `sectionObserverRef` một cửa `observe`/`unobserve`, và\n * `onSectionRegister`/`onSectionUnregister` gọi thẳng cửa đó: mục đến/đi KHÔNG dựng lại observer.\n * Observer vẫn chỉ dựng lại khi bốn tuỳ chọn trên đổi (chúng không đổi được trên một observer đã\n * có), và vẫn chỉ được TẠO khi có mục đầu tiên — spy chưa có mục nào không tạo observer, như bản\n * gốc (môi trường thiếu API này, vd jsdom, không đổi hành vi).\n *\n * Không cần cờ nào để biết \"observer đã có chưa\", vì thứ tự của React lo phần đó: layout effect\n * của CON chạy trước của CHA, và mọi cleanup của một lần commit chạy trước mọi effect. Mục đăng ký\n * trong CÙNG lần commit mà effect này chạy (vd observer dựng lại vì `scrollContainer` vừa có) gặp\n * cửa còn `null`, chỉ vào `sectionMap`, rồi được observe ở vòng lặp dưới; mục đăng ký ở commit sau\n * đi thẳng vào observer đang sống. StrictMode (gỡ cả cây: CHA trước, rồi dựng lại: CON trước) đi\n * đúng hai nhánh đó.\n *\n * Luật chọn mục của bản gốc giữ nguyên: trong MỘT lần báo, mục vừa vào dải theo dõi và nằm cao\n * nhất thành mục đang xem. Một mục mới hiện ra ngay trong dải cũng là \"vừa vào dải\" — nó thành mục\n * đang xem, như khi người dùng cuộn tới nó. Mục hiện ra ngoài dải thì không đổi gì.\n */\n useIsomorphicLayoutEffect(() => {\n const sectionMap = sectionMapRef.current;\n const observerRootMargin = rootMargin ?? `${-offset}px 0px -70% 0px`;\n let observer: IntersectionObserver | null = null;\n\n const onIntersect = (entries: IntersectionObserverEntry[]) => {\n if (isScrollingRef.current) return;\n\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n }\n\n rafIdRef.current = requestAnimationFrame(() => {\n const intersecting = entries.filter((entry) => entry.isIntersecting);\n\n if (intersecting.length === 0) return;\n\n const topmost = intersecting.reduce((prev, curr) => {\n return curr.boundingClientRect.top < prev.boundingClientRect.top ? curr : prev;\n });\n\n const id = topmost.target.id;\n if (id && sectionMap.has(id)) {\n store.setState(\"value\", id);\n }\n });\n };\n\n const sectionObserver: SectionObserver = {\n observe: (element) => {\n observer ??= new IntersectionObserver(onIntersect, {\n root: scrollContainer,\n rootMargin: observerRootMargin,\n threshold\n });\n observer.observe(element);\n },\n unobserve: (element) => {\n observer?.unobserve(element);\n }\n };\n\n sectionObserverRef.current = sectionObserver;\n\n for (const element of sectionMap.values()) {\n sectionObserver.observe(element);\n }\n\n return () => {\n sectionObserverRef.current = null;\n observer?.disconnect();\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n }\n };\n }, [offset, rootMargin, threshold, scrollContainer]);\n\n /*\n * ⚠ Khác thượng nguồn (3.1.0): hẹn giờ tắt cờ \"đang cuộn theo lệnh\" (`onScrollToSection`) chỉ bị\n * huỷ khi spy rời DOM. Bản gốc huỷ nó trong cleanup của observer — tức cả khi observer DỰNG LẠI —\n * mà không tắt cờ: đổi `offset` / `scrollContainer` giữa lúc đang cuộn theo lệnh là cờ kẹt ở\n * `true`, observer bỏ qua mọi lần báo, và spy đứng hình tới lần bấm link kế tiếp (đã đo: bấm link\n * rồi đổi `offset` ngay, cuộn tay sau đó không đổi mục đang xem nữa).\n */\n React.useEffect(() => {\n return () => {\n if (scrollTimeoutRef.current !== null) {\n clearTimeout(scrollTimeoutRef.current);\n }\n };\n }, []);\n\n const contextValue = React.useMemo<ScrollSpyContextValue>(\n () => ({\n dir,\n orientation,\n offset,\n scrollBehavior,\n scrollContainer,\n isScrollingRef,\n onSectionRegister,\n onSectionUnregister,\n onScrollToSection\n }),\n [\n dir,\n orientation,\n offset,\n scrollBehavior,\n scrollContainer,\n onSectionRegister,\n onSectionUnregister,\n onScrollToSection\n ]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <ScrollSpyContext.Provider value={contextValue}>\n <RootPrimitive\n data-orientation={orientation}\n data-slot=\"scroll-spy\"\n dir={dir}\n {...rootProps}\n className={cn(\"flex\", orientation === \"horizontal\" ? \"flex-row\" : \"flex-col\", className)}\n />\n </ScrollSpyContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface ScrollSpyNavProps extends React.ComponentProps<\"nav\"> {\n asChild?: boolean;\n}\n\nfunction ScrollSpyNav(props: ScrollSpyNavProps) {\n const { asChild, className, ...navProps } = props;\n\n const { dir, orientation } = useScrollSpyContext(NAV_NAME);\n const t = useComitorMessages(\"scrollSpy\");\n\n const NavPrimitive = asChild ? Slot : \"nav\";\n\n return (\n <NavPrimitive\n /*\n * ⚠ Khác thượng nguồn: `<nav>` có tên mặc định (khoá `navLabel` của namespace `scrollSpy`,\n * theo `ComitorLocaleProvider`). Trong khung app Comitor đã có ít nhất MỘT landmark\n * `navigation` (sidebar), nên một `<nav>` thứ hai không tên là hai landmark trùng loại không\n * phân biệt được trong danh sách landmark của trình đọc màn hình. Ghi đè bằng chính prop\n * `aria-label` (cùng khuôn `Breadcrumb`/`Pagination` của gói).\n */\n aria-label={t.navLabel}\n data-orientation={orientation}\n data-slot=\"scroll-spy-nav\"\n dir={dir}\n {...navProps}\n className={cn(\"flex gap-2\", orientation === \"horizontal\" ? \"flex-col\" : \"flex-row\", className)}\n />\n );\n}\n\ninterface ScrollSpyLinkProps extends React.ComponentProps<\"a\"> {\n value: string;\n asChild?: boolean;\n}\n\nfunction ScrollSpyLink(props: ScrollSpyLinkProps) {\n const { value: linkValue, asChild, onClick, className, ...linkProps } = props;\n\n const { orientation, onScrollToSection } = useScrollSpyContext(LINK_NAME);\n const value = useStore((state) => state.value);\n const isActive = value === linkValue;\n\n const onLinkClick = React.useCallback(\n (event: React.MouseEvent<LinkElement>) => {\n event.preventDefault();\n onClick?.(event);\n onScrollToSection(linkValue);\n },\n [linkValue, onClick, onScrollToSection]\n );\n\n const LinkPrimitive = asChild ? Slot : \"a\";\n\n return (\n <LinkPrimitive\n /*\n * ⚠ Khác thượng nguồn: bản gốc chỉ đặt `data-state=\"active\"` — thuộc tính mà trình đọc màn\n * hình KHÔNG đọc, nên mục đang xem chỉ được báo bằng hình. `aria-current=\"location\"` là giá\n * trị ARIA dành cho \"vị trí hiện tại\" trong một ngữ cảnh — ở đây là mục đang xem của trang.\n * Không dùng `\"page\"`: link trỏ tới một mục TRONG trang, không phải tới một trang khác.\n */\n aria-current={isActive ? \"location\" : undefined}\n data-orientation={orientation}\n data-slot=\"scroll-spy-link\"\n data-state={isActive ? \"active\" : \"inactive\"}\n {...linkProps}\n href={asChild ? undefined : `#${linkValue}`}\n className={cn(\n \"px-3 py-1.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground data-[state=active]:bg-accent data-[state=active]:text-foreground\",\n /*\n * ⚠ Khác thượng nguồn: thêm VẠCH ACTIVE. Bản gốc báo mục đang xem chỉ bằng `bg-accent` —\n * #FBF5DC trên nền trắng là 1,09:1 (dark: 1,17:1), không đủ làm chỉ báo (WCAG 1.4.11 đòi\n * 3:1 cho thành phần phi văn bản mang nghĩa) — cộng đổi màu chữ, mà màu không được là tín\n * hiệu DUY NHẤT (1.4.1). Vạch 2px `border-primary-ink` là đúng khuôn `Tabs` biến thể\n * `default` (tabs-variants.ts): bậc `-ink` vì nó đi lên nền TRANG, và bảng tương phản cao\n * chỉ đổi được nó qua token này. Đặt ở cạnh ĐẦU (dọc) hoặc cạnh DƯỚI (ngang) theo hướng\n * xếp link; `border-s`/`rounded-e` là thuộc tính logic nên đúng cả RTL.\n */\n \"border-transparent data-[state=active]:border-primary-ink\",\n orientation === \"horizontal\" ? \"rounded-e-md border-s-2\" : \"rounded-t-md border-b-2\",\n // Vòng focus cùng khuôn `Tabs` của gói (TABS_TRIGGER_BASE).\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n className\n )}\n onClick={onLinkClick}\n />\n );\n}\n\ninterface ScrollSpyViewportProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\nfunction ScrollSpyViewport(props: ScrollSpyViewportProps) {\n const { asChild, className, ...viewportProps } = props;\n\n const { dir, orientation } = useScrollSpyContext(VIEWPORT_NAME);\n\n const ViewportPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ViewportPrimitive\n data-orientation={orientation}\n data-slot=\"scroll-spy-viewport\"\n dir={dir}\n {...viewportProps}\n className={cn(\"flex flex-1 flex-col gap-8\", className)}\n />\n );\n}\n\ninterface ScrollSpySectionProps extends React.ComponentProps<\"div\"> {\n value: string;\n asChild?: boolean;\n}\n\nfunction ScrollSpySection(props: ScrollSpySectionProps) {\n const { asChild, ref, value, ...sectionProps } = props;\n\n const { orientation, onSectionRegister, onSectionUnregister } = useScrollSpyContext(SECTION_NAME);\n /*\n * ⚠ Khác thượng nguồn (3.1.0): phần tử giữ trong STATE (ref gọi setter), không trong ref object, để\n * đăng ký lại khi NÚT DOM đổi mà `value` thì không. Ca thật: `asChild` quanh một nội dung tải chậm\n * (`{loaded ? <section>…</section> : <Skeleton />}`) — đổi loại phần tử là React thay hẳn nút, và\n * bản gốc (effect chỉ theo `value`) cứ quan sát nút skeleton đã rời DOM: mục ấy không bao giờ sáng\n * (đã đo trên trình duyệt). Giá phải trả: mỗi mục render thêm MỘT lượt lúc mount (và mỗi lần nút\n * đổi). Cây con không render lại — `children` vẫn là cùng tham chiếu phần tử nên React bỏ qua; riêng\n * `asChild` thì phần tử con do `Slot` nhân bản render thêm lượt đó cùng mục.\n */\n const [element, setElement] = React.useState<SectionElement | null>(null);\n const composedRef = useComposedRefs(ref, setElement);\n\n useIsomorphicLayoutEffect(() => {\n if (!element || !value) return;\n\n onSectionRegister(value, element);\n\n return () => {\n onSectionUnregister(value, element);\n };\n }, [element, value, onSectionRegister, onSectionUnregister]);\n\n const SectionPrimitive = asChild ? Slot : \"div\";\n\n return (\n <SectionPrimitive\n data-orientation={orientation}\n data-slot=\"scroll-spy-section\"\n {...sectionProps}\n id={value}\n ref={composedRef}\n />\n );\n}\n\nexport {\n ScrollSpy,\n ScrollSpyLink,\n type ScrollSpyLinkProps,\n ScrollSpyNav,\n type ScrollSpyNavProps,\n type ScrollSpyProps,\n ScrollSpySection,\n type ScrollSpySectionProps,\n ScrollSpyViewport,\n type ScrollSpyViewportProps\n};\n"],"mappings":"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","names":["value"]}