@comitor/ui 0.2.1 → 0.3.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 (90) hide show
  1. package/README.md +236 -30
  2. package/dist/chart/chart-colors.d.ts +56 -0
  3. package/dist/chart/chart-colors.js +21 -0
  4. package/dist/chart/chart-colors.js.map +1 -0
  5. package/dist/chart/chart.d.ts +40 -0
  6. package/dist/chart/chart.js.map +1 -1
  7. package/dist/chart/comitor-chart.d.ts +21 -43
  8. package/dist/chart/comitor-chart.js +13 -24
  9. package/dist/chart/comitor-chart.js.map +1 -1
  10. package/dist/chart/index.d.ts +2 -1
  11. package/dist/chart/index.js +1 -0
  12. package/dist/chart/index.js.map +1 -1
  13. package/dist/components/composite/data-table-constants.d.ts +40 -0
  14. package/dist/components/composite/data-table-constants.js +13 -0
  15. package/dist/components/composite/data-table-constants.js.map +1 -0
  16. package/dist/components/composite/data-table.d.ts +2 -27
  17. package/dist/components/composite/data-table.js +1 -10
  18. package/dist/components/composite/data-table.js.map +1 -1
  19. package/dist/components/composite/date-picker-constants.d.ts +21 -0
  20. package/dist/components/composite/date-picker-constants.js +39 -0
  21. package/dist/components/composite/date-picker-constants.js.map +1 -0
  22. package/dist/components/composite/date-picker.d.ts +2 -18
  23. package/dist/components/composite/date-picker.js +6 -48
  24. package/dist/components/composite/date-picker.js.map +1 -1
  25. package/dist/components/composite/form-field-constants.d.ts +26 -0
  26. package/dist/components/composite/form-field-constants.js +13 -0
  27. package/dist/components/composite/form-field-constants.js.map +1 -0
  28. package/dist/components/composite/form-field.d.ts +1 -13
  29. package/dist/components/composite/form-field.js +1 -11
  30. package/dist/components/composite/form-field.js.map +1 -1
  31. package/dist/components/composite/search-filter-bar-constants.d.ts +52 -0
  32. package/dist/components/composite/search-filter-bar-constants.js +18 -0
  33. package/dist/components/composite/search-filter-bar-constants.js.map +1 -0
  34. package/dist/components/composite/search-filter-bar.d.ts +3 -37
  35. package/dist/components/composite/search-filter-bar.js +2 -15
  36. package/dist/components/composite/search-filter-bar.js.map +1 -1
  37. package/dist/components/composite/table-pagination-constants.d.ts +56 -0
  38. package/dist/components/composite/table-pagination-constants.js +18 -0
  39. package/dist/components/composite/table-pagination-constants.js.map +1 -0
  40. package/dist/components/composite/table-pagination.d.ts +2 -43
  41. package/dist/components/composite/table-pagination.js +4 -15
  42. package/dist/components/composite/table-pagination.js.map +1 -1
  43. package/dist/components/ui/badge.js +3 -3
  44. package/dist/components/ui/badge.js.map +1 -1
  45. package/dist/components/ui/button.js +4 -4
  46. package/dist/components/ui/button.js.map +1 -1
  47. package/dist/components/ui/calendar.js +1 -1
  48. package/dist/components/ui/calendar.js.map +1 -1
  49. package/dist/components/ui/checkbox.js +2 -2
  50. package/dist/components/ui/checkbox.js.map +1 -1
  51. package/dist/components/ui/command.js +1 -1
  52. package/dist/components/ui/command.js.map +1 -1
  53. package/dist/components/ui/input-group.js +1 -1
  54. package/dist/components/ui/input-group.js.map +1 -1
  55. package/dist/components/ui/input-otp.js +1 -1
  56. package/dist/components/ui/input-otp.js.map +1 -1
  57. package/dist/components/ui/navigation-menu.js +1 -1
  58. package/dist/components/ui/navigation-menu.js.map +1 -1
  59. package/dist/components/ui/radio-group.js +1 -1
  60. package/dist/components/ui/radio-group.js.map +1 -1
  61. package/dist/components/ui/resizable.js +1 -1
  62. package/dist/components/ui/resizable.js.map +1 -1
  63. package/dist/components/ui/slider.js +1 -1
  64. package/dist/components/ui/slider.js.map +1 -1
  65. package/dist/components/ui/switch.js +1 -1
  66. package/dist/components/ui/switch.js.map +1 -1
  67. package/dist/components/ui/textarea.js +1 -1
  68. package/dist/components/ui/textarea.js.map +1 -1
  69. package/dist/index.d.ts +11 -6
  70. package/dist/index.js +5 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/shell/contrast-constants.d.ts +30 -0
  73. package/dist/shell/contrast-constants.js +16 -0
  74. package/dist/shell/contrast-constants.js.map +1 -0
  75. package/dist/shell/contrast-provider.d.ts +60 -0
  76. package/dist/shell/contrast-provider.js +61 -0
  77. package/dist/shell/contrast-provider.js.map +1 -0
  78. package/dist/shell/contrast-toggle.d.ts +24 -0
  79. package/dist/shell/contrast-toggle.js +29 -0
  80. package/dist/shell/contrast-toggle.js.map +1 -0
  81. package/dist/shell/index.d.ts +3 -0
  82. package/dist/shell/index.js +3 -0
  83. package/dist/shell/index.js.map +1 -1
  84. package/dist/shell/shell-context.js +3 -2
  85. package/dist/shell/shell-context.js.map +1 -1
  86. package/dist/tokens.d.ts +170 -70
  87. package/dist/tokens.js +124 -47
  88. package/dist/tokens.js.map +1 -1
  89. package/package.json +3 -2
  90. package/styles.css +255 -120
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tokens.ts"],"sourcesContent":["/**\n * Design token dạng TS object — dành cho nơi KHÔNG có Tailwind: canvas, biểu đồ tuỳ biến,\n * email HTML, xuất PDF, (sau này) React Native.\n *\n * ⚠ Nguồn sự thật của giá trị là `styles.css` (CSS variable). File này chỉ MIRROR hằng số.\n * Sửa màu ở styles.css thì phải sửa kèm ở đây — và ngược lại.\n *\n * Trong môi trường có Tailwind, LUÔN dùng class token (`bg-primary`, `text-ash-500`),\n * đừng đọc hex từ đây rồi nhét vào style inline: làm vậy là mất dark mode.\n *\n * Hợp đồng ba vai trò của màu (giống hệt `styles.css`; bảng đầy đủ ở docs/hop-dong-mau.md),\n * đọc tên là biết dùng ở đâu:\n * `x` → tô NỀN (fill đặc hoặc tint /5–/20 — trần chung an toàn cho mọi tone)\n * `xForeground` → chữ/icon NẰM TRÊN nền `x` ĐẶC — đo với `x`, ngưỡng 4,5:1\n * `xInk` → chính màu đó khi ĐI LÊN nền trang hoặc lên tint của chính nó (chữ, icon\n * rời, viền, vạch active) — đo với nền đó\n *\n * Cố ý KHÔNG mirror (xem docs/quyet-dinh-tich-hop.md §21): `--elevation-*` (chuỗi box-shadow chỉ\n * có nghĩa trong CSS), `--app-accent*` (giá trị thuộc về APP, không phải gói), `--font-*`.\n */\n\nimport { AVATAR_TONES, type AvatarToneColors, type AvatarTonePalette, getAvatarToneIndex } from \"./lib/avatar-tone.js\";\n\n/** Thang GOLD 7 bậc — trục màu chính của brand Comitor. */\nexport const gold = {\n 50: \"#FBF5DC\",\n 100: \"#F8E89D\",\n 200: \"#F5D060\",\n /** primary ở light mode */\n 300: \"#E8B824\",\n 400: \"#B88A00\",\n 500: \"#7A5800\",\n 600: \"#5C4006\"\n} as const;\n\n/** Trung tính brand (khác thang ash — đây là màu \"giấy/mực\" của brand book). */\nexport const brandNeutral = {\n ink: \"#0E1116\",\n inkSoft: \"#3A3F4A\",\n paper: \"#FBF7EE\",\n warm: \"#EDE8D8\"\n} as const;\n\n/**\n * Thang xám Comitor — namespace `ash`, KHÔNG phải `gray`.\n * Chỉ có 6 bậc; các bậc khuyết (200/400/600/800) cố ý không khai để không lẫn với\n * thang gray dựng sẵn của Tailwind (xem chú thích trong styles.css).\n */\nexport const ash = {\n 50: \"#F7F7F8\",\n 100: \"#EDEEF1\",\n 300: \"#C8CBD3\",\n 500: \"#7E8290\",\n 700: \"#3A3F4A\",\n 900: \"#16181D\"\n} as const;\n\n/**\n * Màu phụ — vai trò TÔ NỀN (fill đặc hoặc tint). Bản `dark` được nâng sáng vì trên nền #0E1116\n * bản `light` chìm nghỉm.\n *\n * ⚠ ĐỪNG dùng bảng này làm màu CHỮ ở light: nó được chọn để tô nền nên quá nhạt — dùng\n * `accentInk` ngay dưới. `accent.dark.navy` giữ nguyên #0F1E3D chỉ để mirror đúng `styles.css`\n * (khối `.dark` không override `--navy`); vai trò navy ở dark do `accentInk.dark.navy` gánh.\n */\nexport const accent = {\n light: {\n navy: \"#0F1E3D\",\n teal: \"#1F8A8B\",\n red: \"#D64545\",\n green: \"#2EA56A\",\n yellow: \"#F2C94C\"\n },\n dark: {\n navy: \"#0F1E3D\",\n teal: \"#2DD4BF\",\n red: \"#F87171\",\n green: \"#4ADE80\",\n yellow: \"#FACC15\"\n }\n} as const;\n\n/**\n * Bậc INK của màu phụ — mirror `--teal-ink` / `--green-ink` / `--red-ink` / `--yellow-ink` /\n * `--navy-ink`. Đây là màu phụ khi nó làm **CHỮ/ICON/VIỀN trên nền trang** (hoặc trên tint\n * /5–/20 của chính nó), tức vai trò NGƯỢC với `accent`.\n *\n * Hợp đồng đặt tên của cả gói: `--x` tô nền · `--x-foreground` là chữ NẰM TRÊN nền `--x` ·\n * `--x-ink` là chính màu đó ĐI LÊN nền trang.\n *\n * Bản `light` là bậc tối đã đóng băng (kết quả của `color-mix(in srgb, --<màu>, --ink 30/40%)`\n * mà trước đây mỗi component tự tính lấy); bản `dark` chính là `accent.dark` vì bên đó màu phụ\n * đã đủ sáng để làm chữ. Đo trên tint 15% của chính nó — nền thật mà chữ initials avatar và\n * badge tonal đứng lên: teal 5,54 · green 5,60 · red 5,83:1 ở light (bản chưa có ink: 3,44 /\n * 2,69 / 3,57:1 ✗); 7,12 / 7,44 / 5,18:1 ở dark.\n */\nexport const accentInk = {\n light: {\n navy: accent.light.navy,\n teal: \"#1A6668\",\n red: \"#9A3537\",\n green: \"#216A48\",\n /** = gold[500]: vàng không có bậc tối riêng, mượn thang gold cùng sắc. */\n yellow: gold[500]\n },\n dark: {\n /** navy nguyên bản chìm vào nền dark (1,15:1) → bậc sáng riêng; cũng là `--chart-3` ở dark. */\n navy: \"#7EA2E8\",\n teal: accent.dark.teal,\n red: accent.dark.red,\n green: accent.dark.green,\n yellow: accent.dark.yellow\n }\n} as const;\n\n/**\n * Bậc FOREGROUND của màu phụ — mirror `--teal-foreground` / `--green-foreground` /\n * `--yellow-foreground` / `--navy-foreground`. Đây là chữ/icon nằm **TRÊN nền `accent.*` ĐẶC**,\n * tức vai trò thứ ba, khác hẳn `accentInk` (màu đó đi lên nền TRANG).\n *\n * Cả ba sắc teal/green/yellow đều sáng ở light và còn sáng hơn ở dark → chữ là MỰC ở cả hai\n * theme, một giá trị đủ dùng: teal 4,56:1 (light) / 10,16:1 (dark) · green 6,04 / 10,85 ·\n * yellow 11,92 / 12,35. Navy thì ngược lại — chữ TRẮNG, 16,49:1 ở cả hai theme.\n *\n * ⚠ CỐ Ý KHÔNG có `red`: nền `accent.light.red` #D64545 đặc không mang được chữ ở light — trắng\n * 4,38:1 ✗ và mực 4,32:1 ✗. Nền đỏ đặc có chữ phải dùng `status.*.destructive` (#C93B3B) cùng\n * `destructiveForeground` = 5,03:1 ✓. `accent.*.red` chỉ để tô TINT và làm màu chart.\n */\nexport const accentForeground = {\n light: {\n navy: \"#FFFFFF\",\n teal: \"#0E1116\",\n green: \"#0E1116\",\n yellow: \"#0E1116\"\n },\n dark: {\n navy: \"#FFFFFF\",\n teal: \"#0E1116\",\n green: \"#0E1116\",\n yellow: \"#0E1116\"\n }\n} as const;\n\n/** Semantic token của shadcn — mirror khối `:root` / `.dark` trong styles.css. */\nexport const semantic = {\n light: {\n background: \"#FFFFFF\",\n foreground: \"#0E1116\",\n card: \"#FFFFFF\",\n cardForeground: \"#0E1116\",\n popover: \"#FFFFFF\",\n popoverForeground: \"#0E1116\",\n primary: \"#E8B824\",\n primaryForeground: \"#0E1116\",\n /** Bậc INK của brand — gold khi phải ĐI LÊN nền trang (rãnh Switch khi BẬT, ô Checkbox đã\n * chọn). `primary` #E8B824 chỉ 1,86:1 với nền trắng ✗; bậc này = `gold[500]` = 6,51:1 ✓. */\n primaryInk: gold[500],\n secondary: \"#EDE8D8\",\n secondaryForeground: \"#0E1116\",\n muted: \"#F7F7F8\",\n /** Bậc chữ phụ — là CHỮ nên ngưỡng AA 4,5:1: 5,23:1 trên nền trắng, 4,89:1 trên `muted`.\n * KHÔNG còn bằng `ash[500]` (#7E8290 chỉ 3,83:1 ✗) — bậc bảng màu và token semantic tách nhau. */\n mutedForeground: \"#686C7A\",\n accent: \"#FBF5DC\",\n accentForeground: \"#0E1116\",\n destructive: \"#C93B3B\",\n destructiveForeground: \"#FFFFFF\",\n /** Chữ báo lỗi trên nền trang — KHÁC `destructive` (nền) và `destructiveForeground` (chữ\n * trắng trên nền đó). 7,15:1 trên nền trắng. */\n destructiveInk: accentInk.light.red,\n /** RANH GIỚI TRANG TRÍ (vạch chia, viền thẻ nghỉ) — 1,16:1, cố ý: 1.4.11 không đòi tương\n * phản cho thứ không mang thông tin. Ranh giới của CONTROL đi qua `controlEdge`. */\n border: \"#EDEEF1\",\n /** = `controlEdge`: viền ô nhập là ranh giới nhận dạng control (1.4.11) → 3,83:1 ✓. */\n input: \"#7E8290\",\n ring: \"#E8B824\",\n /** Ranh giới của control lúc NGHỈ (viền Input, ô Checkbox chưa chọn, rãnh Switch khi TẮT) —\n * WCAG 1.4.11, ràng buộc HAI PHÍA. Một giá trị cho cả hai theme: 3,83:1 với nền trắng và\n * 3,83:1 với `controlKnob` (trắng ở light); 4,94:1 với nền dark và với knob #0E1116. */\n controlEdge: \"#7E8290\",\n /** Cùng vai trò nhưng ở HOVER/ACTIVE — phải ĐẬM hơn lúc nghỉ. = `ash[700]`, 10,55:1 trên nền\n * trắng · 9,86:1 trên `muted`. */\n controlEdgeStrong: ash[700],\n /** Nền control khi BẬT/ĐÃ CHỌN (rãnh Switch bật, ô Checkbox đã chọn, chấm Radio) = `primaryInk`.\n * Ràng buộc hai phía: 6,51:1 với nền trang VÀ 6,51:1 với `controlKnob` ở light. `primary`\n * #E8B824 chỉ 1,86:1 cả hai phía ✗. */\n controlOn: gold[500],\n /** Núm Switch / dấu check / chấm Radio — mang màu NỀN TRANG nên luôn tương phản đúng chiều\n * với cả rãnh BẬT (6,51:1) lẫn rãnh TẮT (3,83:1). KHÔNG dùng `primaryForeground` (mực): mực\n * trên `controlOn` #7A5800 chỉ 1,86:1 ✗. */\n controlKnob: \"#FFFFFF\",\n sidebar: \"#FAFAF9\",\n sidebarForeground: \"#0E1116\",\n sidebarBorder: \"#EDEEF1\",\n sidebarAccent: \"#FBF5DC\",\n sidebarAccentForeground: \"#0E1116\"\n },\n dark: {\n background: \"#0E1116\",\n foreground: \"#F7F7F8\",\n card: \"#16181D\",\n cardForeground: \"#F7F7F8\",\n popover: \"#16181D\",\n popoverForeground: \"#F7F7F8\",\n primary: \"#F5D060\",\n primaryForeground: \"#0E1116\",\n /** Ở dark `primary` vốn đã là bậc sáng (12,67:1 trên nền `background`) nên ink = chính nó. */\n primaryInk: \"#F5D060\",\n secondary: \"#1E2128\",\n secondaryForeground: \"#F7F7F8\",\n muted: \"#1E2128\",\n /** Sáng hơn bản light: chữ phụ ở dark hay nằm trên `card`/`muted`. 5,35:1 trên `card`,\n * 4,86:1 trên `muted` (giá trị cũ #7E8290 chỉ 4,21:1 trên `muted` ✗). */\n mutedForeground: \"#888D9B\",\n accent: \"#1E2128\",\n accentForeground: \"#F7F7F8\",\n destructive: \"#C93B3B\",\n destructiveForeground: \"#FFFFFF\",\n /** 6,42:1 trên `card` — `destructive` dùng làm chữ ở dark chỉ được 3,53:1 ✗. */\n destructiveInk: accentInk.dark.red,\n /** TRANG TRÍ, 1,17:1 trên `background` và 1,10:1 trên `card` — cố ý, xem nhánh light. */\n border: \"#1E2128\",\n /** = `controlEdge`, ghim một giá trị cho cả hai theme — 4,94:1 trên `background` ✓. */\n input: \"#7E8290\",\n ring: \"#F5D060\",\n /** Ghim đúng giá trị của light — xem chú thích ở nhánh light. */\n controlEdge: \"#7E8290\",\n /** = `ash[300]` (lật chiều so với light): 11,65:1 trên `background` · 10,94:1 trên `card`. */\n controlEdgeStrong: ash[300],\n /** = `primaryInk` của dark; 12,67:1 với nền trang VÀ với `controlKnob` (#0E1116). */\n controlOn: \"#F5D060\",\n /** = `background` của dark. Núm trắng cứng sẽ chỉ được 1,49:1 với rãnh BẬT ✗. */\n controlKnob: \"#0E1116\",\n sidebar: \"#16181D\",\n sidebarForeground: \"#F7F7F8\",\n sidebarBorder: \"#1E2128\",\n sidebarAccent: \"#1E2128\",\n sidebarAccentForeground: \"#F7F7F8\"\n }\n} as const;\n\n/**\n * Alias trạng thái — success/warning/info trỏ vào màu phụ, destructive giữ nguyên 2 chế độ.\n *\n * Ba lớp KHÁC nhau, đừng gộp:\n * • `destructive` (#C93B3B) — màu NỀN (nút xoá), đủ đậm cho chữ trắng ở cả hai theme (5,03:1);\n * • `destructiveForeground` (#FFFFFF) — chữ NẰM TRÊN nền đó;\n * • `destructiveInk` — màu CHỮ đỏ trên nền trang (dòng lỗi). Dùng nhầm `destructive` cho vai\n * trò này thì ở dark chỉ được 3,53:1, dùng `accent.light.red` thì ở light chỉ 4,38:1.\n *\n * `successForeground` / `warningForeground` / `infoForeground` là MỰC ở CẢ hai theme (không phải\n * trắng ở light rồi lật ở dark như bản 0.1.0): ba nền trạng thái đều là sắc sáng.\n * success mực 6,04:1 (light) · 10,85:1 (dark) [trắng chỉ 3,13 / 1,74:1 ✗]\n * info mực 4,56:1 (light) · 10,16:1 (dark) [trắng chỉ 4,14 / 1,86:1 ✗]\n * warning mực 11,92:1 (light) · 12,35:1 (dark) [trắng chỉ 1,59 / 1,53:1 ✗]\n * ⚠ `info` ở light là cặp chặt nhất gói (4,56:1, dư 0,06) — đổi `accent.light.teal` là phải đo lại.\n */\nexport const status = {\n light: {\n success: accent.light.green,\n successForeground: \"#0E1116\",\n warning: accent.light.yellow,\n warningForeground: \"#0E1116\",\n info: accent.light.teal,\n infoForeground: \"#0E1116\",\n destructive: \"#C93B3B\",\n destructiveForeground: \"#FFFFFF\",\n successInk: accentInk.light.green,\n warningInk: accentInk.light.yellow,\n infoInk: accentInk.light.teal,\n destructiveInk: accentInk.light.red\n },\n dark: {\n success: accent.dark.green,\n successForeground: \"#0E1116\",\n warning: accent.dark.yellow,\n warningForeground: \"#0E1116\",\n info: accent.dark.teal,\n infoForeground: \"#0E1116\",\n destructive: \"#C93B3B\",\n destructiveForeground: \"#FFFFFF\",\n successInk: accentInk.dark.green,\n warningInk: accentInk.dark.yellow,\n infoInk: accentInk.dark.teal,\n destructiveInk: accentInk.dark.red\n }\n} as const;\n\n/** Bảng màu biểu đồ (chart-1…chart-5). Thứ tự = thứ tự series mặc định. */\nexport const chart = {\n light: [gold[300], accent.light.teal, accent.light.navy, accent.light.green, accent.light.red],\n dark: [gold[200], accent.dark.teal, accentInk.dark.navy, accent.dark.green, accent.dark.red]\n} as const;\n\n/**\n * Màu avatar chữ cái (hex đục) cho nơi KHÔNG có Tailwind: canvas, email HTML, PDF.\n *\n * ⚠ KHÔNG phải bảng màu thứ hai. Bảng tone DUY NHẤT của cả gói nằm ở `lib/avatar-tone.ts`, mỗi\n * tone mang cả chuỗi class (cho DOM) lẫn công thức hex tương ứng; ở đây chỉ nạp bảng màu vào công\n * thức đó. Web và email vì vậy dùng chung một thứ tự tone, một hàm băm, một cách chuẩn hoá tên —\n * không còn hai bảng để lệch nhau.\n */\nconst avatarTonePalette = {\n light: {\n gold,\n ash,\n brandNeutral,\n accent: accent.light,\n accentInk: accentInk.light,\n card: semantic.light.card\n },\n dark: {\n gold,\n ash,\n brandNeutral,\n accent: accent.dark,\n accentInk: accentInk.dark,\n card: semantic.dark.card\n }\n} satisfies Record<ThemeMode, AvatarTonePalette>;\n\n/**\n * Cặp nền/chữ (hex) của avatar cho một tên, theo theme.\n *\n * Tên hàm nói đúng thứ nó trả về: `...Colors` = hex (canvas/email/PDF), còn bản trả về chuỗi\n * class Tailwind cho DOM là `getAvatarToneClasses` ở `@comitor/ui`. Cùng một tên người luôn ra\n * cùng một tone ở cả hai đường vì chỉ số do MỘT hàm tính (`getAvatarToneIndex`).\n */\nexport function getAvatarToneColors(name: string, mode: ThemeMode = \"light\"): AvatarToneColors {\n // `noUncheckedIndexedAccess` bật → phải có nhánh lùi, dù chỉ số luôn nằm trong [0, 8).\n const tone = AVATAR_TONES[getAvatarToneIndex(name)] ?? AVATAR_TONES[0];\n return tone[mode](avatarTonePalette[mode]);\n}\n\nexport type { AvatarToneColors };\nexport { getAvatarToneIndex };\n\n/** Số đo khung ứng dụng — mirror --sidebar-width / --sidebar-width-icon / --header-height. */\nexport const layout = {\n /** px — --header-height 3.5rem */\n headerHeight: 56,\n /** px — --sidebar-width 16rem */\n sidebarWidth: 256,\n /** px — --sidebar-width-icon 3.5rem */\n sidebarCollapsedWidth: 56,\n /** px — --radius 0.375rem */\n radius: 6,\n breakpoints: { mobile: 768, tablet: 1024, desktop: 1280 },\n /** px — kích thước tối thiểu của vùng chạm trên mobile (WCAG 2.5.5) */\n minTapTarget: 44\n} as const;\n\n/** Font stack — app phải tự nạp Inter (subsets latin + vietnamese) và gán --font-inter. */\nexport const typography = {\n fontSans: '\"Inter\", system-ui, sans-serif',\n fontMono: '\"Geist Mono\", ui-monospace, monospace'\n} as const;\n\nexport type ThemeMode = \"light\" | \"dark\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/tokens.ts"],"sourcesContent":["/**\n * Design token dạng TS object — dành cho nơi KHÔNG có Tailwind: canvas, biểu đồ tuỳ biến,\n * email HTML, xuất PDF, (sau này) React Native.\n *\n * ⚠ Nguồn sự thật của giá trị là `styles.css` (CSS variable). File này chỉ MIRROR hằng số.\n * Sửa màu ở styles.css thì phải sửa kèm ở đây — và ngược lại.\n *\n * Trong môi trường có Tailwind, LUÔN dùng class token (`bg-primary`, `text-ash-500`),\n * đừng đọc hex từ đây rồi nhét vào style inline: làm vậy là mất dark mode.\n *\n * Hợp đồng ba vai trò của màu (giống hệt `styles.css`; bảng đầy đủ ở docs/hop-dong-mau.md),\n * đọc tên là biết dùng ở đâu:\n * `x` → tô NỀN (fill đặc hoặc tint /5–/20 — trần chung an toàn cho mọi tone)\n * `xForeground` → chữ/icon NẰM TRÊN nền `x` ĐẶC — đo với `x`, ngưỡng 4,5:1\n * `xInk` → chính màu đó khi ĐI LÊN nền trang hoặc lên tint của chính nó (chữ, icon\n * rời, viền, vạch active) — đo với nền đó\n *\n * Cố ý KHÔNG mirror (xem docs/quyet-dinh-tich-hop.md §21): `--elevation-*` (chuỗi box-shadow chỉ\n * có nghĩa trong CSS), `--app-accent*` (giá trị thuộc về APP, không phải gói), `--font-*`.\n */\n\nimport { AVATAR_TONES, type AvatarToneColors, type AvatarTonePalette, getAvatarToneIndex } from \"./lib/avatar-tone.js\";\n\n/** Thang GOLD 7 bậc — trục màu chính của brand Comitor. */\nexport const gold = {\n 50: \"#FBF5DC\",\n 100: \"#F8E89D\",\n 200: \"#F5D060\",\n /** primary ở light mode */\n 300: \"#E8B824\",\n 400: \"#B88A00\",\n 500: \"#7A5800\",\n 600: \"#5C4006\"\n} as const;\n\n/** Trung tính brand (khác thang ash — đây là màu \"giấy/mực\" của brand book). */\nexport const brandNeutral = {\n ink: \"#0E1116\",\n inkSoft: \"#3A3F4A\",\n paper: \"#FBF7EE\",\n warm: \"#EDE8D8\"\n} as const;\n\n/**\n * Thang xám Comitor — namespace `ash`, KHÔNG phải `gray`.\n * Chỉ có 6 bậc; các bậc khuyết (200/400/600/800) cố ý không khai để không lẫn với\n * thang gray dựng sẵn của Tailwind (xem chú thích trong styles.css).\n */\nexport const ash = {\n 50: \"#F7F7F8\",\n 100: \"#EDEEF1\",\n 300: \"#C8CBD3\",\n 500: \"#7E8290\",\n 700: \"#3A3F4A\",\n 900: \"#16181D\"\n} as const;\n\n/**\n * Màu phụ — vai trò TÔ NỀN (fill đặc hoặc tint). Bản `dark` được nâng sáng vì trên nền #0E1116\n * bản `light` chìm nghỉm.\n *\n * ⚠ ĐỪNG dùng bảng này làm màu CHỮ ở light: nó được chọn để tô nền nên quá nhạt — dùng\n * `accentInk` ngay dưới. `accent.dark.navy` giữ nguyên #0F1E3D chỉ để mirror đúng `styles.css`\n * (khối `.dark` không override `--navy`); vai trò navy ở dark do `accentInk.dark.navy` gánh.\n */\nexport const accent = {\n light: {\n navy: \"#0F1E3D\",\n teal: \"#1F8A8B\",\n red: \"#D64545\",\n green: \"#2EA56A\",\n yellow: \"#F2C94C\"\n },\n /** Bảng MẶC ĐỊNH (comitor-ds) không khai lại màu phụ ở dark — cùng hex với light. Bản sáng\n * dành cho nền tối nằm ở `highContrast.dark`. */\n dark: {\n navy: \"#0F1E3D\",\n teal: \"#1F8A8B\",\n red: \"#D64545\",\n green: \"#2EA56A\",\n yellow: \"#F2C94C\"\n }\n} as const;\n\n/**\n * Bậc INK của màu phụ — mirror `--teal-ink` / `--green-ink` / `--red-ink` / `--yellow-ink` /\n * `--navy-ink`. Đây là màu phụ khi nó làm **CHỮ/ICON/VIỀN trên nền trang** (hoặc trên tint\n * /5–/20 của chính nó), tức vai trò NGƯỢC với `accent`.\n *\n * Hợp đồng đặt tên của cả gói: `--x` tô nền · `--x-foreground` là chữ NẰM TRÊN nền `--x` ·\n * `--x-ink` là chính màu đó ĐI LÊN nền trang.\n *\n * Bản `light` là bậc tối đã đóng băng (kết quả của `color-mix(in srgb, --<màu>, --ink 30/40%)`\n * mà trước đây mỗi component tự tính lấy); bản `dark` chính là `accent.dark`. Đo trên tint 15%\n * của chính nó — nền thật mà chữ initials avatar và badge tonal đứng lên: teal 5,54 · green 5,60\n * · red 5,83:1 ở light (bản chưa có ink: 3,44 / 2,69 / 3,57:1 ✗).\n *\n * ⚠ Ở bảng MẶC ĐỊNH, `accent.dark` bằng hex của light nên bậc ink ở dark cũng vậy — đúng thứ\n * comitor-ds render. Bậc sáng cho nền tối nằm ở `highContrast.dark`.\n */\nexport const accentInk = {\n light: {\n navy: accent.light.navy,\n teal: \"#1A6668\",\n red: \"#9A3537\",\n green: \"#216A48\",\n /** = gold[500]: vàng không có bậc tối riêng, mượn thang gold cùng sắc. */\n yellow: gold[500]\n },\n dark: {\n /** navy nguyên bản chìm vào nền dark (1,15:1) → bậc sáng riêng; cũng là `--chart-3` ở dark. */\n navy: \"#7EA2E8\",\n teal: accent.dark.teal,\n red: accent.dark.red,\n green: accent.dark.green,\n yellow: accent.dark.yellow\n }\n} as const;\n\n/**\n * Bậc FOREGROUND của màu phụ — mirror `--teal-foreground` / `--green-foreground` /\n * `--yellow-foreground` / `--navy-foreground`. Đây là chữ/icon nằm **TRÊN nền `accent.*` ĐẶC**,\n * tức vai trò thứ ba, khác hẳn `accentInk` (màu đó đi lên nền TRANG).\n *\n * Cả ba sắc teal/green/yellow đều sáng ở light và còn sáng hơn ở dark → chữ là MỰC ở cả hai\n * theme, một giá trị đủ dùng: teal 4,56:1 (light) / 10,16:1 (dark) · green 6,04 / 10,85 ·\n * yellow 11,92 / 12,35. Navy thì ngược lại — chữ TRẮNG, 16,49:1 ở cả hai theme.\n *\n * ⚠ CỐ Ý KHÔNG có `red`: nền đỏ đặc không mang được chữ tốt ở light — trắng trên #D64545 được\n * 4,38:1 và mực 4,32:1, cả hai đều dưới AA. Nền đỏ đặc có chữ phải dùng `status.*.destructive`;\n * ở bảng tương phản cao token đó là #C93B3B và đạt 5,03:1. `accent.*.red` chỉ để tô TINT và làm\n * màu chart.\n */\nexport const accentForeground = {\n light: {\n navy: \"#FFFFFF\",\n teal: \"#0E1116\",\n green: \"#0E1116\",\n yellow: \"#0E1116\"\n },\n dark: {\n navy: \"#FFFFFF\",\n teal: \"#0E1116\",\n green: \"#0E1116\",\n yellow: \"#0E1116\"\n }\n} as const;\n\n/** Semantic token của shadcn — mirror khối `:root` / `.dark` trong styles.css. */\nexport const semantic = {\n light: {\n background: \"#FFFFFF\",\n foreground: \"#0E1116\",\n card: \"#FFFFFF\",\n cardForeground: \"#0E1116\",\n popover: \"#FFFFFF\",\n popoverForeground: \"#0E1116\",\n primary: \"#E8B824\",\n primaryForeground: \"#0E1116\",\n /** Bậc INK của brand. Ở bảng MẶC ĐỊNH nó BẰNG `primary`: comitor-ds tô gold cho cả những vai\n * trò mà 1.4.11 đòi 3:1 (rãnh Switch BẬT, gạch active của Tabs) — 1,86:1, đã biết và chấp\n * nhận. Bậc tối #7A5800 nằm ở `highContrast.light.primaryInk`. */\n primaryInk: \"#E8B824\",\n secondary: \"#EDE8D8\",\n secondaryForeground: \"#0E1116\",\n muted: \"#F7F7F8\",\n /** Bậc chữ phụ — giá trị của comitor-ds, bằng đúng `ash[500]`. 3,83:1 trên nền trắng và\n * 3,58:1 trên `muted`, tức dưới AA 4,5:1: đã biết và chấp nhận, bản đạt chuẩn nằm ở\n * `highContrast.light.mutedForeground`. */\n mutedForeground: ash[500],\n accent: \"#FBF5DC\",\n accentForeground: \"#0E1116\",\n /** Nền nút xoá. Chữ trắng trên nó được 4,38:1 — thiếu 0,12 so với AA, đã biết và chấp nhận. */\n destructive: \"#D64545\",\n destructiveForeground: \"#FFFFFF\",\n /** Nền nút xoá lúc HOVER = `destructive` ở 90% trên nền trắng, đúng thứ `hover:bg-red/90`\n * của comitor-ds render. Ghim hex vì `/90` phụ thuộc nền phía sau. */\n destructiveHover: \"#DA5A5A\",\n /** Chữ báo lỗi trên nền trang. comitor-ds viết `text-destructive` cho vai trò này, tức cùng\n * hex với nền — 4,38:1 trên nền trắng. */\n destructiveInk: \"#D64545\",\n /** RANH GIỚI TRANG TRÍ (vạch chia, viền thẻ nghỉ) — 1,16:1, cố ý: 1.4.11 không đòi tương\n * phản cho thứ không mang thông tin. Ranh giới của CONTROL đi qua `controlEdge`. */\n border: \"#EDEEF1\",\n /** Viền ô nhập — comitor-ds cho nó cùng bậc với `border`. 1,16:1, đã biết và chấp nhận. */\n input: \"#EDEEF1\",\n ring: \"#E8B824\",\n /** Ranh giới của control lúc NGHỈ — ở bảng mặc định bằng đúng `input`. */\n controlEdge: \"#EDEEF1\",\n /** Cùng vai trò nhưng ở HOVER/ACTIVE. comitor-ds dùng `hover:border-gray-300` = `ash[300]`. */\n controlEdgeStrong: ash[300],\n /** Nền control khi BẬT/ĐÃ CHỌN (rãnh Switch bật, ô Checkbox đã chọn, chấm Radio). comitor-ds\n * tô gold: 1,86:1 với nền trang và với núm — đã biết và chấp nhận. */\n controlOn: \"#E8B824\",\n /** Núm Switch / chấm Radio — TRẮNG ở cả hai theme, đúng `bg-white` của comitor-ds. */\n controlKnob: \"#FFFFFF\",\n /** DẤU CHECK của Checkbox và chữ trên ngày ĐANG CHỌN của Calendar — tách khỏi `controlKnob`\n * vì trên nền gold SÁNG thì dấu phải là MỰC (10,19:1), còn ở bảng tương phản cao nền là\n * gold-500 TỐI nên dấu lật thành màu nền trang. */\n controlCheck: brandNeutral.ink,\n /** Rãnh Switch khi TẮT — comitor-ds dùng `bg-gray-300` / `dark:bg-gray-700`. */\n switchTrack: ash[300],\n /** Rãnh Slider — comitor-ds dùng `bg-muted`, khác bậc với rãnh Switch. */\n sliderTrack: \"#F7F7F8\",\n /** Button variant `link`. comitor-ds dùng `gold[400]` — 3,15:1, dưới AA, đã biết và chấp nhận. */\n linkInk: gold[400],\n linkInkHover: gold[300],\n sidebar: \"#FAFAF9\",\n sidebarForeground: \"#0E1116\",\n sidebarBorder: \"#EDEEF1\",\n sidebarAccent: \"#FBF5DC\",\n sidebarAccentForeground: \"#0E1116\"\n },\n dark: {\n background: \"#0E1116\",\n foreground: \"#F7F7F8\",\n card: \"#16181D\",\n cardForeground: \"#F7F7F8\",\n popover: \"#16181D\",\n popoverForeground: \"#F7F7F8\",\n primary: \"#F5D060\",\n primaryForeground: \"#0E1116\",\n /** Ở dark `primary` vốn đã là bậc sáng (12,67:1 trên nền `background`) nên ink = chính nó. */\n primaryInk: \"#F5D060\",\n secondary: \"#1E2128\",\n secondaryForeground: \"#F7F7F8\",\n muted: \"#1E2128\",\n /** comitor-ds không khai lại token này ở dark — cùng hex với light. 4,21:1 trên `muted`,\n * dưới AA: đã biết và chấp nhận. */\n mutedForeground: ash[500],\n accent: \"#1E2128\",\n accentForeground: \"#F7F7F8\",\n /** Ghim đúng giá trị của light — comitor-ds dùng chung một hex cho cả hai theme. */\n destructive: \"#D64545\",\n destructiveForeground: \"#FFFFFF\",\n destructiveHover: \"#DA5A5A\",\n /** 4,06:1 trên `card` — cùng hex với nền, đúng `text-destructive` của comitor-ds. */\n destructiveInk: \"#D64545\",\n /** TRANG TRÍ, 1,17:1 trên `background` và 1,10:1 trên `card` — cố ý, xem nhánh light. */\n border: \"#1E2128\",\n /** Viền ô nhập bản dark của comitor-ds — cùng bậc với `border`. */\n input: \"#1E2128\",\n ring: \"#F5D060\",\n controlEdge: \"#1E2128\",\n /** comitor-ds dùng `dark:hover:border-gray-500` = `ash[500]` (lật chiều so với light). */\n controlEdgeStrong: ash[500],\n /** comitor-ds tô `dark:data-[state=checked]:bg-gold-300`, nhưng token `primary` của chính nó\n * ở dark là #F5D060; gói theo token, nên control BẬT ở dark là bậc sáng. */\n controlOn: \"#F5D060\",\n /** TRẮNG ở cả hai theme, đúng `bg-white` của comitor-ds. */\n controlKnob: \"#FFFFFF\",\n /** comitor-ds vẽ dấu check bằng `text-ink` ở CẢ hai theme. */\n controlCheck: brandNeutral.ink,\n switchTrack: ash[700],\n sliderTrack: \"#1E2128\",\n linkInk: gold[400],\n linkInkHover: gold[300],\n sidebar: \"#16181D\",\n sidebarForeground: \"#F7F7F8\",\n sidebarBorder: \"#1E2128\",\n sidebarAccent: \"#1E2128\",\n sidebarAccentForeground: \"#F7F7F8\"\n }\n} as const;\n\n/**\n * BẢNG MÀU THỨ HAI — TƯƠNG PHẢN CAO. Mirror khối `[data-contrast=\"high\"]` /\n * `.dark[data-contrast=\"high\"]` trong styles.css.\n *\n * Chỉ chứa những token KHÁC bảng mặc định, đúng như CSS: hợp lên trên để có bảng đầy đủ.\n *\n * ```ts\n * const mau = { ...semantic.light, ...highContrast.light };\n * ```\n *\n * Bảng mặc định là comitor-ds (bản duyệt, có những cặp dưới ngưỡng — đã liệt kê ở từng token).\n * Bảng này là bảng đã đo, do NGƯỜI DÙNG bật qua `<ContrastProvider>` + `<ContrastToggle>`.\n * `accent` là màu phụ bản sáng dành cho nền tối — bảng mặc định không có, xem `accent.dark`.\n */\nexport const highContrast = {\n light: {\n /** 5,23:1 trên `background` · 4,89:1 trên `muted` (bảng mặc định: 3,83 / 3,58) */\n mutedForeground: \"#686C7A\",\n /** Chữ trắng trên nền này được 5,03:1 (bảng mặc định #D64545 chỉ 4,38:1) */\n destructive: \"#C93B3B\",\n /** = color-mix(destructive, ink 15%) — ĐẬM thêm khi hover, ngược chiều bảng mặc định. */\n destructiveHover: \"#AD3535\",\n /** 7,15:1 trên nền trắng (bảng mặc định dùng chính #D64545, 4,38:1) */\n destructiveInk: accentInk.light.red,\n /** 3,83:1 trên nền trắng (bảng mặc định #EDEEF1 chỉ 1,16:1) */\n input: \"#7E8290\",\n controlEdge: \"#7E8290\",\n controlEdgeStrong: ash[700],\n /** Rãnh ⇄ nền 6,51:1 và rãnh ⇄ núm 6,51:1 (bảng mặc định: 1,86 / 1,86) */\n controlOn: gold[500],\n /** = `background`, nên luôn tương phản đúng chiều với cả rãnh BẬT lẫn rãnh TẮT. */\n controlKnob: \"#FFFFFF\",\n controlCheck: \"#FFFFFF\",\n switchTrack: \"#7E8290\",\n sliderTrack: \"#7E8290\",\n primaryInk: gold[500],\n linkInk: gold[500],\n linkInkHover: gold[600],\n accent: accent.light\n },\n dark: {\n /** 5,70:1 trên `background` · 5,35:1 trên `card` · 4,86:1 trên `muted` */\n mutedForeground: \"#888D9B\",\n destructive: \"#C93B3B\",\n destructiveHover: \"#AD3535\",\n destructiveInk: \"#F87171\",\n /** Ghim một giá trị cho cả hai theme — 4,94:1 trên `background` */\n input: \"#7E8290\",\n controlEdge: \"#7E8290\",\n controlEdgeStrong: ash[300],\n /** 12,67:1 với nền trang VÀ với `controlKnob` (#0E1116) */\n controlOn: \"#F5D060\",\n controlKnob: \"#0E1116\",\n controlCheck: \"#0E1116\",\n switchTrack: \"#7E8290\",\n sliderTrack: \"#7E8290\",\n primaryInk: \"#F5D060\",\n linkInk: gold[200],\n linkInkHover: gold[100],\n /** Màu phụ bản SÁNG cho nền tối — bảng mặc định không có bản dark cho nhóm này. */\n accent: {\n navy: \"#0F1E3D\",\n teal: \"#2DD4BF\",\n red: \"#F87171\",\n green: \"#4ADE80\",\n yellow: \"#FACC15\"\n }\n }\n} as const;\n\n/**\n * Alias trạng thái — success/warning/info trỏ vào màu phụ, destructive giữ nguyên 2 chế độ.\n *\n * Ba lớp KHÁC nhau, đừng gộp:\n * • `destructive` — màu NỀN (nút xoá): #D64545 ở bảng mặc định (chữ trắng 4,38:1, dưới AA và đã\n * chấp nhận), #C93B3B ở bảng tương phản cao (5,03:1 ✓);\n * • `destructiveForeground` (#FFFFFF) — chữ NẰM TRÊN nền đó;\n * • `destructiveInk` — màu CHỮ đỏ trên nền trang (dòng lỗi). Bảng mặc định cho nó cùng hex với\n * nền (đúng `text-destructive` của comitor-ds); bảng tương phản cao tách thành bậc tối riêng.\n *\n * `successForeground` / `warningForeground` / `infoForeground` là MỰC ở CẢ hai theme (không phải\n * trắng ở light rồi lật ở dark như bản 0.1.0): ba nền trạng thái đều là sắc sáng.\n * success mực 6,04:1 (light) · 10,85:1 (dark) [trắng chỉ 3,13 / 1,74:1 ✗]\n * info mực 4,56:1 (light) · 10,16:1 (dark) [trắng chỉ 4,14 / 1,86:1 ✗]\n * warning mực 11,92:1 (light) · 12,35:1 (dark) [trắng chỉ 1,59 / 1,53:1 ✗]\n * ⚠ `info` ở light là cặp chặt nhất gói (4,56:1, dư 0,06) — đổi `accent.light.teal` là phải đo lại.\n */\nexport const status = {\n light: {\n success: accent.light.green,\n successForeground: \"#0E1116\",\n warning: accent.light.yellow,\n warningForeground: \"#0E1116\",\n info: accent.light.teal,\n infoForeground: \"#0E1116\",\n destructive: \"#D64545\",\n destructiveForeground: \"#FFFFFF\",\n successInk: accentInk.light.green,\n warningInk: accentInk.light.yellow,\n infoInk: accentInk.light.teal,\n destructiveInk: accentInk.light.red\n },\n dark: {\n success: accent.dark.green,\n successForeground: \"#0E1116\",\n warning: accent.dark.yellow,\n warningForeground: \"#0E1116\",\n info: accent.dark.teal,\n infoForeground: \"#0E1116\",\n destructive: \"#D64545\",\n destructiveForeground: \"#FFFFFF\",\n successInk: accentInk.dark.green,\n warningInk: accentInk.dark.yellow,\n infoInk: accentInk.dark.teal,\n destructiveInk: accentInk.dark.red\n }\n} as const;\n\n/** Bảng màu biểu đồ (chart-1…chart-5). Thứ tự = thứ tự series mặc định. */\nexport const chart = {\n light: [gold[300], accent.light.teal, accent.light.navy, accent.light.green, accent.light.red],\n dark: [gold[200], accent.dark.teal, accentInk.dark.navy, accent.dark.green, accent.dark.red]\n} as const;\n\n/**\n * Màu avatar chữ cái (hex đục) cho nơi KHÔNG có Tailwind: canvas, email HTML, PDF.\n *\n * ⚠ KHÔNG phải bảng màu thứ hai. Bảng tone DUY NHẤT của cả gói nằm ở `lib/avatar-tone.ts`, mỗi\n * tone mang cả chuỗi class (cho DOM) lẫn công thức hex tương ứng; ở đây chỉ nạp bảng màu vào công\n * thức đó. Web và email vì vậy dùng chung một thứ tự tone, một hàm băm, một cách chuẩn hoá tên —\n * không còn hai bảng để lệch nhau.\n */\nconst avatarTonePalette = {\n light: {\n gold,\n ash,\n brandNeutral,\n accent: accent.light,\n accentInk: accentInk.light,\n card: semantic.light.card\n },\n dark: {\n gold,\n ash,\n brandNeutral,\n accent: accent.dark,\n accentInk: accentInk.dark,\n card: semantic.dark.card\n }\n} satisfies Record<ThemeMode, AvatarTonePalette>;\n\n/**\n * Cặp nền/chữ (hex) của avatar cho một tên, theo theme.\n *\n * Tên hàm nói đúng thứ nó trả về: `...Colors` = hex (canvas/email/PDF), còn bản trả về chuỗi\n * class Tailwind cho DOM là `getAvatarToneClasses` ở `@comitor/ui`. Cùng một tên người luôn ra\n * cùng một tone ở cả hai đường vì chỉ số do MỘT hàm tính (`getAvatarToneIndex`).\n */\nexport function getAvatarToneColors(name: string, mode: ThemeMode = \"light\"): AvatarToneColors {\n // `noUncheckedIndexedAccess` bật → phải có nhánh lùi, dù chỉ số luôn nằm trong [0, 8).\n const tone = AVATAR_TONES[getAvatarToneIndex(name)] ?? AVATAR_TONES[0];\n return tone[mode](avatarTonePalette[mode]);\n}\n\nexport type { AvatarToneColors };\nexport { getAvatarToneIndex };\n\n/** Số đo khung ứng dụng — mirror --sidebar-width / --sidebar-width-icon / --header-height. */\nexport const layout = {\n /** px — --header-height 3.5rem */\n headerHeight: 56,\n /** px — --sidebar-width 16rem */\n sidebarWidth: 256,\n /** px — --sidebar-width-icon 3.5rem */\n sidebarCollapsedWidth: 56,\n /** px — --radius 0.375rem */\n radius: 6,\n breakpoints: { mobile: 768, tablet: 1024, desktop: 1280 },\n /** px — kích thước tối thiểu của vùng chạm trên mobile (WCAG 2.5.5) */\n minTapTarget: 44\n} as const;\n\n/** Font stack — app phải tự nạp Inter (subsets latin + vietnamese) và gán --font-inter. */\nexport const typography = {\n fontSans: '\"Inter\", system-ui, sans-serif',\n fontMono: '\"Geist Mono\", ui-monospace, monospace'\n} as const;\n\nexport type ThemeMode = \"light\" | \"dark\";\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comitor/ui",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Comitor design system — Shadcn/UI tùy biến theo brand Comitor + component dùng chung cho hệ sinh thái SaaS (Tasks, Chat, CRM, HR…)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -66,8 +66,9 @@
66
66
  "test:cong-a11y": "node scripts/a11y/tu-kiem.mjs",
67
67
  "test:nav-active": "node scripts/kiem-nav-active.mjs",
68
68
  "verify:directives": "node scripts/verify-directives.mjs",
69
+ "smoke:entries": "node scripts/smoke-entries.mjs",
69
70
  "check:exports": "publint --strict && attw --pack . --profile esm-only --exclude-entrypoints styles.css",
70
- "prepublishOnly": "pnpm run typecheck && pnpm run build && pnpm run verify:directives && pnpm run test:nav-active && pnpm run test:cong-a11y && pnpm run lint:a11y"
71
+ "prepublishOnly": "pnpm run typecheck && pnpm run build && pnpm run verify:directives && pnpm run smoke:entries && pnpm run check:exports && pnpm run test:nav-active && pnpm run test:cong-a11y && pnpm run lint:a11y"
71
72
  },
72
73
  "peerDependencies": {
73
74
  "lucide-react": ">=0.540.0",