@ng-cn/core 1.0.10 → 1.0.12

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 (392) hide show
  1. package/package.json +3 -2
  2. package/src/app/lib/components/ui/accordion/accordion-content.component.ts +53 -0
  3. package/src/app/lib/components/ui/accordion/accordion-context.ts +33 -0
  4. package/src/app/lib/components/ui/accordion/accordion-item.component.ts +86 -0
  5. package/src/app/lib/components/ui/accordion/accordion-trigger.component.ts +73 -0
  6. package/src/app/lib/components/ui/accordion/accordion.component.ts +197 -0
  7. package/src/app/lib/components/ui/accordion/index.ts +15 -0
  8. package/src/app/lib/components/ui/alert/alert-description.component.ts +33 -0
  9. package/src/app/lib/components/ui/alert/alert-title.component.ts +30 -0
  10. package/src/app/lib/components/ui/alert/alert-variants.ts +23 -0
  11. package/src/app/lib/components/ui/alert/alert.component.ts +50 -0
  12. package/src/app/lib/components/ui/alert/index.ts +5 -0
  13. package/src/app/lib/components/ui/alert-dialog/alert-dialog-action.component.ts +44 -0
  14. package/src/app/lib/components/ui/alert-dialog/alert-dialog-cancel.component.ts +45 -0
  15. package/src/app/lib/components/ui/alert-dialog/alert-dialog-content.component.ts +146 -0
  16. package/src/app/lib/components/ui/alert-dialog/alert-dialog-context.ts +14 -0
  17. package/src/app/lib/components/ui/alert-dialog/alert-dialog-description.component.ts +37 -0
  18. package/src/app/lib/components/ui/alert-dialog/alert-dialog-footer.component.ts +35 -0
  19. package/src/app/lib/components/ui/alert-dialog/alert-dialog-header.component.ts +35 -0
  20. package/src/app/lib/components/ui/alert-dialog/alert-dialog-title.component.ts +37 -0
  21. package/src/app/lib/components/ui/alert-dialog/alert-dialog-trigger.component.ts +44 -0
  22. package/src/app/lib/components/ui/alert-dialog/alert-dialog.component.ts +91 -0
  23. package/src/app/lib/components/ui/alert-dialog/index.ts +11 -0
  24. package/src/app/lib/components/ui/aspect-ratio/aspect-ratio.component.ts +63 -0
  25. package/src/app/lib/components/ui/aspect-ratio/index.ts +1 -0
  26. package/src/app/lib/components/ui/avatar/avatar-fallback.component.ts +34 -0
  27. package/src/app/lib/components/ui/avatar/avatar-image.component.ts +31 -0
  28. package/src/app/lib/components/ui/avatar/avatar.component.ts +37 -0
  29. package/src/app/lib/components/ui/avatar/index.ts +5 -0
  30. package/src/app/lib/components/ui/avatar/ui-avatar.component.ts +52 -0
  31. package/src/app/lib/components/ui/badge/badge-variants.ts +28 -0
  32. package/src/app/lib/components/ui/badge/badge.component.ts +50 -0
  33. package/src/app/lib/components/ui/badge/index.ts +3 -0
  34. package/src/app/lib/components/ui/breadcrumb/breadcrumb-ellipsis.component.ts +48 -0
  35. package/src/app/lib/components/ui/breadcrumb/breadcrumb-item.component.ts +28 -0
  36. package/src/app/lib/components/ui/breadcrumb/breadcrumb-link.component.ts +32 -0
  37. package/src/app/lib/components/ui/breadcrumb/breadcrumb-list.component.ts +31 -0
  38. package/src/app/lib/components/ui/breadcrumb/breadcrumb-page.component.ts +31 -0
  39. package/src/app/lib/components/ui/breadcrumb/breadcrumb-separator.component.ts +47 -0
  40. package/src/app/lib/components/ui/breadcrumb/breadcrumb.component.ts +43 -0
  41. package/src/app/lib/components/ui/breadcrumb/index.ts +8 -0
  42. package/src/app/lib/components/ui/button/button-variants.ts +38 -0
  43. package/src/app/lib/components/ui/button/button.component.ts +103 -0
  44. package/src/app/lib/components/ui/button/index.ts +3 -0
  45. package/src/app/lib/components/ui/button-group/button-group-variants.ts +24 -0
  46. package/src/app/lib/components/ui/button-group/button-group.component.ts +57 -0
  47. package/src/app/lib/components/ui/button-group/index.ts +6 -0
  48. package/src/app/lib/components/ui/calendar/calendar.component.ts +368 -0
  49. package/src/app/lib/components/ui/calendar/index.ts +1 -0
  50. package/src/app/lib/components/ui/card/card-action.component.ts +39 -0
  51. package/src/app/lib/components/ui/card/card-content.component.ts +31 -0
  52. package/src/app/lib/components/ui/card/card-description.component.ts +31 -0
  53. package/src/app/lib/components/ui/card/card-footer.component.ts +34 -0
  54. package/src/app/lib/components/ui/card/card-header.component.ts +37 -0
  55. package/src/app/lib/components/ui/card/card-title.component.ts +31 -0
  56. package/src/app/lib/components/ui/card/card.component.ts +41 -0
  57. package/src/app/lib/components/ui/card/index.ts +8 -0
  58. package/src/app/lib/components/ui/carousel/carousel-content.component.ts +38 -0
  59. package/src/app/lib/components/ui/carousel/carousel-context.ts +18 -0
  60. package/src/app/lib/components/ui/carousel/carousel-item.component.ts +32 -0
  61. package/src/app/lib/components/ui/carousel/carousel-next.component.ts +54 -0
  62. package/src/app/lib/components/ui/carousel/carousel-previous.component.ts +54 -0
  63. package/src/app/lib/components/ui/carousel/carousel.component.ts +125 -0
  64. package/src/app/lib/components/ui/carousel/index.ts +7 -0
  65. package/src/app/lib/components/ui/chart/chart-container.component.ts +81 -0
  66. package/src/app/lib/components/ui/chart/chart-context.ts +38 -0
  67. package/src/app/lib/components/ui/chart/chart-legend-content.component.ts +51 -0
  68. package/src/app/lib/components/ui/chart/chart-legend.component.ts +28 -0
  69. package/src/app/lib/components/ui/chart/chart-tooltip-content.component.ts +37 -0
  70. package/src/app/lib/components/ui/chart/chart-tooltip.component.ts +28 -0
  71. package/src/app/lib/components/ui/chart/chart.component.ts +308 -0
  72. package/src/app/lib/components/ui/chart/index.ts +16 -0
  73. package/src/app/lib/components/ui/checkbox/checkbox.component.ts +203 -0
  74. package/src/app/lib/components/ui/checkbox/index.ts +1 -0
  75. package/src/app/lib/components/ui/collapsible/collapsible-content.component.ts +58 -0
  76. package/src/app/lib/components/ui/collapsible/collapsible-context.ts +17 -0
  77. package/src/app/lib/components/ui/collapsible/collapsible-trigger.component.ts +56 -0
  78. package/src/app/lib/components/ui/collapsible/collapsible.component.ts +102 -0
  79. package/src/app/lib/components/ui/collapsible/index.ts +5 -0
  80. package/src/app/lib/components/ui/combobox/combobox-content.component.ts +59 -0
  81. package/src/app/lib/components/ui/combobox/combobox-context.ts +49 -0
  82. package/src/app/lib/components/ui/combobox/combobox-empty.component.ts +35 -0
  83. package/src/app/lib/components/ui/combobox/combobox-group.component.ts +32 -0
  84. package/src/app/lib/components/ui/combobox/combobox-input.component.ts +89 -0
  85. package/src/app/lib/components/ui/combobox/combobox-item.component.ts +129 -0
  86. package/src/app/lib/components/ui/combobox/combobox-list.component.ts +40 -0
  87. package/src/app/lib/components/ui/combobox/combobox-trigger.component.ts +53 -0
  88. package/src/app/lib/components/ui/combobox/combobox-value.component.ts +47 -0
  89. package/src/app/lib/components/ui/combobox/combobox.component.ts +290 -0
  90. package/src/app/lib/components/ui/combobox/index.ts +15 -0
  91. package/src/app/lib/components/ui/command/command-context.ts +24 -0
  92. package/src/app/lib/components/ui/command/command-dialog.component.ts +69 -0
  93. package/src/app/lib/components/ui/command/command-empty.component.ts +23 -0
  94. package/src/app/lib/components/ui/command/command-group.component.ts +66 -0
  95. package/src/app/lib/components/ui/command/command-input.component.ts +137 -0
  96. package/src/app/lib/components/ui/command/command-item.component.ts +148 -0
  97. package/src/app/lib/components/ui/command/command-list.component.ts +30 -0
  98. package/src/app/lib/components/ui/command/command-separator.component.ts +23 -0
  99. package/src/app/lib/components/ui/command/command-shortcut.component.ts +23 -0
  100. package/src/app/lib/components/ui/command/command.component.ts +105 -0
  101. package/src/app/lib/components/ui/command/index.ts +11 -0
  102. package/src/app/lib/components/ui/context-menu/context-menu-checkbox-item.component.ts +68 -0
  103. package/src/app/lib/components/ui/context-menu/context-menu-content.component.ts +213 -0
  104. package/src/app/lib/components/ui/context-menu/context-menu-context.ts +17 -0
  105. package/src/app/lib/components/ui/context-menu/context-menu-item.component.ts +63 -0
  106. package/src/app/lib/components/ui/context-menu/context-menu-label.component.ts +30 -0
  107. package/src/app/lib/components/ui/context-menu/context-menu-radio-group.component.ts +36 -0
  108. package/src/app/lib/components/ui/context-menu/context-menu-radio-item.component.ts +71 -0
  109. package/src/app/lib/components/ui/context-menu/context-menu-separator.component.ts +24 -0
  110. package/src/app/lib/components/ui/context-menu/context-menu-shortcut.component.ts +23 -0
  111. package/src/app/lib/components/ui/context-menu/context-menu-sub-content.component.ts +51 -0
  112. package/src/app/lib/components/ui/context-menu/context-menu-sub-trigger.component.ts +50 -0
  113. package/src/app/lib/components/ui/context-menu/context-menu-sub.component.ts +31 -0
  114. package/src/app/lib/components/ui/context-menu/context-menu-trigger.component.ts +51 -0
  115. package/src/app/lib/components/ui/context-menu/context-menu.component.ts +27 -0
  116. package/src/app/lib/components/ui/context-menu/index.ts +15 -0
  117. package/src/app/lib/components/ui/data-table/data-table-content.component.ts +226 -0
  118. package/src/app/lib/components/ui/data-table/data-table-context.ts +49 -0
  119. package/src/app/lib/components/ui/data-table/data-table-pagination.component.ts +138 -0
  120. package/src/app/lib/components/ui/data-table/data-table-search.component.ts +52 -0
  121. package/src/app/lib/components/ui/data-table/data-table-toolbar.component.ts +27 -0
  122. package/src/app/lib/components/ui/data-table/data-table-view-options.component.ts +92 -0
  123. package/src/app/lib/components/ui/data-table/data-table.component.ts +131 -0
  124. package/src/app/lib/components/ui/data-table/index.ts +16 -0
  125. package/src/app/lib/components/ui/date-picker/date-picker.component.ts +94 -0
  126. package/src/app/lib/components/ui/date-picker/index.ts +1 -0
  127. package/src/app/lib/components/ui/dialog/dialog-close.component.ts +31 -0
  128. package/src/app/lib/components/ui/dialog/dialog-content.component.ts +177 -0
  129. package/src/app/lib/components/ui/dialog/dialog-context.ts +15 -0
  130. package/src/app/lib/components/ui/dialog/dialog-description.component.ts +34 -0
  131. package/src/app/lib/components/ui/dialog/dialog-footer.component.ts +28 -0
  132. package/src/app/lib/components/ui/dialog/dialog-header.component.ts +28 -0
  133. package/src/app/lib/components/ui/dialog/dialog-title.component.ts +34 -0
  134. package/src/app/lib/components/ui/dialog/dialog-trigger.component.ts +38 -0
  135. package/src/app/lib/components/ui/dialog/dialog.component.ts +87 -0
  136. package/src/app/lib/components/ui/dialog/index.ts +10 -0
  137. package/src/app/lib/components/ui/drawer/drawer-close.component.ts +31 -0
  138. package/src/app/lib/components/ui/drawer/drawer-content.component.ts +143 -0
  139. package/src/app/lib/components/ui/drawer/drawer-context.ts +17 -0
  140. package/src/app/lib/components/ui/drawer/drawer-description.component.ts +33 -0
  141. package/src/app/lib/components/ui/drawer/drawer-footer.component.ts +28 -0
  142. package/src/app/lib/components/ui/drawer/drawer-header.component.ts +28 -0
  143. package/src/app/lib/components/ui/drawer/drawer-title.component.ts +33 -0
  144. package/src/app/lib/components/ui/drawer/drawer-trigger.component.ts +38 -0
  145. package/src/app/lib/components/ui/drawer/drawer.component.ts +93 -0
  146. package/src/app/lib/components/ui/drawer/index.ts +10 -0
  147. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.component.ts +68 -0
  148. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-content.component.ts +234 -0
  149. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-context.ts +15 -0
  150. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-group.component.ts +15 -0
  151. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-item.component.ts +56 -0
  152. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-label.component.ts +30 -0
  153. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.component.ts +42 -0
  154. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.component.ts +71 -0
  155. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-separator.component.ts +24 -0
  156. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.component.ts +23 -0
  157. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.component.ts +51 -0
  158. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.component.ts +53 -0
  159. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub.component.ts +31 -0
  160. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-trigger.component.ts +45 -0
  161. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu.component.ts +32 -0
  162. package/src/app/lib/components/ui/dropdown-menu/index.ts +16 -0
  163. package/src/app/lib/components/ui/empty/empty-action.component.ts +28 -0
  164. package/src/app/lib/components/ui/empty/empty-description.component.ts +31 -0
  165. package/src/app/lib/components/ui/empty/empty-icon.component.ts +31 -0
  166. package/src/app/lib/components/ui/empty/empty-title.component.ts +28 -0
  167. package/src/app/lib/components/ui/empty/empty.component.ts +53 -0
  168. package/src/app/lib/components/ui/empty/index.ts +6 -0
  169. package/src/app/lib/components/ui/form/form-context.ts +34 -0
  170. package/src/app/lib/components/ui/form/form-control.component.ts +137 -0
  171. package/src/app/lib/components/ui/form/form-description.component.ts +37 -0
  172. package/src/app/lib/components/ui/form/form-field.component.ts +84 -0
  173. package/src/app/lib/components/ui/form/form-item.component.ts +42 -0
  174. package/src/app/lib/components/ui/form/form-label.component.ts +58 -0
  175. package/src/app/lib/components/ui/form/form-message.component.ts +107 -0
  176. package/src/app/lib/components/ui/form/form.component.ts +123 -0
  177. package/src/app/lib/components/ui/form/index.ts +17 -0
  178. package/src/app/lib/components/ui/hover-card/hover-card-content.component.ts +203 -0
  179. package/src/app/lib/components/ui/hover-card/hover-card-context.ts +25 -0
  180. package/src/app/lib/components/ui/hover-card/hover-card-trigger.component.ts +160 -0
  181. package/src/app/lib/components/ui/hover-card/hover-card.component.ts +147 -0
  182. package/src/app/lib/components/ui/hover-card/index.ts +13 -0
  183. package/src/app/lib/components/ui/index.ts +551 -0
  184. package/src/app/lib/components/ui/input/index.ts +1 -0
  185. package/src/app/lib/components/ui/input/input.component.ts +165 -0
  186. package/src/app/lib/components/ui/input-group/index.ts +4 -0
  187. package/src/app/lib/components/ui/input-group/input-group-addon.component.ts +43 -0
  188. package/src/app/lib/components/ui/input-group/input-group-input.component.ts +33 -0
  189. package/src/app/lib/components/ui/input-group/input-group.component.ts +53 -0
  190. package/src/app/lib/components/ui/input-otp/index.ts +14 -0
  191. package/src/app/lib/components/ui/input-otp/input-otp-context.ts +31 -0
  192. package/src/app/lib/components/ui/input-otp/input-otp-group.component.ts +23 -0
  193. package/src/app/lib/components/ui/input-otp/input-otp-separator.component.ts +31 -0
  194. package/src/app/lib/components/ui/input-otp/input-otp-slot.component.ts +67 -0
  195. package/src/app/lib/components/ui/input-otp/input-otp.component.ts +240 -0
  196. package/src/app/lib/components/ui/kbd/index.ts +3 -0
  197. package/src/app/lib/components/ui/kbd/kbd-variants.ts +23 -0
  198. package/src/app/lib/components/ui/kbd/kbd.component.ts +50 -0
  199. package/src/app/lib/components/ui/label/index.ts +1 -0
  200. package/src/app/lib/components/ui/label/label.component.ts +139 -0
  201. package/src/app/lib/components/ui/menubar/index.ts +26 -0
  202. package/src/app/lib/components/ui/menubar/menubar-checkbox-item.component.ts +66 -0
  203. package/src/app/lib/components/ui/menubar/menubar-content.component.ts +236 -0
  204. package/src/app/lib/components/ui/menubar/menubar-context.ts +63 -0
  205. package/src/app/lib/components/ui/menubar/menubar-item.component.ts +60 -0
  206. package/src/app/lib/components/ui/menubar/menubar-label.component.ts +30 -0
  207. package/src/app/lib/components/ui/menubar/menubar-menu.component.ts +40 -0
  208. package/src/app/lib/components/ui/menubar/menubar-radio-group.component.ts +36 -0
  209. package/src/app/lib/components/ui/menubar/menubar-radio-item.component.ts +66 -0
  210. package/src/app/lib/components/ui/menubar/menubar-separator.component.ts +24 -0
  211. package/src/app/lib/components/ui/menubar/menubar-shortcut.component.ts +23 -0
  212. package/src/app/lib/components/ui/menubar/menubar-sub-content.component.ts +51 -0
  213. package/src/app/lib/components/ui/menubar/menubar-sub-trigger.component.ts +50 -0
  214. package/src/app/lib/components/ui/menubar/menubar-sub.component.ts +29 -0
  215. package/src/app/lib/components/ui/menubar/menubar-trigger.component.ts +132 -0
  216. package/src/app/lib/components/ui/menubar/menubar.component.ts +158 -0
  217. package/src/app/lib/components/ui/native-select/index.ts +6 -0
  218. package/src/app/lib/components/ui/native-select/native-select-variants.ts +23 -0
  219. package/src/app/lib/components/ui/native-select/native-select.component.ts +74 -0
  220. package/src/app/lib/components/ui/navigation-menu/index.ts +21 -0
  221. package/src/app/lib/components/ui/navigation-menu/navigation-menu-content.component.ts +66 -0
  222. package/src/app/lib/components/ui/navigation-menu/navigation-menu-context.ts +55 -0
  223. package/src/app/lib/components/ui/navigation-menu/navigation-menu-indicator.component.ts +28 -0
  224. package/src/app/lib/components/ui/navigation-menu/navigation-menu-item.component.ts +29 -0
  225. package/src/app/lib/components/ui/navigation-menu/navigation-menu-link.component.ts +43 -0
  226. package/src/app/lib/components/ui/navigation-menu/navigation-menu-list.component.ts +26 -0
  227. package/src/app/lib/components/ui/navigation-menu/navigation-menu-trigger-style.ts +7 -0
  228. package/src/app/lib/components/ui/navigation-menu/navigation-menu-trigger.component.ts +58 -0
  229. package/src/app/lib/components/ui/navigation-menu/navigation-menu-viewport.component.ts +26 -0
  230. package/src/app/lib/components/ui/navigation-menu/navigation-menu.component.ts +149 -0
  231. package/src/app/lib/components/ui/pagination/index.ts +8 -0
  232. package/src/app/lib/components/ui/pagination/pagination-content.component.ts +28 -0
  233. package/src/app/lib/components/ui/pagination/pagination-ellipsis.component.ts +47 -0
  234. package/src/app/lib/components/ui/pagination/pagination-item.component.ts +28 -0
  235. package/src/app/lib/components/ui/pagination/pagination-link.component.ts +46 -0
  236. package/src/app/lib/components/ui/pagination/pagination-next.component.ts +54 -0
  237. package/src/app/lib/components/ui/pagination/pagination-previous.component.ts +54 -0
  238. package/src/app/lib/components/ui/pagination/pagination.component.ts +48 -0
  239. package/src/app/lib/components/ui/popover/index.ts +14 -0
  240. package/src/app/lib/components/ui/popover/popover-anchor.component.ts +64 -0
  241. package/src/app/lib/components/ui/popover/popover-content.component.ts +231 -0
  242. package/src/app/lib/components/ui/popover/popover-context.ts +29 -0
  243. package/src/app/lib/components/ui/popover/popover-trigger.component.ts +100 -0
  244. package/src/app/lib/components/ui/popover/popover.component.ts +163 -0
  245. package/src/app/lib/components/ui/progress/index.ts +6 -0
  246. package/src/app/lib/components/ui/progress/progress.component.ts +212 -0
  247. package/src/app/lib/components/ui/radio-group/index.ts +10 -0
  248. package/src/app/lib/components/ui/radio-group/radio-group-context.ts +38 -0
  249. package/src/app/lib/components/ui/radio-group/radio-group-item.component.ts +298 -0
  250. package/src/app/lib/components/ui/radio-group/radio-group.component.ts +275 -0
  251. package/src/app/lib/components/ui/resizable/index.ts +5 -0
  252. package/src/app/lib/components/ui/resizable/resizable-context.ts +14 -0
  253. package/src/app/lib/components/ui/resizable/resizable-handle.component.ts +232 -0
  254. package/src/app/lib/components/ui/resizable/resizable-panel-group.component.ts +140 -0
  255. package/src/app/lib/components/ui/resizable/resizable-panel.component.ts +77 -0
  256. package/src/app/lib/components/ui/scroll-area/index.ts +8 -0
  257. package/src/app/lib/components/ui/scroll-area/scroll-area.component.ts +126 -0
  258. package/src/app/lib/components/ui/scroll-area/scroll-bar.component.ts +93 -0
  259. package/src/app/lib/components/ui/segmented/index.ts +13 -0
  260. package/src/app/lib/components/ui/segmented/segmented-context.ts +11 -0
  261. package/src/app/lib/components/ui/segmented/segmented-item.component.ts +72 -0
  262. package/src/app/lib/components/ui/segmented/segmented-variants.ts +40 -0
  263. package/src/app/lib/components/ui/segmented/segmented.component.ts +99 -0
  264. package/src/app/lib/components/ui/select/index.ts +19 -0
  265. package/src/app/lib/components/ui/select/select-content.component.ts +97 -0
  266. package/src/app/lib/components/ui/select/select-context.ts +53 -0
  267. package/src/app/lib/components/ui/select/select-group.component.ts +56 -0
  268. package/src/app/lib/components/ui/select/select-item.component.ts +163 -0
  269. package/src/app/lib/components/ui/select/select-label.component.ts +32 -0
  270. package/src/app/lib/components/ui/select/select-separator.component.ts +34 -0
  271. package/src/app/lib/components/ui/select/select-trigger.component.ts +164 -0
  272. package/src/app/lib/components/ui/select/select-value.component.ts +49 -0
  273. package/src/app/lib/components/ui/select/select.component.ts +263 -0
  274. package/src/app/lib/components/ui/separator/index.ts +6 -0
  275. package/src/app/lib/components/ui/separator/separator.component.ts +128 -0
  276. package/src/app/lib/components/ui/sheet/index.ts +11 -0
  277. package/src/app/lib/components/ui/sheet/sheet-close.component.ts +32 -0
  278. package/src/app/lib/components/ui/sheet/sheet-content.component.ts +157 -0
  279. package/src/app/lib/components/ui/sheet/sheet-context.ts +15 -0
  280. package/src/app/lib/components/ui/sheet/sheet-description.component.ts +34 -0
  281. package/src/app/lib/components/ui/sheet/sheet-footer.component.ts +28 -0
  282. package/src/app/lib/components/ui/sheet/sheet-header.component.ts +28 -0
  283. package/src/app/lib/components/ui/sheet/sheet-title.component.ts +34 -0
  284. package/src/app/lib/components/ui/sheet/sheet-trigger.component.ts +38 -0
  285. package/src/app/lib/components/ui/sheet/sheet-variants.ts +22 -0
  286. package/src/app/lib/components/ui/sheet/sheet.component.ts +97 -0
  287. package/src/app/lib/components/ui/sidebar/index.ts +41 -0
  288. package/src/app/lib/components/ui/sidebar/sidebar-content.component.ts +31 -0
  289. package/src/app/lib/components/ui/sidebar/sidebar-context.ts +33 -0
  290. package/src/app/lib/components/ui/sidebar/sidebar-footer.component.ts +28 -0
  291. package/src/app/lib/components/ui/sidebar/sidebar-group-action.component.ts +33 -0
  292. package/src/app/lib/components/ui/sidebar/sidebar-group-content.component.ts +28 -0
  293. package/src/app/lib/components/ui/sidebar/sidebar-group-label.component.ts +32 -0
  294. package/src/app/lib/components/ui/sidebar/sidebar-group.component.ts +28 -0
  295. package/src/app/lib/components/ui/sidebar/sidebar-header.component.ts +28 -0
  296. package/src/app/lib/components/ui/sidebar/sidebar-input.component.ts +31 -0
  297. package/src/app/lib/components/ui/sidebar/sidebar-inset.component.ts +31 -0
  298. package/src/app/lib/components/ui/sidebar/sidebar-menu-action.component.ts +56 -0
  299. package/src/app/lib/components/ui/sidebar/sidebar-menu-badge.component.ts +42 -0
  300. package/src/app/lib/components/ui/sidebar/sidebar-menu-button.component.ts +64 -0
  301. package/src/app/lib/components/ui/sidebar/sidebar-menu-item.component.ts +32 -0
  302. package/src/app/lib/components/ui/sidebar/sidebar-menu-skeleton.component.ts +39 -0
  303. package/src/app/lib/components/ui/sidebar/sidebar-menu-sub-button.component.ts +59 -0
  304. package/src/app/lib/components/ui/sidebar/sidebar-menu-sub-item.component.ts +25 -0
  305. package/src/app/lib/components/ui/sidebar/sidebar-menu-sub.component.ts +32 -0
  306. package/src/app/lib/components/ui/sidebar/sidebar-menu.component.ts +31 -0
  307. package/src/app/lib/components/ui/sidebar/sidebar-provider.component.ts +141 -0
  308. package/src/app/lib/components/ui/sidebar/sidebar-rail.component.ts +47 -0
  309. package/src/app/lib/components/ui/sidebar/sidebar-route-active.service.ts +124 -0
  310. package/src/app/lib/components/ui/sidebar/sidebar-separator.component.ts +28 -0
  311. package/src/app/lib/components/ui/sidebar/sidebar-trigger.component.ts +57 -0
  312. package/src/app/lib/components/ui/sidebar/sidebar.component.ts +130 -0
  313. package/src/app/lib/components/ui/skeleton/index.ts +1 -0
  314. package/src/app/lib/components/ui/skeleton/skeleton.component.ts +52 -0
  315. package/src/app/lib/components/ui/slider/index.ts +6 -0
  316. package/src/app/lib/components/ui/slider/slider.component.ts +477 -0
  317. package/src/app/lib/components/ui/spinner/index.ts +3 -0
  318. package/src/app/lib/components/ui/spinner/spinner-variants.ts +32 -0
  319. package/src/app/lib/components/ui/spinner/spinner.component.ts +77 -0
  320. package/src/app/lib/components/ui/switch/index.ts +6 -0
  321. package/src/app/lib/components/ui/switch/switch.component.ts +282 -0
  322. package/src/app/lib/components/ui/table/index.ts +9 -0
  323. package/src/app/lib/components/ui/table/table-body.component.ts +28 -0
  324. package/src/app/lib/components/ui/table/table-caption.component.ts +28 -0
  325. package/src/app/lib/components/ui/table/table-cell.component.ts +31 -0
  326. package/src/app/lib/components/ui/table/table-footer.component.ts +28 -0
  327. package/src/app/lib/components/ui/table/table-head.component.ts +36 -0
  328. package/src/app/lib/components/ui/table/table-header.component.ts +28 -0
  329. package/src/app/lib/components/ui/table/table-row.component.ts +34 -0
  330. package/src/app/lib/components/ui/table/table.component.ts +52 -0
  331. package/src/app/lib/components/ui/tabs/index.ts +14 -0
  332. package/src/app/lib/components/ui/tabs/tabs-content.component.ts +132 -0
  333. package/src/app/lib/components/ui/tabs/tabs-context.ts +33 -0
  334. package/src/app/lib/components/ui/tabs/tabs-list.component.ts +228 -0
  335. package/src/app/lib/components/ui/tabs/tabs-trigger.component.ts +167 -0
  336. package/src/app/lib/components/ui/tabs/tabs.component.ts +203 -0
  337. package/src/app/lib/components/ui/textarea/index.ts +1 -0
  338. package/src/app/lib/components/ui/textarea/textarea.component.ts +44 -0
  339. package/src/app/lib/components/ui/toast/index.ts +16 -0
  340. package/src/app/lib/components/ui/toast/toast-action.component.ts +77 -0
  341. package/src/app/lib/components/ui/toast/toast-description.component.ts +52 -0
  342. package/src/app/lib/components/ui/toast/toast-title.component.ts +52 -0
  343. package/src/app/lib/components/ui/toast/toast-variants.ts +24 -0
  344. package/src/app/lib/components/ui/toast/toast.component.ts +177 -0
  345. package/src/app/lib/components/ui/toast/toast.service.ts +202 -0
  346. package/src/app/lib/components/ui/toast/toaster.component.ts +128 -0
  347. package/src/app/lib/components/ui/toggle/index.ts +6 -0
  348. package/src/app/lib/components/ui/toggle/toggle-variants.ts +30 -0
  349. package/src/app/lib/components/ui/toggle/toggle.component.ts +199 -0
  350. package/src/app/lib/components/ui/toggle-group/index.ts +11 -0
  351. package/src/app/lib/components/ui/toggle-group/toggle-group-context.ts +48 -0
  352. package/src/app/lib/components/ui/toggle-group/toggle-group-item.component.ts +241 -0
  353. package/src/app/lib/components/ui/toggle-group/toggle-group.component.ts +288 -0
  354. package/src/app/lib/components/ui/tooltip/index.ts +14 -0
  355. package/src/app/lib/components/ui/tooltip/tooltip-content.component.ts +154 -0
  356. package/src/app/lib/components/ui/tooltip/tooltip-context.ts +29 -0
  357. package/src/app/lib/components/ui/tooltip/tooltip-provider.component.ts +95 -0
  358. package/src/app/lib/components/ui/tooltip/tooltip-trigger.component.ts +138 -0
  359. package/src/app/lib/components/ui/tooltip/tooltip.component.ts +159 -0
  360. package/src/app/lib/components/ui/typography/index.ts +13 -0
  361. package/src/app/lib/components/ui/typography/typography-blockquote.component.ts +31 -0
  362. package/src/app/lib/components/ui/typography/typography-h1.component.ts +32 -0
  363. package/src/app/lib/components/ui/typography/typography-h2.component.ts +32 -0
  364. package/src/app/lib/components/ui/typography/typography-h3.component.ts +29 -0
  365. package/src/app/lib/components/ui/typography/typography-h4.component.ts +29 -0
  366. package/src/app/lib/components/ui/typography/typography-inline-code.component.ts +31 -0
  367. package/src/app/lib/components/ui/typography/typography-large.component.ts +28 -0
  368. package/src/app/lib/components/ui/typography/typography-lead.component.ts +31 -0
  369. package/src/app/lib/components/ui/typography/typography-list.component.ts +31 -0
  370. package/src/app/lib/components/ui/typography/typography-muted.component.ts +28 -0
  371. package/src/app/lib/components/ui/typography/typography-p.component.ts +29 -0
  372. package/src/app/lib/components/ui/typography/typography-small.component.ts +28 -0
  373. package/src/app/lib/index.ts +7 -0
  374. package/src/app/lib/utils/accessibility/aria-id.service.ts +118 -0
  375. package/src/app/lib/utils/accessibility/click-outside.directive.ts +85 -0
  376. package/src/app/lib/utils/accessibility/focus-management.service.ts +231 -0
  377. package/src/app/lib/utils/accessibility/focus-trap.directive.ts +203 -0
  378. package/src/app/lib/utils/accessibility/index.ts +23 -0
  379. package/src/app/lib/utils/accessibility/keyboard-navigation.directive.ts +440 -0
  380. package/src/app/lib/utils/accessibility/live-region.directive.ts +260 -0
  381. package/src/app/lib/utils/accessibility/touch-target.directive.ts +81 -0
  382. package/src/app/lib/utils/accessibility/visually-hidden.component.ts +79 -0
  383. package/src/app/lib/utils/animation/animated.directive.ts +191 -0
  384. package/src/app/lib/utils/animation/animation-tokens.service.ts +88 -0
  385. package/src/app/lib/utils/animation/animation.types.ts +55 -0
  386. package/src/app/lib/utils/animation/animation.utils.ts +158 -0
  387. package/src/app/lib/utils/animation/index.ts +17 -0
  388. package/src/app/lib/utils/animation/presence.component.ts +168 -0
  389. package/src/app/lib/utils/animation/presence.directive.ts +169 -0
  390. package/src/app/lib/utils/cn.ts +15 -0
  391. package/src/app/lib/utils/index.ts +11 -0
  392. package/src/app/lib/utils/positioning/index.ts +218 -0
