@comitor/ui 1.11.0 → 2.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 (176) hide show
  1. package/LICENSE +35 -0
  2. package/README.md +23 -7
  3. package/dist/components/ui/action-bar-constants.d.ts +31 -0
  4. package/dist/components/ui/action-bar-constants.js +9 -0
  5. package/dist/components/ui/action-bar-constants.js.map +1 -0
  6. package/dist/components/ui/action-bar.d.ts +67 -0
  7. package/dist/components/ui/action-bar.js +522 -0
  8. package/dist/components/ui/action-bar.js.map +1 -0
  9. package/dist/components/ui/badge-overflow.d.ts +30 -0
  10. package/dist/components/ui/badge-overflow.js +179 -0
  11. package/dist/components/ui/badge-overflow.js.map +1 -0
  12. package/dist/components/ui/banner.d.ts +79 -0
  13. package/dist/components/ui/banner.js +518 -0
  14. package/dist/components/ui/banner.js.map +1 -0
  15. package/dist/components/ui/circular-progress.d.ts +50 -0
  16. package/dist/components/ui/circular-progress.js +266 -0
  17. package/dist/components/ui/circular-progress.js.map +1 -0
  18. package/dist/components/ui/cropper-constants.d.ts +34 -0
  19. package/dist/components/ui/cropper-constants.js +10 -0
  20. package/dist/components/ui/cropper-constants.js.map +1 -0
  21. package/dist/components/ui/cropper.d.ts +106 -0
  22. package/dist/components/ui/cropper.js +1269 -0
  23. package/dist/components/ui/cropper.js.map +1 -0
  24. package/dist/components/ui/drawer.d.ts +1 -1
  25. package/dist/components/ui/drawer.js +2 -2
  26. package/dist/components/ui/drawer.js.map +1 -1
  27. package/dist/components/ui/kanban-constants.d.ts +61 -0
  28. package/dist/components/ui/kanban-constants.js +21 -0
  29. package/dist/components/ui/kanban-constants.js.map +1 -0
  30. package/dist/components/ui/kanban.d.ts +72 -0
  31. package/dist/components/ui/kanban.js +787 -0
  32. package/dist/components/ui/kanban.js.map +1 -0
  33. package/dist/components/ui/key-value-constants.d.ts +33 -0
  34. package/dist/components/ui/key-value-constants.js +11 -0
  35. package/dist/components/ui/key-value-constants.js.map +1 -0
  36. package/dist/components/ui/key-value.d.ts +96 -0
  37. package/dist/components/ui/key-value.js +641 -0
  38. package/dist/components/ui/key-value.js.map +1 -0
  39. package/dist/components/ui/mask-input-constants.d.ts +99 -0
  40. package/dist/components/ui/mask-input-constants.js +601 -0
  41. package/dist/components/ui/mask-input-constants.js.map +1 -0
  42. package/dist/components/ui/mask-input.d.ts +36 -0
  43. package/dist/components/ui/mask-input.js +558 -0
  44. package/dist/components/ui/mask-input.js.map +1 -0
  45. package/dist/components/ui/mention.d.ts +31 -0
  46. package/dist/components/ui/mention.js +128 -0
  47. package/dist/components/ui/mention.js.map +1 -0
  48. package/dist/components/ui/phone-input-constants.d.ts +54 -0
  49. package/dist/components/ui/phone-input-constants.js +9 -0
  50. package/dist/components/ui/phone-input-constants.js.map +1 -0
  51. package/dist/components/ui/phone-input.d.ts +85 -0
  52. package/dist/components/ui/phone-input.js +743 -0
  53. package/dist/components/ui/phone-input.js.map +1 -0
  54. package/dist/components/ui/rating.d.ts +56 -0
  55. package/dist/components/ui/rating.js +646 -0
  56. package/dist/components/ui/rating.js.map +1 -0
  57. package/dist/components/ui/responsive-dialog.d.ts +35 -0
  58. package/dist/components/ui/responsive-dialog.js +193 -0
  59. package/dist/components/ui/responsive-dialog.js.map +1 -0
  60. package/dist/components/ui/scroll-spy.d.ts +42 -0
  61. package/dist/components/ui/scroll-spy.js +334 -0
  62. package/dist/components/ui/scroll-spy.js.map +1 -0
  63. package/dist/components/ui/stepper-constants.d.ts +29 -0
  64. package/dist/components/ui/stepper-constants.js +9 -0
  65. package/dist/components/ui/stepper-constants.js.map +1 -0
  66. package/dist/components/ui/stepper.d.ts +80 -0
  67. package/dist/components/ui/stepper.js +902 -0
  68. package/dist/components/ui/stepper.js.map +1 -0
  69. package/dist/components/ui/tags-input.d.ts +41 -0
  70. package/dist/components/ui/tags-input.js +127 -0
  71. package/dist/components/ui/tags-input.js.map +1 -0
  72. package/dist/components/ui/time-picker-constants.d.ts +48 -0
  73. package/dist/components/ui/time-picker-constants.js +14 -0
  74. package/dist/components/ui/time-picker-constants.js.map +1 -0
  75. package/dist/components/ui/time-picker.d.ts +115 -0
  76. package/dist/components/ui/time-picker.js +1620 -0
  77. package/dist/components/ui/time-picker.js.map +1 -0
  78. package/dist/components/ui/timeline.d.ts +32 -0
  79. package/dist/components/ui/timeline.js +559 -0
  80. package/dist/components/ui/timeline.js.map +1 -0
  81. package/dist/components/ui/tour-constants.d.ts +39 -0
  82. package/dist/components/ui/tour-constants.js +12 -0
  83. package/dist/components/ui/tour-constants.js.map +1 -0
  84. package/dist/components/ui/tour.d.ts +124 -0
  85. package/dist/components/ui/tour.js +1207 -0
  86. package/dist/components/ui/tour.js.map +1 -0
  87. package/dist/data-grid/data-grid-cell-variants.js +10 -6
  88. package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
  89. package/dist/data-grid/data-grid-cell-wrapper.js +1 -1
  90. package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -1
  91. package/dist/data-grid/data-grid-column-header.js +4 -2
  92. package/dist/data-grid/data-grid-column-header.js.map +1 -1
  93. package/dist/data-grid/data-grid-context-menu.js +5 -4
  94. package/dist/data-grid/data-grid-context-menu.js.map +1 -1
  95. package/dist/data-grid/data-grid-filter-menu.d.ts +12 -1
  96. package/dist/data-grid/data-grid-filter-menu.js +28 -17
  97. package/dist/data-grid/data-grid-filter-menu.js.map +1 -1
  98. package/dist/data-grid/data-grid-keyboard-shortcuts.d.ts +12 -1
  99. package/dist/data-grid/data-grid-keyboard-shortcuts.js +7 -5
  100. package/dist/data-grid/data-grid-keyboard-shortcuts.js.map +1 -1
  101. package/dist/data-grid/data-grid-locale.d.ts +24 -0
  102. package/dist/data-grid/data-grid-locale.js +25 -0
  103. package/dist/data-grid/data-grid-locale.js.map +1 -0
  104. package/dist/data-grid/data-grid-paste-dialog.js +3 -2
  105. package/dist/data-grid/data-grid-paste-dialog.js.map +1 -1
  106. package/dist/data-grid/data-grid-row-height-menu.d.ts +11 -1
  107. package/dist/data-grid/data-grid-row-height-menu.js +25 -28
  108. package/dist/data-grid/data-grid-row-height-menu.js.map +1 -1
  109. package/dist/data-grid/data-grid-row.js +1 -1
  110. package/dist/data-grid/data-grid-row.js.map +1 -1
  111. package/dist/data-grid/data-grid-search.js +6 -5
  112. package/dist/data-grid/data-grid-search.js.map +1 -1
  113. package/dist/data-grid/data-grid-select-column.js +3 -1
  114. package/dist/data-grid/data-grid-select-column.js.map +1 -1
  115. package/dist/data-grid/data-grid-sort-menu.d.ts +12 -1
  116. package/dist/data-grid/data-grid-sort-menu.js +25 -13
  117. package/dist/data-grid/data-grid-sort-menu.js.map +1 -1
  118. package/dist/data-grid/data-grid-view-menu.d.ts +12 -1
  119. package/dist/data-grid/data-grid-view-menu.js +12 -4
  120. package/dist/data-grid/data-grid-view-menu.js.map +1 -1
  121. package/dist/data-grid/data-grid.d.ts +14 -2
  122. package/dist/data-grid/data-grid.js +7 -4
  123. package/dist/data-grid/data-grid.js.map +1 -1
  124. package/dist/data-grid/filters.d.ts +17 -21
  125. package/dist/data-grid/filters.js +73 -52
  126. package/dist/data-grid/filters.js.map +1 -1
  127. package/dist/data-grid/index.d.ts +4 -1
  128. package/dist/data-grid/index.js +20 -2
  129. package/dist/data-grid/index.js.map +1 -1
  130. package/dist/data-grid/messages-en.d.ts +294 -0
  131. package/dist/data-grid/messages-en.js +279 -0
  132. package/dist/data-grid/messages-en.js.map +1 -0
  133. package/dist/data-grid/messages-vi.d.ts +12 -0
  134. package/dist/data-grid/messages-vi.js +279 -0
  135. package/dist/data-grid/messages-vi.js.map +1 -0
  136. package/dist/data-grid/messages.d.ts +549 -262
  137. package/dist/data-grid/messages.js +16 -275
  138. package/dist/data-grid/messages.js.map +1 -1
  139. package/dist/data-grid/sortable.js +1 -1
  140. package/dist/data-grid/sortable.js.map +1 -1
  141. package/dist/data-grid/use-data-grid-undo-redo.d.ts +13 -1
  142. package/dist/data-grid/use-data-grid-undo-redo.js +13 -10
  143. package/dist/data-grid/use-data-grid-undo-redo.js.map +1 -1
  144. package/dist/data-grid/use-data-grid.d.ts +281 -1
  145. package/dist/data-grid/use-data-grid.js +24 -19
  146. package/dist/data-grid/use-data-grid.js.map +1 -1
  147. package/dist/data-grid/utils.d.ts +9 -1
  148. package/dist/data-grid/utils.js +3 -2
  149. package/dist/data-grid/utils.js.map +1 -1
  150. package/dist/index.d.ts +31 -0
  151. package/dist/index.js +42 -0
  152. package/dist/index.js.map +1 -1
  153. package/dist/lib/compose-refs.js.map +1 -0
  154. package/dist/lib/use-as-ref.js.map +1 -0
  155. package/dist/lib/use-is-mobile.d.ts +10 -0
  156. package/dist/lib/use-is-mobile.js +21 -0
  157. package/dist/lib/use-is-mobile.js.map +1 -0
  158. package/dist/lib/use-isomorphic-layout-effect.js.map +1 -0
  159. package/dist/lib/use-lazy-ref.js.map +1 -0
  160. package/dist/lib/visually-hidden-input.d.ts +12 -0
  161. package/dist/lib/visually-hidden-input.js +105 -0
  162. package/dist/lib/visually-hidden-input.js.map +1 -0
  163. package/package.json +5 -1
  164. package/styles.css +19 -0
  165. package/dist/data-grid/compose-refs.js.map +0 -1
  166. package/dist/data-grid/use-as-ref.js.map +0 -1
  167. package/dist/data-grid/use-isomorphic-layout-effect.js.map +0 -1
  168. package/dist/data-grid/use-lazy-ref.js.map +0 -1
  169. /package/dist/{data-grid → lib}/compose-refs.d.ts +0 -0
  170. /package/dist/{data-grid → lib}/compose-refs.js +0 -0
  171. /package/dist/{data-grid → lib}/use-as-ref.d.ts +0 -0
  172. /package/dist/{data-grid → lib}/use-as-ref.js +0 -0
  173. /package/dist/{data-grid → lib}/use-isomorphic-layout-effect.d.ts +0 -0
  174. /package/dist/{data-grid → lib}/use-isomorphic-layout-effect.js +0 -0
  175. /package/dist/{data-grid → lib}/use-lazy-ref.d.ts +0 -0
  176. /package/dist/{data-grid → lib}/use-lazy-ref.js +0 -0