@@ -0,0 +1,107 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ inject,
7
+ input,
8
+ } from '@angular/core';
9
+ import { FORM_FIELD_CONTEXT } from './form-context';
10
+
11
+ /**
12
+ * FormMessage component - displays validation error messages.
13
+ *
14
+ * @example
15
+ * <FormMessage />
16
+ *
17
+ * <!-- Or with custom message -->
18
+ * <FormMessage>Custom error message</FormMessage>
19
+ */
20
+ @Component({
21
+ selector: 'FormMessage',
22
+ template: `
23
+ @if (errorMessage() || hasContent) {
24
+ <ng-content />
25
+ @if (!hasContent && errorMessage()) {
26
+ {{ errorMessage() }}
27
+ }
28
+ }
29
+ `,
30
+ host: {
31
+ '[class]': 'computedClass()',
32
+ '[attr.id]': 'fieldContext?.formMessageId()',
33
+ '[attr.role]': 'hasError() ? "alert" : null',
34
+ 'data-slot': 'form-message',
35
+ },
36
+ changeDetection: ChangeDetectionStrategy.OnPush,
37
+ })
38
+ export class FormMessage {
39
+ protected readonly fieldContext = inject(FORM_FIELD_CONTEXT, { optional: true });
40
+
41
+ /** Additional CSS classes to apply */
42
+ readonly class = input<string>('');
43
+
44
+ /** Whether component has projected content */
45
+ hasContent = false;
46
+
47
+ /** Check if field has error */
48
+ protected readonly hasError = computed(() => {
49
+ const control = this.fieldContext?.control();
50
+ return control?.invalid && (control?.dirty || control?.touched);
51
+ });
52
+
53
+ /** Get first error message */
54
+ protected readonly errorMessage = computed(() => {
55
+ const control = this.fieldContext?.control();
56
+ if (!control?.errors || !this.hasError()) return null;
57
+
58
+ const errors = control.errors;
59
+ const errorKeys = Object.keys(errors);
60
+ if (errorKeys.length === 0) return null;
61
+
62
+ const firstErrorKey = errorKeys[0];
63
+ const errorValue = errors[firstErrorKey];
64
+
65
+ // Handle common error types
66
+ switch (firstErrorKey) {
67
+ case 'required':
68
+ return 'This field is required';
69
+ case 'minlength':
70
+ return `Minimum length is ${errorValue.requiredLength} characters`;
71
+ case 'maxlength':
72
+ return `Maximum length is ${errorValue.requiredLength} characters`;
73
+ case 'min':
74
+ return `Minimum value is ${errorValue.min}`;
75
+ case 'max':
76
+ return `Maximum value is ${errorValue.max}`;
77
+ case 'email':
78
+ return 'Please enter a valid email address';
79
+ case 'pattern':
80
+ return 'Invalid format';
81
+ default:
82
+ // If error is a string, return it directly
83
+ if (typeof errorValue === 'string') {
84
+ return errorValue;
85
+ }
86
+ // If error has a message property
87
+ if (errorValue?.message) {
88
+ return errorValue.message;
89
+ }
90
+ return 'Invalid value';
91
+ }
92
+ });
93
+
94
+ /** Computed class combining base styles and custom classes */
95
+ protected readonly computedClass = computed(() =>
96
+ cn(
97
+ 'text-destructive text-[0.8rem] font-medium',
98
+ !this.hasError() && !this.hasContent && 'hidden',
99
+ this.class()
100
+ )
101
+ );
102
+
103
+ ngAfterContentInit() {
104
+ // Check if there's projected content
105
+ // This is a simplified check - in production you might want to use ContentChild
106
+ }
107
+ }
@@ -0,0 +1,123 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ forwardRef,
7
+ input,
8
+ signal,
9
+ } from '@angular/core';
10
+ import { FormGroup, ReactiveFormsModule } from '@angular/forms';
11
+ import { FORM_CONTEXT, type FormContext } from './form-context';
12
+
13
+ // ============================================================================
14
+ // Types
15
+ // ============================================================================
16
+
17
+ /**
18
+ * Props for the Form component
19
+ */
20
+ export interface FormProps {
21
+ /** The reactive form group to bind to */
22
+ formGroup?: FormGroup | null;
23
+ /** Additional CSS classes */
24
+ class?: string;
25
+ }
26
+
27
+ // ============================================================================
28
+ // Component
29
+ // ============================================================================
30
+
31
+ /**
32
+ * @component Form
33
+ *
34
+ * Building forms with Angular Reactive Forms.
35
+ *
36
+ * @description
37
+ * Form provides a wrapper for Angular Reactive Forms that integrates with
38
+ * the form component system for consistent styling and accessibility.
39
+ *
40
+ * ## Features
41
+ * - Integrates with Angular Reactive Forms
42
+ * - Provides context for FormField, FormItem, FormLabel, etc.
43
+ * - Automatic error message display
44
+ * - Accessible form structure with proper ARIA relationships
45
+ * - Consistent validation styling
46
+ *
47
+ * ## Form Components
48
+ * - `Form` - Wrapper providing form context
49
+ * - `FormField` - Wraps a form control with context
50
+ * - `FormItem` - Container for label, control, description, message
51
+ * - `FormLabel` - Label with accessibility bindings
52
+ * - `FormControl` - Control with ARIA attributes
53
+ * - `FormDescription` - Helper text for the field
54
+ * - `FormMessage` - Error/validation messages
55
+ *
56
+ * ## Accessibility
57
+ * - `aria-describedby` links controls to description and errors
58
+ * - `aria-invalid` when field has errors
59
+ * - Labels properly associated with controls
60
+ *
61
+ * @example Basic usage
62
+ * ```html
63
+ * <Form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
64
+ * <FormField name="email">
65
+ * <FormItem>
66
+ * <FormLabel>Email</FormLabel>
67
+ * <FormControl>
68
+ * <Input type="email" formControlName="email" />
69
+ * </FormControl>
70
+ * <FormDescription>Enter your email address</FormDescription>
71
+ * <FormMessage />
72
+ * </FormItem>
73
+ * </FormField>
74
+ * <Button type="submit">Submit</Button>
75
+ * </Form>
76
+ * ```
77
+ *
78
+ * @example With validation
79
+ * ```typescript
80
+ * loginForm = this.fb.group({
81
+ * email: ['', [Validators.required, Validators.email]],
82
+ * password: ['', [Validators.required, Validators.minLength(8)]],
83
+ * });
84
+ * ```
85
+ */
86
+ @Component({
87
+ selector: 'Form',
88
+ imports: [ReactiveFormsModule],
89
+ template: `<ng-content />`,
90
+ host: {
91
+ '[class]': 'computedClass()',
92
+ 'data-slot': 'form',
93
+ },
94
+ providers: [
95
+ {
96
+ provide: FORM_CONTEXT,
97
+ useFactory: (component: Form) => component.context,
98
+ deps: [forwardRef(() => Form)],
99
+ },
100
+ ],
101
+ changeDetection: ChangeDetectionStrategy.OnPush,
102
+ })
103
+ export class Form {
104
+ /** The reactive form group */
105
+ readonly formGroup = input<FormGroup | null>(null);
106
+
107
+ /** Additional CSS classes */
108
+ readonly class = input<string>('');
109
+
110
+ /** Context for child components */
111
+ readonly context: FormContext = {
112
+ form: signal(this.formGroup()),
113
+ };
114
+
115
+ /** Computed class combining base styles and custom classes */
116
+ protected readonly computedClass = computed(() =>
117
+ cn('space-y-6', this.class())
118
+ );
119
+
120
+ ngOnChanges() {
121
+ this.context.form.set(this.formGroup());
122
+ }
123
+ }
@@ -0,0 +1,17 @@
1
+ // Context and types
2
+ export {
3
+ FORM_CONTEXT,
4
+ FORM_FIELD_CONTEXT,
5
+ type FormContext,
6
+ type FormFieldContext
7
+ } from './form-context';
8
+
9
+ // Components and their types
10
+ export { FormControl, FormControlInput } from './form-control.component';
11
+ export { FormDescription } from './form-description.component';
12
+ export { FormField } from './form-field.component';
13
+ export { FormItem } from './form-item.component';
14
+ export { FormLabel } from './form-label.component';
15
+ export { FormMessage } from './form-message.component';
16
+ export { Form, type FormProps } from './form.component';
17
+
@@ -0,0 +1,203 @@
1
+ import { cn, Presence } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ ElementRef,
7
+ inject,
8
+ input,
9
+ OnDestroy,
10
+ } from '@angular/core';
11
+ import { HOVER_CARD_CONTEXT, HoverCardAlign, HoverCardSide } from './hover-card-context';
12
+
13
+ // ============================================================================
14
+ // Types
15
+ // ============================================================================
16
+
17
+ export type HoverCardContentState = 'open' | 'closed';
18
+
19
+ /**
20
+ * Props for the HoverCardContent component
21
+ */
22
+ export interface HoverCardContentProps {
23
+ /** The preferred side of the trigger to render against.
24
+ * @default 'bottom' */
25
+ side?: HoverCardSide;
26
+ /** The distance in pixels from the trigger.
27
+ * @default 4 */
28
+ sideOffset?: number;
29
+ /** The preferred alignment against the trigger.
30
+ * @default 'center' */
31
+ align?: HoverCardAlign;
32
+ /** Additional CSS classes */
33
+ class?: string;
34
+ }
35
+
36
+ // ============================================================================
37
+ // Component
38
+ // ============================================================================
39
+
40
+ /**
41
+ * @component HoverCardContent
42
+ *
43
+ * The component that pops out when the hover card is open.
44
+ *
45
+ * @description
46
+ * HoverCardContent displays the preview content. It stays open when
47
+ * hovered, allowing users to interact with the content.
48
+ *
49
+ * ## Features
50
+ * - Stays open when content is hovered
51
+ * - Configurable side and alignment
52
+ * - Smooth animations
53
+ * - Escape key to dismiss
54
+ *
55
+ * ## Accessibility
56
+ * - `role="dialog"` on the content
57
+ * - Focusable content items
58
+ * - Escape returns focus to trigger
59
+ *
60
+ * @example Basic usage
61
+ * ```html
62
+ * <HoverCardContent>
63
+ * <p>Preview content</p>
64
+ * </HoverCardContent>
65
+ * ```
66
+ *
67
+ * @example With positioning
68
+ * ```html
69
+ * <HoverCardContent side="right" align="start">
70
+ * <p>Right-aligned content</p>
71
+ * </HoverCardContent>
72
+ * ```
73
+ *
74
+ * @data-attributes
75
+ * - `data-state` - 'open' | 'closed'
76
+ * - `data-side` - 'top' | 'right' | 'bottom' | 'left'
77
+ * - `data-align` - 'start' | 'center' | 'end'
78
+ */
79
+ @Component({
80
+ selector: 'HoverCardContent',
81
+ imports: [Presence],
82
+ template: `
83
+ <Presence [present]="context.open()">
84
+ <div
85
+ role="dialog"
86
+ [attr.aria-modal]="false"
87
+ tabindex="-1"
88
+ [class]="computedClass()"
89
+ [attr.data-state]="state()"
90
+ [attr.data-side]="side()"
91
+ [attr.data-align]="align()"
92
+ data-slot="hover-card-content"
93
+ (mouseenter)="onMouseEnter()"
94
+ (mouseleave)="onMouseLeave()"
95
+ (focusin)="onFocusIn()"
96
+ (focusout)="onFocusOut($event)"
97
+ (keydown.escape)="onEscape()"
98
+ >
99
+ <ng-content />
100
+ </div>
101
+ </Presence>
102
+ `,
103
+ host: {
104
+ class: 'contents',
105
+ },
106
+ changeDetection: ChangeDetectionStrategy.OnPush,
107
+ })
108
+ export class HoverCardContent implements OnDestroy {
109
+ protected readonly context = inject(HOVER_CARD_CONTEXT);
110
+ private readonly elementRef = inject(ElementRef<HTMLElement>);
111
+
112
+ /** The preferred side of the trigger to render against */
113
+ readonly side = input<HoverCardSide>('bottom');
114
+
115
+ /** The distance in pixels from the trigger */
116
+ readonly sideOffset = input<number>(4);
117
+
118
+ /** The preferred alignment against the trigger */
119
+ readonly align = input<HoverCardAlign>('center');
120
+
121
+ /** Additional CSS classes */
122
+ readonly class = input<string>('');
123
+
124
+ private closeTimeout: ReturnType<typeof setTimeout> | null = null;
125
+
126
+ /** Current state: open or closed */
127
+ protected readonly state = computed<HoverCardContentState>(() =>
128
+ this.context.open() ? 'open' : 'closed'
129
+ );
130
+
131
+ protected readonly computedClass = computed(() => {
132
+ const sideClasses = {
133
+ top: 'bottom-full mb-2',
134
+ bottom: 'top-full mt-2',
135
+ left: 'right-full mr-2',
136
+ right: 'left-full ml-2',
137
+ };
138
+
139
+ const alignClasses = {
140
+ start: 'left-0',
141
+ center: 'left-1/2 -translate-x-1/2',
142
+ end: 'right-0',
143
+ };
144
+
145
+ return cn(
146
+ 'absolute z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
147
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out',
148
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
149
+ 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
150
+ 'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',
151
+ 'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
152
+ sideClasses[this.side()],
153
+ this.side() === 'top' || this.side() === 'bottom' ? alignClasses[this.align()] : '',
154
+ this.class()
155
+ );
156
+ });
157
+
158
+ ngOnDestroy(): void {
159
+ this.clearTimeout();
160
+ }
161
+
162
+ onMouseEnter(): void {
163
+ this.clearTimeout();
164
+ }
165
+
166
+ onMouseLeave(): void {
167
+ this.closeTimeout = setTimeout(() => {
168
+ this.context.setOpen(false);
169
+ }, this.context.closeDelay);
170
+ }
171
+
172
+ onFocusIn(): void {
173
+ this.clearTimeout();
174
+ }
175
+
176
+ onFocusOut(event: FocusEvent): void {
177
+ const relatedTarget = event.relatedTarget as HTMLElement | null;
178
+ const trigger = this.elementRef.nativeElement.parentElement?.querySelector('[data-state]');
179
+
180
+ // Check if focus moved to trigger or stayed within content
181
+ if (relatedTarget && (trigger === relatedTarget || trigger?.contains(relatedTarget))) {
182
+ return;
183
+ }
184
+
185
+ this.closeTimeout = setTimeout(() => {
186
+ this.context.setOpen(false);
187
+ }, this.context.closeDelay);
188
+ }
189
+
190
+ onEscape(): void {
191
+ this.context.setOpen(false);
192
+ // Return focus to trigger
193
+ const trigger = this.elementRef.nativeElement.parentElement?.querySelector('[data-state]') as HTMLElement;
194
+ trigger?.focus();
195
+ }
196
+
197
+ private clearTimeout(): void {
198
+ if (this.closeTimeout) {
199
+ clearTimeout(this.closeTimeout);
200
+ this.closeTimeout = null;
201
+ }
202
+ }
203
+ }
@@ -0,0 +1,25 @@
1
+ import { InjectionToken, WritableSignal } from '@angular/core';
2
+
3
+ // ============================================================================
4
+ // Types
5
+ // ============================================================================
6
+
7
+ export type HoverCardSide = 'top' | 'right' | 'bottom' | 'left';
8
+ export type HoverCardAlign = 'start' | 'center' | 'end';
9
+
10
+ export interface HoverCardContextValue {
11
+ /** Signal for open state */
12
+ open: WritableSignal<boolean>;
13
+ /** Set open state */
14
+ setOpen: (open: boolean) => void;
15
+ /** The duration from when the pointer enters the trigger until the hover card opens (ms) */
16
+ openDelay: number;
17
+ /** The duration from when the pointer leaves the trigger/content until the hover card closes (ms) */
18
+ closeDelay: number;
19
+ }
20
+
21
+ // ============================================================================
22
+ // Injection Tokens
23
+ // ============================================================================
24
+
25
+ export const HOVER_CARD_CONTEXT = new InjectionToken<HoverCardContextValue>('HOVER_CARD_CONTEXT');
@@ -0,0 +1,160 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ ElementRef,
5
+ inject,
6
+ input,
7
+ OnDestroy,
8
+ } from '@angular/core';
9
+ import { HOVER_CARD_CONTEXT } from './hover-card-context';
10
+
11
+ // ============================================================================
12
+ // Types
13
+ // ============================================================================
14
+
15
+ /**
16
+ * Props for the HoverCardTrigger component
17
+ */
18
+ export interface HoverCardTriggerProps {
19
+ /** Change the default rendered element for the one passed as a child.
20
+ * @default false */
21
+ asChild?: boolean;
22
+ }
23
+
24
+ // ============================================================================
25
+ // Component
26
+ // ============================================================================
27
+
28
+ /**
29
+ * @component HoverCardTrigger
30
+ *
31
+ * The link that opens the hover card when hovered.
32
+ *
33
+ * @description
34
+ * HoverCardTrigger wraps the element that activates the hover card on hover
35
+ * or focus. It manages timing for open/close delays.
36
+ *
37
+ * ## Features
38
+ * - Opens on hover with delay
39
+ * - Opens immediately on focus (keyboard)
40
+ * - Toggle on Enter/Space (keyboard)
41
+ * - Escape dismisses and returns focus
42
+ *
43
+ * ## Accessibility
44
+ * - `aria-expanded` reflects open state
45
+ * - `aria-haspopup="dialog"` indicates content type
46
+ * - Focus triggers immediate open for keyboard users
47
+ * - Escape returns focus to trigger
48
+ *
49
+ * ## Keyboard Navigation
50
+ * - `Tab` - Focus triggers hover card
51
+ * - `Enter` / `Space` - Toggle hover card
52
+ * - `Escape` - Close and return focus
53
+ *
54
+ * @example Basic usage
55
+ * ```html
56
+ * <HoverCardTrigger>
57
+ * <a href="#">&#64;username</a>
58
+ * </HoverCardTrigger>
59
+ * ```
60
+ *
61
+ * @example With custom element
62
+ * ```html
63
+ * <HoverCardTrigger>
64
+ * <span class="cursor-pointer underline">Hover for info</span>
65
+ * </HoverCardTrigger>
66
+ * ```
67
+ *
68
+ * @data-attributes
69
+ * - `data-state` - 'open' | 'closed'
70
+ */
71
+ @Component({
72
+ selector: 'HoverCardTrigger',
73
+ template: `<ng-content />`,
74
+ host: {
75
+ 'tabindex': '0',
76
+ 'role': 'button',
77
+ '(mouseenter)': 'onMouseEnter()',
78
+ '(mouseleave)': 'onMouseLeave()',
79
+ '(focus)': 'onFocus()',
80
+ '(blur)': 'onBlur($event)',
81
+ '(keydown.enter)': 'onKeyDown($event)',
82
+ '(keydown.space)': 'onKeyDown($event)',
83
+ '(keydown.escape)': 'onEscape()',
84
+ '[attr.data-state]': 'context.open() ? "open" : "closed"',
85
+ '[attr.aria-expanded]': 'context.open()',
86
+ '[attr.aria-haspopup]': '"dialog"',
87
+ },
88
+ changeDetection: ChangeDetectionStrategy.OnPush,
89
+ })
90
+ export class HoverCardTrigger implements OnDestroy {
91
+ protected readonly context = inject(HOVER_CARD_CONTEXT);
92
+ private readonly elementRef = inject(ElementRef<HTMLElement>);
93
+
94
+ /** Change the default rendered element for the one passed as a child */
95
+ readonly asChild = input<boolean>(false);
96
+
97
+ private openTimeout: ReturnType<typeof setTimeout> | null = null;
98
+ private closeTimeout: ReturnType<typeof setTimeout> | null = null;
99
+
100
+ ngOnDestroy(): void {
101
+ this.clearTimeouts();
102
+ }
103
+
104
+ onMouseEnter(): void {
105
+ this.clearTimeouts();
106
+ this.openTimeout = setTimeout(() => {
107
+ this.context.setOpen(true);
108
+ }, this.context.openDelay);
109
+ }
110
+
111
+ onMouseLeave(): void {
112
+ this.clearTimeouts();
113
+ this.closeTimeout = setTimeout(() => {
114
+ this.context.setOpen(false);
115
+ }, this.context.closeDelay);
116
+ }
117
+
118
+ onFocus(): void {
119
+ this.clearTimeouts();
120
+ // Open immediately on focus for keyboard users
121
+ this.context.setOpen(true);
122
+ }
123
+
124
+ onBlur(event: FocusEvent): void {
125
+ // Check if focus moved to the hover card content
126
+ const relatedTarget = event.relatedTarget as HTMLElement | null;
127
+ const hoverCardContent = this.elementRef.nativeElement.parentElement?.querySelector('[data-slot="hover-card-content"]');
128
+
129
+ if (relatedTarget && hoverCardContent?.contains(relatedTarget)) {
130
+ // Focus moved to content, don't close
131
+ return;
132
+ }
133
+
134
+ this.clearTimeouts();
135
+ this.closeTimeout = setTimeout(() => {
136
+ this.context.setOpen(false);
137
+ }, this.context.closeDelay);
138
+ }
139
+
140
+ onKeyDown(event: Event): void {
141
+ event.preventDefault();
142
+ this.context.setOpen(!this.context.open());
143
+ }
144
+
145
+ onEscape(): void {
146
+ this.context.setOpen(false);
147
+ this.elementRef.nativeElement.focus();
148
+ }
149
+
150
+ private clearTimeouts(): void {
151
+ if (this.openTimeout) {
152
+ clearTimeout(this.openTimeout);
153
+ this.openTimeout = null;
154
+ }
155
+ if (this.closeTimeout) {
156
+ clearTimeout(this.closeTimeout);
157
+ this.closeTimeout = null;
158
+ }
159
+ }
160
+ }