@@ -0,0 +1,128 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import * as MentionPrimitive from "@diceui/mention";
4
+ import { useDirection } from "@radix-ui/react-direction";
5
+ import * as React from "react";
6
+ import { cn } from "../../lib/cn.js";
7
+ const MentionListIdContext = React.createContext(void 0);
8
+ function Mention({ className, dir: dirProp, ...props }) {
9
+ const dir = useDirection(dirProp);
10
+ const listId = React.useId();
11
+ return /* @__PURE__ */ jsx(MentionListIdContext.Provider, { value: listId, children: /* @__PURE__ */ jsx(
12
+ MentionPrimitive.Root,
13
+ {
14
+ "data-slot": "mention",
15
+ dir,
16
+ className: cn(
17
+ /*
18
+ * Khối `@Tên` đã chèn. Gói vẽ nó bằng một lớp phủ (`MentionHighlighter`) định vị TUYỆT
19
+ * ĐỐI nằm ĐÈ LÊN ô nhập: chữ thường của lớp phủ trong suốt để lộ chữ của ô bên dưới,
20
+ * chỉ đoạn `[data-tag]` là có nền.
21
+ *
22
+ * ⚠ Khác thượng nguồn: bản gốc tô `bg-blue-200 text-blue-950` / `dark:bg-blue-800
23
+ * dark:text-blue-50` (bảng màu mặc định của Tailwind). Đổi sang cặp tonal của gói
24
+ * (`info` = teal — bậc "xanh" của Comitor), và CHỮ là `text-foreground` chứ không phải
25
+ * `text-info-ink`: nền tint `/15` trong suốt nên chữ của ô nhập vẫn lộ ra dưới khối,
26
+ * chữ khối vẽ đè đúng chỗ đó — hai lớp chữ phải CÙNG MÀU, lệch màu là thành viền răng
27
+ * cưa quanh từng nét. (Bản gốc cũng chọn chữ gần như trùng màu chữ thường ở cả hai theme.)
28
+ * Khối không chỉ nói bằng màu: nó luôn mang ký tự kích hoạt `@` ở đầu.
29
+ * chữ ⇄ khối: 15,69:1 (light, trên nền trắng) · 15,15:1 (dark) · tệ nhất 13,44:1
30
+ * (dark tương phản cao, `--teal` #2DD4BF). Khối ⇄ nền trang 1,21:1 — cố ý nhạt.
31
+ */
32
+ "**:data-tag:rounded **:data-tag:bg-info/15 **:data-tag:py-px **:data-tag:text-foreground",
33
+ className
34
+ ),
35
+ ...props
36
+ }
37
+ ) });
38
+ }
39
+ function MentionLabel({ className, ...props }) {
40
+ return /* @__PURE__ */ jsx(
41
+ MentionPrimitive.Label,
42
+ {
43
+ "data-slot": "mention-label",
44
+ className: cn("px-0.5 py-1.5 text-sm font-semibold", className),
45
+ ...props
46
+ }
47
+ );
48
+ }
49
+ function MentionInput({ className, ...props }) {
50
+ const listId = React.useContext(MentionListIdContext);
51
+ return /* @__PURE__ */ jsx(
52
+ MentionPrimitive.Input,
53
+ {
54
+ "data-slot": "mention-input",
55
+ "aria-controls": listId,
56
+ className: cn(
57
+ /*
58
+ * Khuôn viền/focus của `Input`: `border-input` lúc nghỉ, `--control-edge-strong` khi rê,
59
+ * `--primary-ink` + `ring-2 ring/50` khi focus. Nền theo `Textarea` (ô soạn tin thường là
60
+ * `asChild` + `<textarea>`): trong suốt, ở dark tô `--input-fill` — không `bg-input/30`,
61
+ * xem chú thích đầu textarea.tsx.
62
+ * ⚠ Khác thượng nguồn: `focus-visible:ring-1 ring-ring` → khuôn focus của `Input`; bỏ
63
+ * `shadow-xs` (bóng của gói chỉ đi qua `--elevation-*`, `Input` không có bóng).
64
+ */
65
+ "flex w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm text-foreground transition-colors duration-150 ease-out placeholder:text-muted-foreground hover:border-control-edge-strong focus:border-primary-ink focus:outline-none focus:ring-2 focus:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input-fill",
66
+ className
67
+ ),
68
+ ...props
69
+ }
70
+ );
71
+ }
72
+ function MentionContent({
73
+ className,
74
+ children,
75
+ "aria-label": ariaLabel = "Danh s\xE1ch g\u1EE3i \xFD",
76
+ ...props
77
+ }) {
78
+ const listId = React.useContext(MentionListIdContext);
79
+ return /* @__PURE__ */ jsx(MentionPrimitive.Portal, { children: /* @__PURE__ */ jsx(
80
+ MentionPrimitive.Content,
81
+ {
82
+ "data-slot": "mention-content",
83
+ id: listId,
84
+ "aria-label": ariaLabel,
85
+ className: cn(
86
+ /*
87
+ * Mặt nổi cùng bộ với `PopoverContent`/`Command`: `bg-popover text-popover-foreground`,
88
+ * bóng `shadow-overlay` (đổi theo theme qua `--elevation-*`).
89
+ * ⚠ Khác thượng nguồn: `shadow-md` → `shadow-overlay`; thêm `origin-(--dice-transform-origin)`
90
+ * — biến gói headless tính sẵn theo cạnh bám, để hiệu ứng `zoom-in-95` nở ra TỪ phía con
91
+ * trỏ như `PopoverContent` (bản gốc nở từ tâm).
92
+ */
93
+ "relative z-50 min-w-32 origin-(--dice-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-overlay data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
94
+ className
95
+ ),
96
+ ...props,
97
+ children
98
+ }
99
+ ) });
100
+ }
101
+ function MentionItem({ className, children, ...props }) {
102
+ return /* @__PURE__ */ jsx(
103
+ MentionPrimitive.Item,
104
+ {
105
+ "data-slot": "mention-item",
106
+ className: cn(
107
+ /*
108
+ * ⚠ Khác thượng nguồn: bộ lớp của `CommandItem` (mục đang sáng `bg-accent`/`text-accent-
109
+ * foreground`, khoảng đệm theo trục mật độ `--menu-item-py`, icon con mặc định
110
+ * `text-muted-foreground` cỡ 4) — chỉ đổi thuộc tính trạng thái sang dạng của gói headless
111
+ * (`data-highlighted` / `data-disabled` là thuộc tính CÓ MẶT, không phải `="true"`).
112
+ */
113
+ "relative mt-1 flex w-full cursor-default items-center gap-2 rounded-sm px-2 py-(--menu-item-py) text-sm outline-hidden select-none first:mt-0 data-disabled:pointer-events-none data-disabled:opacity-50 data-highlighted:bg-accent data-highlighted:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
114
+ className
115
+ ),
116
+ ...props,
117
+ children
118
+ }
119
+ );
120
+ }
121
+ export {
122
+ Mention,
123
+ MentionContent,
124
+ MentionInput,
125
+ MentionItem,
126
+ MentionLabel
127
+ };
128
+ //# sourceMappingURL=mention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/mention.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/mention) — 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 * as MentionPrimitive from \"@diceui/mention\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\n\n/*\n * ⚠ Khác thượng nguồn: context RIÊNG của lớp bọc, chỉ mang một id — xem chú thích ở `MentionInput`.\n */\nconst MentionListIdContext = React.createContext<string | undefined>(undefined);\n\n/**\n * Mention — ô nhập có gợi ý `@nhắc tên`: gõ ký tự kích hoạt (mặc định `@`) là mở danh sách, chọn\n * một mục thì chèn `@Tên` vào ô và đánh dấu nó thành một khối (xoá là xoá cả khối).\n * Dùng cho ô soạn tin của Chat và bình luận trong task.\n *\n * Phần lõi (dò ký tự kích hoạt, lọc, điều hướng bàn phím, định vị danh sách theo con trỏ) là gói\n * headless `@diceui/mention`; file này chỉ phủ style theo token của Comitor.\n */\ntype MentionProps = React.ComponentProps<typeof MentionPrimitive.Root>;\n\nfunction Mention({ className, dir: dirProp, ...props }: MentionProps) {\n /*\n * ⚠ Khác thượng nguồn: `@diceui/shared` có `useDirection` RIÊNG, đọc một `DirectionContext` mà\n * gói không xuất ra — nên `DirectionProvider` của Radix (nguồn hướng chữ của mọi component khác\n * trong gói) không tới được nó. Đọc hướng từ Radix rồi truyền xuống bằng prop `dir`.\n */\n const dir = useDirection(dirProp);\n const listId = React.useId();\n\n return (\n <MentionListIdContext.Provider value={listId}>\n <MentionPrimitive.Root\n data-slot=\"mention\"\n dir={dir}\n className={cn(\n /*\n * Khối `@Tên` đã chèn. Gói vẽ nó bằng một lớp phủ (`MentionHighlighter`) định vị TUYỆT\n * ĐỐI nằm ĐÈ LÊN ô nhập: chữ thường của lớp phủ trong suốt để lộ chữ của ô bên dưới,\n * chỉ đoạn `[data-tag]` là có nền.\n *\n * ⚠ Khác thượng nguồn: bản gốc tô `bg-blue-200 text-blue-950` / `dark:bg-blue-800\n * dark:text-blue-50` (bảng màu mặc định của Tailwind). Đổi sang cặp tonal của gói\n * (`info` = teal — bậc \"xanh\" của Comitor), và CHỮ là `text-foreground` chứ không phải\n * `text-info-ink`: nền tint `/15` trong suốt nên chữ của ô nhập vẫn lộ ra dưới khối,\n * chữ khối vẽ đè đúng chỗ đó — hai lớp chữ phải CÙNG MÀU, lệch màu là thành viền răng\n * cưa quanh từng nét. (Bản gốc cũng chọn chữ gần như trùng màu chữ thường ở cả hai theme.)\n * Khối không chỉ nói bằng màu: nó luôn mang ký tự kích hoạt `@` ở đầu.\n * chữ ⇄ khối: 15,69:1 (light, trên nền trắng) · 15,15:1 (dark) · tệ nhất 13,44:1\n * (dark tương phản cao, `--teal` #2DD4BF). Khối ⇄ nền trang 1,21:1 — cố ý nhạt.\n */\n \"**:data-tag:rounded **:data-tag:bg-info/15 **:data-tag:py-px **:data-tag:text-foreground\",\n className\n )}\n {...props}\n />\n </MentionListIdContext.Provider>\n );\n}\n\ntype MentionLabelProps = React.ComponentProps<typeof MentionPrimitive.Label>;\n\nfunction MentionLabel({ className, ...props }: MentionLabelProps) {\n return (\n <MentionPrimitive.Label\n data-slot=\"mention-label\"\n className={cn(\"px-0.5 py-1.5 text-sm font-semibold\", className)}\n {...props}\n />\n );\n}\n\ntype MentionInputProps = React.ComponentProps<typeof MentionPrimitive.Input>;\n\n/**\n * Ô nhập của `Mention`. Muốn nhiều dòng (ô soạn tin) thì `asChild` với một `<textarea />`.\n * Không có `MentionLabel` thì PHẢI truyền `aria-label`.\n */\nfunction MentionInput({ className, ...props }: MentionInputProps) {\n const listId = React.useContext(MentionListIdContext);\n\n return (\n <MentionPrimitive.Input\n data-slot=\"mention-input\"\n /*\n * ⚠ Khác thượng nguồn (a11y): ô nhập là `role=\"combobox\"` và gói đặt `aria-controls` trỏ tới\n * một id sinh trong gốc — nhưng `MentionContent` của gói KHÔNG gắn id đó lên `role=\"listbox\"`,\n * nên quan hệ combobox → listbox trỏ vào hư không. Lớp bọc tự sinh một id, gắn ở CẢ HAI đầu\n * (props của ta được trải SAU props của gói nên thắng).\n */\n aria-controls={listId}\n className={cn(\n /*\n * Khuôn viền/focus của `Input`: `border-input` lúc nghỉ, `--control-edge-strong` khi rê,\n * `--primary-ink` + `ring-2 ring/50` khi focus. Nền theo `Textarea` (ô soạn tin thường là\n * `asChild` + `<textarea>`): trong suốt, ở dark tô `--input-fill` — không `bg-input/30`,\n * xem chú thích đầu textarea.tsx.\n * ⚠ Khác thượng nguồn: `focus-visible:ring-1 ring-ring` → khuôn focus của `Input`; bỏ\n * `shadow-xs` (bóng của gói chỉ đi qua `--elevation-*`, `Input` không có bóng).\n */\n \"flex w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm text-foreground transition-colors duration-150 ease-out placeholder:text-muted-foreground hover:border-control-edge-strong focus:border-primary-ink focus:outline-none focus:ring-2 focus:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input-fill\",\n className\n )}\n {...props}\n />\n );\n}\n\ntype MentionContentProps = React.ComponentProps<typeof MentionPrimitive.Content>;\n\n/**\n * Danh sách gợi ý (`role=\"listbox\"`), render qua portal.\n * Tên cho trình đọc màn hình mặc định \"Danh sách gợi ý\" — đổi bằng `aria-label`.\n */\nfunction MentionContent({\n className,\n children,\n \"aria-label\": ariaLabel = \"Danh sách gợi ý\",\n ...props\n}: MentionContentProps) {\n const listId = React.useContext(MentionListIdContext);\n\n return (\n <MentionPrimitive.Portal>\n <MentionPrimitive.Content\n data-slot=\"mention-content\"\n // ⚠ Khác thượng nguồn (a11y): id để `aria-controls` của ô nhập trỏ tới được — xem\n // `MentionInput`. Và `role=\"listbox\"` BẮT BUỘC có tên (ARIA 1.2); bản gốc không đặt.\n id={listId}\n aria-label={ariaLabel}\n className={cn(\n /*\n * Mặt nổi cùng bộ với `PopoverContent`/`Command`: `bg-popover text-popover-foreground`,\n * bóng `shadow-overlay` (đổi theo theme qua `--elevation-*`).\n * ⚠ Khác thượng nguồn: `shadow-md` → `shadow-overlay`; thêm `origin-(--dice-transform-origin)`\n * — biến gói headless tính sẵn theo cạnh bám, để hiệu ứng `zoom-in-95` nở ra TỪ phía con\n * trỏ như `PopoverContent` (bản gốc nở từ tâm).\n */\n \"relative z-50 min-w-32 origin-(--dice-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-overlay data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n className\n )}\n {...props}\n >\n {children}\n </MentionPrimitive.Content>\n </MentionPrimitive.Portal>\n );\n}\n\ntype MentionItemProps = React.ComponentProps<typeof MentionPrimitive.Item>;\n\nfunction MentionItem({ className, children, ...props }: MentionItemProps) {\n return (\n <MentionPrimitive.Item\n data-slot=\"mention-item\"\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: bộ lớp của `CommandItem` (mục đang sáng `bg-accent`/`text-accent-\n * foreground`, khoảng đệm theo trục mật độ `--menu-item-py`, icon con mặc định\n * `text-muted-foreground` cỡ 4) — chỉ đổi thuộc tính trạng thái sang dạng của gói headless\n * (`data-highlighted` / `data-disabled` là thuộc tính CÓ MẶT, không phải `=\"true\"`).\n */\n \"relative mt-1 flex w-full cursor-default items-center gap-2 rounded-sm px-2 py-(--menu-item-py) text-sm outline-hidden select-none first:mt-0 data-disabled:pointer-events-none data-disabled:opacity-50 data-highlighted:bg-accent data-highlighted:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className\n )}\n {...props}\n >\n {children}\n </MentionPrimitive.Item>\n );\n}\n\nexport {\n Mention,\n MentionContent,\n type MentionContentProps,\n MentionInput,\n type MentionInputProps,\n MentionItem,\n type MentionItemProps,\n MentionLabel,\n type MentionLabelProps,\n type MentionProps\n};\n"],"mappings":";AAsCM;AA/BN,YAAY,sBAAsB;AAClC,SAAS,oBAAoB;AAC7B,YAAY,WAAW;AACvB,SAAS,UAAU;AAKnB,MAAM,uBAAuB,MAAM,cAAkC,MAAS;AAY9E,SAAS,QAAQ,EAAE,WAAW,KAAK,SAAS,GAAG,MAAM,GAAiB;AAMpE,QAAM,MAAM,aAAa,OAAO;AAChC,QAAM,SAAS,MAAM,MAAM;AAE3B,SACE,oBAAC,qBAAqB,UAArB,EAA8B,OAAO,QACpC;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAgBT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN,GACF;AAEJ;AAIA,SAAS,aAAa,EAAE,WAAW,GAAG,MAAM,GAAsB;AAChE,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,uCAAuC,SAAS;AAAA,MAC7D,GAAG;AAAA;AAAA,EACN;AAEJ;AAQA,SAAS,aAAa,EAAE,WAAW,GAAG,MAAM,GAAsB;AAChE,QAAM,SAAS,MAAM,WAAW,oBAAoB;AAEpD,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MAOV,iBAAe;AAAA,MACf,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAST;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAQA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA,cAAc,YAAY;AAAA,EAC1B,GAAG;AACL,GAAwB;AACtB,QAAM,SAAS,MAAM,WAAW,oBAAoB;AAEpD,SACE,oBAAC,iBAAiB,QAAjB,EACC;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MAGV,IAAI;AAAA,MACJ,cAAY;AAAA,MACZ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH,GACF;AAEJ;AAIA,SAAS,YAAY,EAAE,WAAW,UAAU,GAAG,MAAM,GAAqB;AACxE,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Kiểu quốc gia và nhãn mặc định của `PhoneInput`.
3
+ *
4
+ * Module **CỐ Ý không có `"use client"`** — xem `src/chart/chart-colors.ts` để biết lý do đầy
5
+ * đủ: mọi export của một file `"use client"` đến tay Server Component dưới dạng
6
+ * client-reference proxy, đọc ra `undefined` mà KHÔNG throw, KHÔNG warning. Hằng dữ liệu thuần
7
+ * (nhãn mặc định) phải sống ngoài ranh giới client để app spread/override được ở cả hai phía.
8
+ *
9
+ * ⚠ Barrel `src/index.ts` xuất module này TRỰC TIẾP. `phone-input.tsx` chỉ được `import`,
10
+ * KHÔNG được `export` lại (re-export qua file client là vô hiệu, và đụng tên với `export *`).
11
+ */
12
+ /**
13
+ * Một quốc gia trong danh sách chọn của `PhoneInput` — cũng là hình dạng của prop `countries`
14
+ * khi app muốn tự giới hạn danh sách.
15
+ *
16
+ * ⚠ Khác thượng nguồn: thượng nguồn khai kiểu này dưới tên `Country` và KHÔNG export (app phải
17
+ * viết `PhoneInputProps["countries"]`). Ở đây export dưới tên có tiền tố — `Country` trần là tên
18
+ * quá chung cho entry chính.
19
+ */
20
+ interface PhoneInputCountry {
21
+ /** Mã ISO 3166-1 alpha-2, viết HOA — `"VN"`. */
22
+ code: string;
23
+ /** Tên hiển thị trong danh sách và trong nhãn của nút chọn — `"Việt Nam"`. */
24
+ name: string;
25
+ /** Mã quay số quốc tế, có dấu `+` — `"+84"`. */
26
+ dialCode: string;
27
+ /** Cờ emoji — `"🇻🇳"`. Bỏ trống thì không vẽ cờ. */
28
+ flag?: string;
29
+ }
30
+ /**
31
+ * Chuỗi hiển thị của `PhoneInput` (kể cả chuỗi chỉ dành cho trình đọc màn hình) — override từng
32
+ * khoá qua prop `labels`. Mặc định tiếng Việt.
33
+ *
34
+ * ⚠ Placeholder của ô nhập số KHÔNG nằm ở đây: nó vẫn là prop `placeholder` rời như thượng nguồn
35
+ * (trên `PhoneInput`, hoặc trên chính `PhoneInputField`).
36
+ */
37
+ interface PhoneInputLabels {
38
+ /**
39
+ * Tên cho trình đọc màn hình của nút chọn quốc gia. Nhận quốc gia đang chọn (`undefined` khi
40
+ * chưa chọn) vì tên phải nói được GIÁ TRỊ hiện tại — nút chỉ chứa một lá cờ emoji.
41
+ *
42
+ * ⚠ Thêm so với thượng nguồn: ở bản gốc nút này KHÔNG có tên (lá cờ + mũi tên, hoặc một ô xám
43
+ * trống khi chưa chọn). Là HÀM chứ không phải chuỗi mẫu vì có giá trị chèn vào giữa câu.
44
+ */
45
+ countrySelect: (country: PhoneInputCountry | undefined) => string;
46
+ /** Placeholder ô tìm kiếm trong danh sách quốc gia. */
47
+ searchPlaceholder: string;
48
+ /** Dòng báo khi không quốc gia nào khớp từ khoá. */
49
+ empty: string;
50
+ }
51
+ /** Nhãn tiếng Việt mặc định — mọi khoá đều override được qua prop `labels`. */
52
+ declare const DEFAULT_PHONE_INPUT_LABELS: PhoneInputLabels;
53
+
54
+ export { DEFAULT_PHONE_INPUT_LABELS, type PhoneInputCountry, type PhoneInputLabels };
@@ -0,0 +1,9 @@
1
+ const DEFAULT_PHONE_INPUT_LABELS = {
2
+ countrySelect: (country) => country ? `Qu\u1ED1c gia: ${country.name} (${country.dialCode})` : "Ch\u1ECDn qu\u1ED1c gia",
3
+ searchPlaceholder: "T\xECm qu\u1ED1c gia\u2026",
4
+ empty: "Kh\xF4ng t\xECm th\u1EA5y qu\u1ED1c gia."
5
+ };
6
+ export {
7
+ DEFAULT_PHONE_INPUT_LABELS
8
+ };
9
+ //# sourceMappingURL=phone-input-constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/phone-input-constants.ts"],"sourcesContent":["/**\n * Kiểu quốc gia và nhãn mặc định của `PhoneInput`.\n *\n * Module **CỐ Ý không có `\"use client\"`** — xem `src/chart/chart-colors.ts` để biết lý do đầy\n * đủ: mọi export của một file `\"use client\"` đến tay Server Component dưới dạng\n * client-reference proxy, đọc ra `undefined` mà KHÔNG throw, KHÔNG warning. Hằng dữ liệu thuần\n * (nhãn mặc định) phải sống ngoài ranh giới client để app spread/override được ở cả hai phía.\n *\n * ⚠ Barrel `src/index.ts` xuất module này TRỰC TIẾP. `phone-input.tsx` chỉ được `import`,\n * KHÔNG được `export` lại (re-export qua file client là vô hiệu, và đụng tên với `export *`).\n */\n\n/**\n * Một quốc gia trong danh sách chọn của `PhoneInput` — cũng là hình dạng của prop `countries`\n * khi app muốn tự giới hạn danh sách.\n *\n * ⚠ Khác thượng nguồn: thượng nguồn khai kiểu này dưới tên `Country` và KHÔNG export (app phải\n * viết `PhoneInputProps[\"countries\"]`). Ở đây export dưới tên có tiền tố — `Country` trần là tên\n * quá chung cho entry chính.\n */\nexport interface PhoneInputCountry {\n /** Mã ISO 3166-1 alpha-2, viết HOA — `\"VN\"`. */\n code: string;\n /** Tên hiển thị trong danh sách và trong nhãn của nút chọn — `\"Việt Nam\"`. */\n name: string;\n /** Mã quay số quốc tế, có dấu `+` — `\"+84\"`. */\n dialCode: string;\n /** Cờ emoji — `\"🇻🇳\"`. Bỏ trống thì không vẽ cờ. */\n flag?: string;\n}\n\n/**\n * Chuỗi hiển thị của `PhoneInput` (kể cả chuỗi chỉ dành cho trình đọc màn hình) — override từng\n * khoá qua prop `labels`. Mặc định tiếng Việt.\n *\n * ⚠ Placeholder của ô nhập số KHÔNG nằm ở đây: nó vẫn là prop `placeholder` rời như thượng nguồn\n * (trên `PhoneInput`, hoặc trên chính `PhoneInputField`).\n */\nexport interface PhoneInputLabels {\n /**\n * Tên cho trình đọc màn hình của nút chọn quốc gia. Nhận quốc gia đang chọn (`undefined` khi\n * chưa chọn) vì tên phải nói được GIÁ TRỊ hiện tại — nút chỉ chứa một lá cờ emoji.\n *\n * ⚠ Thêm so với thượng nguồn: ở bản gốc nút này KHÔNG có tên (lá cờ + mũi tên, hoặc một ô xám\n * trống khi chưa chọn). Là HÀM chứ không phải chuỗi mẫu vì có giá trị chèn vào giữa câu.\n */\n countrySelect: (country: PhoneInputCountry | undefined) => string;\n /** Placeholder ô tìm kiếm trong danh sách quốc gia. */\n searchPlaceholder: string;\n /** Dòng báo khi không quốc gia nào khớp từ khoá. */\n empty: string;\n}\n\n/** Nhãn tiếng Việt mặc định — mọi khoá đều override được qua prop `labels`. */\nexport const DEFAULT_PHONE_INPUT_LABELS: PhoneInputLabels = {\n countrySelect: (country) => (country ? `Quốc gia: ${country.name} (${country.dialCode})` : \"Chọn quốc gia\"),\n searchPlaceholder: \"Tìm quốc gia…\",\n empty: \"Không tìm thấy quốc gia.\"\n};\n"],"mappings":"AAsDO,MAAM,6BAA+C;AAAA,EAC1D,eAAe,CAAC,YAAa,UAAU,kBAAa,QAAQ,IAAI,KAAK,QAAQ,QAAQ,MAAM;AAAA,EAC3F,mBAAmB;AAAA,EACnB,OAAO;AACT;","names":[]}
@@ -0,0 +1,85 @@
1
+ import * as React from 'react';
2
+ import { PhoneInputCountry, PhoneInputLabels } from './phone-input-constants.js';
3
+ import { Popover, PopoverTrigger } from './popover.js';
4
+ import '@radix-ui/react-popover';
5
+
6
+ interface StoreState {
7
+ value: string;
8
+ country: string;
9
+ open: boolean;
10
+ startsWithPlus: boolean;
11
+ /**
12
+ * ⚠ 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ự
13
+ * 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.
14
+ */
15
+ nationalInput: string | null;
16
+ }
17
+ interface Store {
18
+ subscribe: (callback: () => void) => () => void;
19
+ getState: () => StoreState;
20
+ setState: <K extends keyof StoreState>(key: K, value: StoreState[K]) => void;
21
+ notify: () => void;
22
+ }
23
+ declare function useStore<T>(selector: (state: StoreState) => T, ogStore?: Store | null): T;
24
+ /**
25
+ * Ô nhập số điện thoại quốc tế: nút chọn quốc gia (`PhoneInputCountrySelect`) + ô số
26
+ * (`PhoneInputField`). Giá trị (`value` / `onValueChange` / input ẩn khi submit form) luôn là E.164
27
+ * chỉ gồm chữ số: `"+84912345678"`. Người dùng gõ được theo HAI cách:
28
+ *
29
+ * - **Số nội địa** — chuỗi KHÔNG bắt đầu bằng `+`, và đang có quốc gia được chọn (mặc định Việt
30
+ * Nam): 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õ
31
+ * (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ị
32
+ * ghép lại theo mã mới, còn chữ trên ô giữ nguyên.
33
+ * Gõ `0912 345 678` → ô hiện `0912 345 678`, `onValueChange("+84912345678")`.
34
+ * ⚠ Khác thượng nguồn — bản gốc ra `+0912345678`. Ý, San Marino, Vatican giữ số 0 đầu (máy bàn
35
+ * `06 …` → `+39 06 …`).
36
+ * - **Số quốc tế** — chuỗi bắt đầu bằng `+` (như thượng nguồn): ô hiện tách nhóm
37
+ * (`+84 912 345 678`), quốc gia tự nhận theo mã quay số.
38
+ * Gõ `+84 912 345 678` → `onValueChange("+84912345678")`, cờ chuyển sang Việt Nam.
39
+ *
40
+ * 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
41
+ * được chọn (`defaultCountry=""`) thì mọi chữ số đầu bị coi là mã quốc gia, như thượng nguồn.
42
+ *
43
+ * Gốc là `role="group"` chưa có tên: đặt `aria-label` (vd "Số điện thoại") hoặc `aria-labelledby`
44
+ * cho chính `PhoneInput`.
45
+ */
46
+ interface PhoneInputProps extends React.ComponentProps<"div"> {
47
+ defaultValue?: string;
48
+ value?: string;
49
+ onValueChange?: (value: string) => void;
50
+ /**
51
+ * Quốc gia ban đầu (mã ISO alpha-2, viết HOA). Mặc định `"VN"`.
52
+ *
53
+ * ⚠ Khác thượng nguồn: thượng nguồn để trống. Truyền `""` để quay về hành vi đó.
54
+ */
55
+ defaultCountry?: string;
56
+ country?: string;
57
+ onCountryChange?: (country: string) => void;
58
+ countries?: PhoneInputCountry[];
59
+ name?: string;
60
+ /** Placeholder ô nhập số. Mặc định "Nhập số điện thoại". */
61
+ placeholder?: string;
62
+ /**
63
+ * Locale BCP 47 để gọi tên quốc gia (`Intl.DisplayNames`) và sắp xếp danh sách. Mặc định `"vi"`.
64
+ * Bỏ qua khi app truyền `countries` riêng (tên lấy nguyên từ đó).
65
+ *
66
+ * ⚠ Thêm so với thượng nguồn — bản gốc ghim tên tiếng Anh.
67
+ */
68
+ locale?: string;
69
+ /** Chuỗi hiển thị/đọc màn hình của phần chọn quốc gia — override từng khoá. */
70
+ labels?: Partial<PhoneInputLabels>;
71
+ asChild?: boolean;
72
+ disabled?: boolean;
73
+ readOnly?: boolean;
74
+ required?: boolean;
75
+ invalid?: boolean;
76
+ showFlag?: boolean;
77
+ }
78
+ declare function PhoneInput(props: PhoneInputProps): React.JSX.Element;
79
+ interface PhoneInputCountrySelectProps extends React.ComponentProps<typeof Popover>, Pick<React.ComponentProps<typeof PopoverTrigger>, "disabled" | "className"> {
80
+ }
81
+ declare function PhoneInputCountrySelect(props: PhoneInputCountrySelectProps): React.JSX.Element;
82
+ type PhoneInputFieldProps = React.ComponentProps<"input">;
83
+ declare function PhoneInputField(props: PhoneInputFieldProps): React.JSX.Element;
84
+
85
+ export { PhoneInput, PhoneInputCountrySelect, type PhoneInputCountrySelectProps, PhoneInputField, type PhoneInputFieldProps, type PhoneInputProps, useStore as usePhoneInput };