@ng-cn/core 1.0.11 → 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 (394) hide show
  1. package/package.json +2 -1
  2. package/schematics/ng-add/index.js +2 -2
  3. package/schematics/ng-add/index.ts +2 -2
  4. package/src/app/lib/components/ui/accordion/accordion-content.component.ts +53 -0
  5. package/src/app/lib/components/ui/accordion/accordion-context.ts +33 -0
  6. package/src/app/lib/components/ui/accordion/accordion-item.component.ts +86 -0
  7. package/src/app/lib/components/ui/accordion/accordion-trigger.component.ts +73 -0
  8. package/src/app/lib/components/ui/accordion/accordion.component.ts +197 -0
  9. package/src/app/lib/components/ui/accordion/index.ts +15 -0
  10. package/src/app/lib/components/ui/alert/alert-description.component.ts +33 -0
  11. package/src/app/lib/components/ui/alert/alert-title.component.ts +30 -0
  12. package/src/app/lib/components/ui/alert/alert-variants.ts +23 -0
  13. package/src/app/lib/components/ui/alert/alert.component.ts +50 -0
  14. package/src/app/lib/components/ui/alert/index.ts +5 -0
  15. package/src/app/lib/components/ui/alert-dialog/alert-dialog-action.component.ts +44 -0
  16. package/src/app/lib/components/ui/alert-dialog/alert-dialog-cancel.component.ts +45 -0
  17. package/src/app/lib/components/ui/alert-dialog/alert-dialog-content.component.ts +146 -0
  18. package/src/app/lib/components/ui/alert-dialog/alert-dialog-context.ts +14 -0
  19. package/src/app/lib/components/ui/alert-dialog/alert-dialog-description.component.ts +37 -0
  20. package/src/app/lib/components/ui/alert-dialog/alert-dialog-footer.component.ts +35 -0
  21. package/src/app/lib/components/ui/alert-dialog/alert-dialog-header.component.ts +35 -0
  22. package/src/app/lib/components/ui/alert-dialog/alert-dialog-title.component.ts +37 -0
  23. package/src/app/lib/components/ui/alert-dialog/alert-dialog-trigger.component.ts +44 -0
  24. package/src/app/lib/components/ui/alert-dialog/alert-dialog.component.ts +91 -0
  25. package/src/app/lib/components/ui/alert-dialog/index.ts +11 -0
  26. package/src/app/lib/components/ui/aspect-ratio/aspect-ratio.component.ts +63 -0
  27. package/src/app/lib/components/ui/aspect-ratio/index.ts +1 -0
  28. package/src/app/lib/components/ui/avatar/avatar-fallback.component.ts +34 -0
  29. package/src/app/lib/components/ui/avatar/avatar-image.component.ts +31 -0
  30. package/src/app/lib/components/ui/avatar/avatar.component.ts +37 -0
  31. package/src/app/lib/components/ui/avatar/index.ts +5 -0
  32. package/src/app/lib/components/ui/avatar/ui-avatar.component.ts +52 -0
  33. package/src/app/lib/components/ui/badge/badge-variants.ts +28 -0
  34. package/src/app/lib/components/ui/badge/badge.component.ts +50 -0
  35. package/src/app/lib/components/ui/badge/index.ts +3 -0
  36. package/src/app/lib/components/ui/breadcrumb/breadcrumb-ellipsis.component.ts +48 -0
  37. package/src/app/lib/components/ui/breadcrumb/breadcrumb-item.component.ts +28 -0
  38. package/src/app/lib/components/ui/breadcrumb/breadcrumb-link.component.ts +32 -0
  39. package/src/app/lib/components/ui/breadcrumb/breadcrumb-list.component.ts +31 -0
  40. package/src/app/lib/components/ui/breadcrumb/breadcrumb-page.component.ts +31 -0
  41. package/src/app/lib/components/ui/breadcrumb/breadcrumb-separator.component.ts +47 -0
  42. package/src/app/lib/components/ui/breadcrumb/breadcrumb.component.ts +43 -0
  43. package/src/app/lib/components/ui/breadcrumb/index.ts +8 -0
  44. package/src/app/lib/components/ui/button/button-variants.ts +38 -0
  45. package/src/app/lib/components/ui/button/button.component.ts +103 -0
  46. package/src/app/lib/components/ui/button/index.ts +3 -0
  47. package/src/app/lib/components/ui/button-group/button-group-variants.ts +24 -0
  48. package/src/app/lib/components/ui/button-group/button-group.component.ts +57 -0
  49. package/src/app/lib/components/ui/button-group/index.ts +6 -0
  50. package/src/app/lib/components/ui/calendar/calendar.component.ts +368 -0
  51. package/src/app/lib/components/ui/calendar/index.ts +1 -0
  52. package/src/app/lib/components/ui/card/card-action.component.ts +39 -0
  53. package/src/app/lib/components/ui/card/card-content.component.ts +31 -0
  54. package/src/app/lib/components/ui/card/card-description.component.ts +31 -0
  55. package/src/app/lib/components/ui/card/card-footer.component.ts +34 -0
  56. package/src/app/lib/components/ui/card/card-header.component.ts +37 -0
  57. package/src/app/lib/components/ui/card/card-title.component.ts +31 -0
  58. package/src/app/lib/components/ui/card/card.component.ts +41 -0
  59. package/src/app/lib/components/ui/card/index.ts +8 -0
  60. package/src/app/lib/components/ui/carousel/carousel-content.component.ts +38 -0
  61. package/src/app/lib/components/ui/carousel/carousel-context.ts +18 -0
  62. package/src/app/lib/components/ui/carousel/carousel-item.component.ts +32 -0
  63. package/src/app/lib/components/ui/carousel/carousel-next.component.ts +54 -0
  64. package/src/app/lib/components/ui/carousel/carousel-previous.component.ts +54 -0
  65. package/src/app/lib/components/ui/carousel/carousel.component.ts +125 -0
  66. package/src/app/lib/components/ui/carousel/index.ts +7 -0
  67. package/src/app/lib/components/ui/chart/chart-container.component.ts +81 -0
  68. package/src/app/lib/components/ui/chart/chart-context.ts +38 -0
  69. package/src/app/lib/components/ui/chart/chart-legend-content.component.ts +51 -0
  70. package/src/app/lib/components/ui/chart/chart-legend.component.ts +28 -0
  71. package/src/app/lib/components/ui/chart/chart-tooltip-content.component.ts +37 -0
  72. package/src/app/lib/components/ui/chart/chart-tooltip.component.ts +28 -0
  73. package/src/app/lib/components/ui/chart/chart.component.ts +308 -0
  74. package/src/app/lib/components/ui/chart/index.ts +16 -0
  75. package/src/app/lib/components/ui/checkbox/checkbox.component.ts +203 -0
  76. package/src/app/lib/components/ui/checkbox/index.ts +1 -0
  77. package/src/app/lib/components/ui/collapsible/collapsible-content.component.ts +58 -0
  78. package/src/app/lib/components/ui/collapsible/collapsible-context.ts +17 -0
  79. package/src/app/lib/components/ui/collapsible/collapsible-trigger.component.ts +56 -0
  80. package/src/app/lib/components/ui/collapsible/collapsible.component.ts +102 -0
  81. package/src/app/lib/components/ui/collapsible/index.ts +5 -0
  82. package/src/app/lib/components/ui/combobox/combobox-content.component.ts +59 -0
  83. package/src/app/lib/components/ui/combobox/combobox-context.ts +49 -0
  84. package/src/app/lib/components/ui/combobox/combobox-empty.component.ts +35 -0
  85. package/src/app/lib/components/ui/combobox/combobox-group.component.ts +32 -0
  86. package/src/app/lib/components/ui/combobox/combobox-input.component.ts +89 -0
  87. package/src/app/lib/components/ui/combobox/combobox-item.component.ts +129 -0
  88. package/src/app/lib/components/ui/combobox/combobox-list.component.ts +40 -0
  89. package/src/app/lib/components/ui/combobox/combobox-trigger.component.ts +53 -0
  90. package/src/app/lib/components/ui/combobox/combobox-value.component.ts +47 -0
  91. package/src/app/lib/components/ui/combobox/combobox.component.ts +290 -0
  92. package/src/app/lib/components/ui/combobox/index.ts +15 -0
  93. package/src/app/lib/components/ui/command/command-context.ts +24 -0
  94. package/src/app/lib/components/ui/command/command-dialog.component.ts +69 -0
  95. package/src/app/lib/components/ui/command/command-empty.component.ts +23 -0
  96. package/src/app/lib/components/ui/command/command-group.component.ts +66 -0
  97. package/src/app/lib/components/ui/command/command-input.component.ts +137 -0
  98. package/src/app/lib/components/ui/command/command-item.component.ts +148 -0
  99. package/src/app/lib/components/ui/command/command-list.component.ts +30 -0
  100. package/src/app/lib/components/ui/command/command-separator.component.ts +23 -0
  101. package/src/app/lib/components/ui/command/command-shortcut.component.ts +23 -0
  102. package/src/app/lib/components/ui/command/command.component.ts +105 -0
  103. package/src/app/lib/components/ui/command/index.ts +11 -0
  104. package/src/app/lib/components/ui/context-menu/context-menu-checkbox-item.component.ts +68 -0
  105. package/src/app/lib/components/ui/context-menu/context-menu-content.component.ts +213 -0
  106. package/src/app/lib/components/ui/context-menu/context-menu-context.ts +17 -0
  107. package/src/app/lib/components/ui/context-menu/context-menu-item.component.ts +63 -0
  108. package/src/app/lib/components/ui/context-menu/context-menu-label.component.ts +30 -0
  109. package/src/app/lib/components/ui/context-menu/context-menu-radio-group.component.ts +36 -0
  110. package/src/app/lib/components/ui/context-menu/context-menu-radio-item.component.ts +71 -0
  111. package/src/app/lib/components/ui/context-menu/context-menu-separator.component.ts +24 -0
  112. package/src/app/lib/components/ui/context-menu/context-menu-shortcut.component.ts +23 -0
  113. package/src/app/lib/components/ui/context-menu/context-menu-sub-content.component.ts +51 -0
  114. package/src/app/lib/components/ui/context-menu/context-menu-sub-trigger.component.ts +50 -0
  115. package/src/app/lib/components/ui/context-menu/context-menu-sub.component.ts +31 -0
  116. package/src/app/lib/components/ui/context-menu/context-menu-trigger.component.ts +51 -0
  117. package/src/app/lib/components/ui/context-menu/context-menu.component.ts +27 -0
  118. package/src/app/lib/components/ui/context-menu/index.ts +15 -0
  119. package/src/app/lib/components/ui/data-table/data-table-content.component.ts +226 -0
  120. package/src/app/lib/components/ui/data-table/data-table-context.ts +49 -0
  121. package/src/app/lib/components/ui/data-table/data-table-pagination.component.ts +138 -0
  122. package/src/app/lib/components/ui/data-table/data-table-search.component.ts +52 -0
  123. package/src/app/lib/components/ui/data-table/data-table-toolbar.component.ts +27 -0
  124. package/src/app/lib/components/ui/data-table/data-table-view-options.component.ts +92 -0
  125. package/src/app/lib/components/ui/data-table/data-table.component.ts +131 -0
  126. package/src/app/lib/components/ui/data-table/index.ts +16 -0
  127. package/src/app/lib/components/ui/date-picker/date-picker.component.ts +94 -0
  128. package/src/app/lib/components/ui/date-picker/index.ts +1 -0
  129. package/src/app/lib/components/ui/dialog/dialog-close.component.ts +31 -0
  130. package/src/app/lib/components/ui/dialog/dialog-content.component.ts +177 -0
  131. package/src/app/lib/components/ui/dialog/dialog-context.ts +15 -0
  132. package/src/app/lib/components/ui/dialog/dialog-description.component.ts +34 -0
  133. package/src/app/lib/components/ui/dialog/dialog-footer.component.ts +28 -0
  134. package/src/app/lib/components/ui/dialog/dialog-header.component.ts +28 -0
  135. package/src/app/lib/components/ui/dialog/dialog-title.component.ts +34 -0
  136. package/src/app/lib/components/ui/dialog/dialog-trigger.component.ts +38 -0
  137. package/src/app/lib/components/ui/dialog/dialog.component.ts +87 -0
  138. package/src/app/lib/components/ui/dialog/index.ts +10 -0
  139. package/src/app/lib/components/ui/drawer/drawer-close.component.ts +31 -0
  140. package/src/app/lib/components/ui/drawer/drawer-content.component.ts +143 -0
  141. package/src/app/lib/components/ui/drawer/drawer-context.ts +17 -0
  142. package/src/app/lib/components/ui/drawer/drawer-description.component.ts +33 -0
  143. package/src/app/lib/components/ui/drawer/drawer-footer.component.ts +28 -0
  144. package/src/app/lib/components/ui/drawer/drawer-header.component.ts +28 -0
  145. package/src/app/lib/components/ui/drawer/drawer-title.component.ts +33 -0
  146. package/src/app/lib/components/ui/drawer/drawer-trigger.component.ts +38 -0
  147. package/src/app/lib/components/ui/drawer/drawer.component.ts +93 -0
  148. package/src/app/lib/components/ui/drawer/index.ts +10 -0
  149. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.component.ts +68 -0
  150. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-content.component.ts +234 -0
  151. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-context.ts +15 -0
  152. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-group.component.ts +15 -0
  153. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-item.component.ts +56 -0
  154. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-label.component.ts +30 -0
  155. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.component.ts +42 -0
  156. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.component.ts +71 -0
  157. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-separator.component.ts +24 -0
  158. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.component.ts +23 -0
  159. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.component.ts +51 -0
  160. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.component.ts +53 -0
  161. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub.component.ts +31 -0
  162. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-trigger.component.ts +45 -0
  163. package/src/app/lib/components/ui/dropdown-menu/dropdown-menu.component.ts +32 -0
  164. package/src/app/lib/components/ui/dropdown-menu/index.ts +16 -0
  165. package/src/app/lib/components/ui/empty/empty-action.component.ts +28 -0
  166. package/src/app/lib/components/ui/empty/empty-description.component.ts +31 -0
  167. package/src/app/lib/components/ui/empty/empty-icon.component.ts +31 -0
  168. package/src/app/lib/components/ui/empty/empty-title.component.ts +28 -0
  169. package/src/app/lib/components/ui/empty/empty.component.ts +53 -0
  170. package/src/app/lib/components/ui/empty/index.ts +6 -0
  171. package/src/app/lib/components/ui/form/form-context.ts +34 -0
  172. package/src/app/lib/components/ui/form/form-control.component.ts +137 -0
  173. package/src/app/lib/components/ui/form/form-description.component.ts +37 -0
  174. package/src/app/lib/components/ui/form/form-field.component.ts +84 -0
  175. package/src/app/lib/components/ui/form/form-item.component.ts +42 -0
  176. package/src/app/lib/components/ui/form/form-label.component.ts +58 -0
  177. package/src/app/lib/components/ui/form/form-message.component.ts +107 -0
  178. package/src/app/lib/components/ui/form/form.component.ts +123 -0
  179. package/src/app/lib/components/ui/form/index.ts +17 -0
  180. package/src/app/lib/components/ui/hover-card/hover-card-content.component.ts +203 -0
  181. package/src/app/lib/components/ui/hover-card/hover-card-context.ts +25 -0
  182. package/src/app/lib/components/ui/hover-card/hover-card-trigger.component.ts +160 -0
  183. package/src/app/lib/components/ui/hover-card/hover-card.component.ts +147 -0
  184. package/src/app/lib/components/ui/hover-card/index.ts +13 -0
  185. package/src/app/lib/components/ui/index.ts +551 -0
  186. package/src/app/lib/components/ui/input/index.ts +1 -0
  187. package/src/app/lib/components/ui/input/input.component.ts +165 -0
  188. package/src/app/lib/components/ui/input-group/index.ts +4 -0
  189. package/src/app/lib/components/ui/input-group/input-group-addon.component.ts +43 -0
  190. package/src/app/lib/components/ui/input-group/input-group-input.component.ts +33 -0
  191. package/src/app/lib/components/ui/input-group/input-group.component.ts +53 -0
  192. package/src/app/lib/components/ui/input-otp/index.ts +14 -0
  193. package/src/app/lib/components/ui/input-otp/input-otp-context.ts +31 -0
  194. package/src/app/lib/components/ui/input-otp/input-otp-group.component.ts +23 -0
  195. package/src/app/lib/components/ui/input-otp/input-otp-separator.component.ts +31 -0
  196. package/src/app/lib/components/ui/input-otp/input-otp-slot.component.ts +67 -0
  197. package/src/app/lib/components/ui/input-otp/input-otp.component.ts +240 -0
  198. package/src/app/lib/components/ui/kbd/index.ts +3 -0
  199. package/src/app/lib/components/ui/kbd/kbd-variants.ts +23 -0
  200. package/src/app/lib/components/ui/kbd/kbd.component.ts +50 -0
  201. package/src/app/lib/components/ui/label/index.ts +1 -0
  202. package/src/app/lib/components/ui/label/label.component.ts +139 -0
  203. package/src/app/lib/components/ui/menubar/index.ts +26 -0
  204. package/src/app/lib/components/ui/menubar/menubar-checkbox-item.component.ts +66 -0
  205. package/src/app/lib/components/ui/menubar/menubar-content.component.ts +236 -0
  206. package/src/app/lib/components/ui/menubar/menubar-context.ts +63 -0
  207. package/src/app/lib/components/ui/menubar/menubar-item.component.ts +60 -0
  208. package/src/app/lib/components/ui/menubar/menubar-label.component.ts +30 -0
  209. package/src/app/lib/components/ui/menubar/menubar-menu.component.ts +40 -0
  210. package/src/app/lib/components/ui/menubar/menubar-radio-group.component.ts +36 -0
  211. package/src/app/lib/components/ui/menubar/menubar-radio-item.component.ts +66 -0
  212. package/src/app/lib/components/ui/menubar/menubar-separator.component.ts +24 -0
  213. package/src/app/lib/components/ui/menubar/menubar-shortcut.component.ts +23 -0
  214. package/src/app/lib/components/ui/menubar/menubar-sub-content.component.ts +51 -0
  215. package/src/app/lib/components/ui/menubar/menubar-sub-trigger.component.ts +50 -0
  216. package/src/app/lib/components/ui/menubar/menubar-sub.component.ts +29 -0
  217. package/src/app/lib/components/ui/menubar/menubar-trigger.component.ts +132 -0
  218. package/src/app/lib/components/ui/menubar/menubar.component.ts +158 -0
  219. package/src/app/lib/components/ui/native-select/index.ts +6 -0
  220. package/src/app/lib/components/ui/native-select/native-select-variants.ts +23 -0
  221. package/src/app/lib/components/ui/native-select/native-select.component.ts +74 -0
  222. package/src/app/lib/components/ui/navigation-menu/index.ts +21 -0
  223. package/src/app/lib/components/ui/navigation-menu/navigation-menu-content.component.ts +66 -0
  224. package/src/app/lib/components/ui/navigation-menu/navigation-menu-context.ts +55 -0
  225. package/src/app/lib/components/ui/navigation-menu/navigation-menu-indicator.component.ts +28 -0
  226. package/src/app/lib/components/ui/navigation-menu/navigation-menu-item.component.ts +29 -0
  227. package/src/app/lib/components/ui/navigation-menu/navigation-menu-link.component.ts +43 -0
  228. package/src/app/lib/components/ui/navigation-menu/navigation-menu-list.component.ts +26 -0
  229. package/src/app/lib/components/ui/navigation-menu/navigation-menu-trigger-style.ts +7 -0
  230. package/src/app/lib/components/ui/navigation-menu/navigation-menu-trigger.component.ts +58 -0
  231. package/src/app/lib/components/ui/navigation-menu/navigation-menu-viewport.component.ts +26 -0
  232. package/src/app/lib/components/ui/navigation-menu/navigation-menu.component.ts +149 -0
  233. package/src/app/lib/components/ui/pagination/index.ts +8 -0
  234. package/src/app/lib/components/ui/pagination/pagination-content.component.ts +28 -0
  235. package/src/app/lib/components/ui/pagination/pagination-ellipsis.component.ts +47 -0
  236. package/src/app/lib/components/ui/pagination/pagination-item.component.ts +28 -0
  237. package/src/app/lib/components/ui/pagination/pagination-link.component.ts +46 -0
  238. package/src/app/lib/components/ui/pagination/pagination-next.component.ts +54 -0
  239. package/src/app/lib/components/ui/pagination/pagination-previous.component.ts +54 -0
  240. package/src/app/lib/components/ui/pagination/pagination.component.ts +48 -0
  241. package/src/app/lib/components/ui/popover/index.ts +14 -0
  242. package/src/app/lib/components/ui/popover/popover-anchor.component.ts +64 -0
  243. package/src/app/lib/components/ui/popover/popover-content.component.ts +231 -0
  244. package/src/app/lib/components/ui/popover/popover-context.ts +29 -0
  245. package/src/app/lib/components/ui/popover/popover-trigger.component.ts +100 -0
  246. package/src/app/lib/components/ui/popover/popover.component.ts +163 -0
  247. package/src/app/lib/components/ui/progress/index.ts +6 -0
  248. package/src/app/lib/components/ui/progress/progress.component.ts +212 -0
  249. package/src/app/lib/components/ui/radio-group/index.ts +10 -0
  250. package/src/app/lib/components/ui/radio-group/radio-group-context.ts +38 -0
  251. package/src/app/lib/components/ui/radio-group/radio-group-item.component.ts +298 -0
  252. package/src/app/lib/components/ui/radio-group/radio-group.component.ts +275 -0
  253. package/src/app/lib/components/ui/resizable/index.ts +5 -0
  254. package/src/app/lib/components/ui/resizable/resizable-context.ts +14 -0
  255. package/src/app/lib/components/ui/resizable/resizable-handle.component.ts +232 -0
  256. package/src/app/lib/components/ui/resizable/resizable-panel-group.component.ts +140 -0
  257. package/src/app/lib/components/ui/resizable/resizable-panel.component.ts +77 -0
  258. package/src/app/lib/components/ui/scroll-area/index.ts +8 -0
  259. package/src/app/lib/components/ui/scroll-area/scroll-area.component.ts +126 -0
  260. package/src/app/lib/components/ui/scroll-area/scroll-bar.component.ts +93 -0
  261. package/src/app/lib/components/ui/segmented/index.ts +13 -0
  262. package/src/app/lib/components/ui/segmented/segmented-context.ts +11 -0
  263. package/src/app/lib/components/ui/segmented/segmented-item.component.ts +72 -0
  264. package/src/app/lib/components/ui/segmented/segmented-variants.ts +40 -0
  265. package/src/app/lib/components/ui/segmented/segmented.component.ts +99 -0
  266. package/src/app/lib/components/ui/select/index.ts +19 -0
  267. package/src/app/lib/components/ui/select/select-content.component.ts +97 -0
  268. package/src/app/lib/components/ui/select/select-context.ts +53 -0
  269. package/src/app/lib/components/ui/select/select-group.component.ts +56 -0
  270. package/src/app/lib/components/ui/select/select-item.component.ts +163 -0
  271. package/src/app/lib/components/ui/select/select-label.component.ts +32 -0
  272. package/src/app/lib/components/ui/select/select-separator.component.ts +34 -0
  273. package/src/app/lib/components/ui/select/select-trigger.component.ts +164 -0
  274. package/src/app/lib/components/ui/select/select-value.component.ts +49 -0
  275. package/src/app/lib/components/ui/select/select.component.ts +263 -0
  276. package/src/app/lib/components/ui/separator/index.ts +6 -0
  277. package/src/app/lib/components/ui/separator/separator.component.ts +128 -0
  278. package/src/app/lib/components/ui/sheet/index.ts +11 -0
  279. package/src/app/lib/components/ui/sheet/sheet-close.component.ts +32 -0
  280. package/src/app/lib/components/ui/sheet/sheet-content.component.ts +157 -0
  281. package/src/app/lib/components/ui/sheet/sheet-context.ts +15 -0
  282. package/src/app/lib/components/ui/sheet/sheet-description.component.ts +34 -0
  283. package/src/app/lib/components/ui/sheet/sheet-footer.component.ts +28 -0
  284. package/src/app/lib/components/ui/sheet/sheet-header.component.ts +28 -0
  285. package/src/app/lib/components/ui/sheet/sheet-title.component.ts +34 -0
  286. package/src/app/lib/components/ui/sheet/sheet-trigger.component.ts +38 -0
  287. package/src/app/lib/components/ui/sheet/sheet-variants.ts +22 -0
  288. package/src/app/lib/components/ui/sheet/sheet.component.ts +97 -0
  289. package/src/app/lib/components/ui/sidebar/index.ts +41 -0
  290. package/src/app/lib/components/ui/sidebar/sidebar-content.component.ts +31 -0
  291. package/src/app/lib/components/ui/sidebar/sidebar-context.ts +33 -0
  292. package/src/app/lib/components/ui/sidebar/sidebar-footer.component.ts +28 -0
  293. package/src/app/lib/components/ui/sidebar/sidebar-group-action.component.ts +33 -0
  294. package/src/app/lib/components/ui/sidebar/sidebar-group-content.component.ts +28 -0
  295. package/src/app/lib/components/ui/sidebar/sidebar-group-label.component.ts +32 -0
  296. package/src/app/lib/components/ui/sidebar/sidebar-group.component.ts +28 -0
  297. package/src/app/lib/components/ui/sidebar/sidebar-header.component.ts +28 -0
  298. package/src/app/lib/components/ui/sidebar/sidebar-input.component.ts +31 -0
  299. package/src/app/lib/components/ui/sidebar/sidebar-inset.component.ts +31 -0
  300. package/src/app/lib/components/ui/sidebar/sidebar-menu-action.component.ts +56 -0
  301. package/src/app/lib/components/ui/sidebar/sidebar-menu-badge.component.ts +42 -0
  302. package/src/app/lib/components/ui/sidebar/sidebar-menu-button.component.ts +64 -0
  303. package/src/app/lib/components/ui/sidebar/sidebar-menu-item.component.ts +32 -0
  304. package/src/app/lib/components/ui/sidebar/sidebar-menu-skeleton.component.ts +39 -0
  305. package/src/app/lib/components/ui/sidebar/sidebar-menu-sub-button.component.ts +59 -0
  306. package/src/app/lib/components/ui/sidebar/sidebar-menu-sub-item.component.ts +25 -0
  307. package/src/app/lib/components/ui/sidebar/sidebar-menu-sub.component.ts +32 -0
  308. package/src/app/lib/components/ui/sidebar/sidebar-menu.component.ts +31 -0
  309. package/src/app/lib/components/ui/sidebar/sidebar-provider.component.ts +141 -0
  310. package/src/app/lib/components/ui/sidebar/sidebar-rail.component.ts +47 -0
  311. package/src/app/lib/components/ui/sidebar/sidebar-route-active.service.ts +124 -0
  312. package/src/app/lib/components/ui/sidebar/sidebar-separator.component.ts +28 -0
  313. package/src/app/lib/components/ui/sidebar/sidebar-trigger.component.ts +57 -0
  314. package/src/app/lib/components/ui/sidebar/sidebar.component.ts +130 -0
  315. package/src/app/lib/components/ui/skeleton/index.ts +1 -0
  316. package/src/app/lib/components/ui/skeleton/skeleton.component.ts +52 -0
  317. package/src/app/lib/components/ui/slider/index.ts +6 -0
  318. package/src/app/lib/components/ui/slider/slider.component.ts +477 -0
  319. package/src/app/lib/components/ui/spinner/index.ts +3 -0
  320. package/src/app/lib/components/ui/spinner/spinner-variants.ts +32 -0
  321. package/src/app/lib/components/ui/spinner/spinner.component.ts +77 -0
  322. package/src/app/lib/components/ui/switch/index.ts +6 -0
  323. package/src/app/lib/components/ui/switch/switch.component.ts +282 -0
  324. package/src/app/lib/components/ui/table/index.ts +9 -0
  325. package/src/app/lib/components/ui/table/table-body.component.ts +28 -0
  326. package/src/app/lib/components/ui/table/table-caption.component.ts +28 -0
  327. package/src/app/lib/components/ui/table/table-cell.component.ts +31 -0
  328. package/src/app/lib/components/ui/table/table-footer.component.ts +28 -0
  329. package/src/app/lib/components/ui/table/table-head.component.ts +36 -0
  330. package/src/app/lib/components/ui/table/table-header.component.ts +28 -0
  331. package/src/app/lib/components/ui/table/table-row.component.ts +34 -0
  332. package/src/app/lib/components/ui/table/table.component.ts +52 -0
  333. package/src/app/lib/components/ui/tabs/index.ts +14 -0
  334. package/src/app/lib/components/ui/tabs/tabs-content.component.ts +132 -0
  335. package/src/app/lib/components/ui/tabs/tabs-context.ts +33 -0
  336. package/src/app/lib/components/ui/tabs/tabs-list.component.ts +228 -0
  337. package/src/app/lib/components/ui/tabs/tabs-trigger.component.ts +167 -0
  338. package/src/app/lib/components/ui/tabs/tabs.component.ts +203 -0
  339. package/src/app/lib/components/ui/textarea/index.ts +1 -0
  340. package/src/app/lib/components/ui/textarea/textarea.component.ts +44 -0
  341. package/src/app/lib/components/ui/toast/index.ts +16 -0
  342. package/src/app/lib/components/ui/toast/toast-action.component.ts +77 -0
  343. package/src/app/lib/components/ui/toast/toast-description.component.ts +52 -0
  344. package/src/app/lib/components/ui/toast/toast-title.component.ts +52 -0
  345. package/src/app/lib/components/ui/toast/toast-variants.ts +24 -0
  346. package/src/app/lib/components/ui/toast/toast.component.ts +177 -0
  347. package/src/app/lib/components/ui/toast/toast.service.ts +202 -0
  348. package/src/app/lib/components/ui/toast/toaster.component.ts +128 -0
  349. package/src/app/lib/components/ui/toggle/index.ts +6 -0
  350. package/src/app/lib/components/ui/toggle/toggle-variants.ts +30 -0
  351. package/src/app/lib/components/ui/toggle/toggle.component.ts +199 -0
  352. package/src/app/lib/components/ui/toggle-group/index.ts +11 -0
  353. package/src/app/lib/components/ui/toggle-group/toggle-group-context.ts +48 -0
  354. package/src/app/lib/components/ui/toggle-group/toggle-group-item.component.ts +241 -0
  355. package/src/app/lib/components/ui/toggle-group/toggle-group.component.ts +288 -0
  356. package/src/app/lib/components/ui/tooltip/index.ts +14 -0
  357. package/src/app/lib/components/ui/tooltip/tooltip-content.component.ts +154 -0
  358. package/src/app/lib/components/ui/tooltip/tooltip-context.ts +29 -0
  359. package/src/app/lib/components/ui/tooltip/tooltip-provider.component.ts +95 -0
  360. package/src/app/lib/components/ui/tooltip/tooltip-trigger.component.ts +138 -0
  361. package/src/app/lib/components/ui/tooltip/tooltip.component.ts +159 -0
  362. package/src/app/lib/components/ui/typography/index.ts +13 -0
  363. package/src/app/lib/components/ui/typography/typography-blockquote.component.ts +31 -0
  364. package/src/app/lib/components/ui/typography/typography-h1.component.ts +32 -0
  365. package/src/app/lib/components/ui/typography/typography-h2.component.ts +32 -0
  366. package/src/app/lib/components/ui/typography/typography-h3.component.ts +29 -0
  367. package/src/app/lib/components/ui/typography/typography-h4.component.ts +29 -0
  368. package/src/app/lib/components/ui/typography/typography-inline-code.component.ts +31 -0
  369. package/src/app/lib/components/ui/typography/typography-large.component.ts +28 -0
  370. package/src/app/lib/components/ui/typography/typography-lead.component.ts +31 -0
  371. package/src/app/lib/components/ui/typography/typography-list.component.ts +31 -0
  372. package/src/app/lib/components/ui/typography/typography-muted.component.ts +28 -0
  373. package/src/app/lib/components/ui/typography/typography-p.component.ts +29 -0
  374. package/src/app/lib/components/ui/typography/typography-small.component.ts +28 -0
  375. package/src/app/lib/index.ts +7 -0
  376. package/src/app/lib/utils/accessibility/aria-id.service.ts +118 -0
  377. package/src/app/lib/utils/accessibility/click-outside.directive.ts +85 -0
  378. package/src/app/lib/utils/accessibility/focus-management.service.ts +231 -0
  379. package/src/app/lib/utils/accessibility/focus-trap.directive.ts +203 -0
  380. package/src/app/lib/utils/accessibility/index.ts +23 -0
  381. package/src/app/lib/utils/accessibility/keyboard-navigation.directive.ts +440 -0
  382. package/src/app/lib/utils/accessibility/live-region.directive.ts +260 -0
  383. package/src/app/lib/utils/accessibility/touch-target.directive.ts +81 -0
  384. package/src/app/lib/utils/accessibility/visually-hidden.component.ts +79 -0
  385. package/src/app/lib/utils/animation/animated.directive.ts +191 -0
  386. package/src/app/lib/utils/animation/animation-tokens.service.ts +88 -0
  387. package/src/app/lib/utils/animation/animation.types.ts +55 -0
  388. package/src/app/lib/utils/animation/animation.utils.ts +158 -0
  389. package/src/app/lib/utils/animation/index.ts +17 -0
  390. package/src/app/lib/utils/animation/presence.component.ts +168 -0
  391. package/src/app/lib/utils/animation/presence.directive.ts +169 -0
  392. package/src/app/lib/utils/cn.ts +15 -0
  393. package/src/app/lib/utils/index.ts +11 -0
  394. package/src/app/lib/utils/positioning/index.ts +218 -0
@@ -0,0 +1,148 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ afterNextRender,
4
+ ChangeDetectionStrategy,
5
+ Component,
6
+ computed,
7
+ effect,
8
+ ElementRef,
9
+ inject,
10
+ input,
11
+ OnDestroy,
12
+ OnInit,
13
+ output,
14
+ } from '@angular/core';
15
+ import { COMMAND_CONTEXT } from './command-context';
16
+
17
+ let itemIndexCounter = 0;
18
+
19
+ /**
20
+ * CommandItem component - a single item in the command list.
21
+ * Matches shadcn/ui React CommandItem exactly.
22
+ * Implements option role with proper focus management.
23
+ */
24
+ @Component({
25
+ selector: 'CommandItem',
26
+ template: `<ng-content />`,
27
+ host: {
28
+ '[class]': 'computedClass()',
29
+ '[attr.role]': '"option"',
30
+ '[attr.id]': 'itemId',
31
+ '[attr.data-command-index]': 'visibleIndex()',
32
+ '[attr.tabindex]': '"-1"',
33
+ '[attr.data-disabled]': 'disabled() ? "" : null',
34
+ '[attr.data-selected]': 'isFocused() ? "" : null',
35
+ '[attr.aria-selected]': 'isFocused()',
36
+ '[attr.aria-disabled]': 'disabled()',
37
+ '[hidden]': '!isVisible()',
38
+ '(click)': 'handleClick()',
39
+ },
40
+ changeDetection: ChangeDetectionStrategy.OnPush,
41
+ })
42
+ export class CommandItem implements OnInit, OnDestroy {
43
+ protected readonly context = inject(COMMAND_CONTEXT);
44
+ private readonly elementRef = inject(ElementRef);
45
+
46
+ readonly itemIndex = itemIndexCounter++;
47
+ readonly itemId = `command-item-${this.itemIndex}`;
48
+
49
+ /** Unique value for this item */
50
+ readonly value = input<string>('');
51
+
52
+ /** Keywords for search filtering */
53
+ readonly keywords = input<string[]>([]);
54
+
55
+ /** Whether the item is disabled */
56
+ readonly disabled = input<boolean>(false);
57
+
58
+ /** Additional CSS classes */
59
+ readonly class = input<string>('');
60
+
61
+ /** Select event emitted when item is clicked */
62
+ readonly onSelect = output<string>();
63
+
64
+ /** Whether item matches current search filter */
65
+ protected readonly isVisible = computed(() => {
66
+ return this.context.shouldShowItem(this.value(), this.keywords());
67
+ });
68
+
69
+ /** Get visible index among shown items */
70
+ protected readonly visibleIndex = computed(() => {
71
+ if (!this.isVisible()) return -1;
72
+
73
+ const parent = this.elementRef.nativeElement.closest('CommandList, [role="listbox"]');
74
+ if (parent) {
75
+ const visibleItems = Array.from(
76
+ parent.querySelectorAll('CommandItem:not([hidden])')
77
+ );
78
+ return visibleItems.indexOf(this.elementRef.nativeElement);
79
+ }
80
+ return this.localIndex;
81
+ });
82
+
83
+ protected readonly isFocused = computed(() => {
84
+ const focusedIdx = this.context.focusedIndex();
85
+ return this.isVisible() && this.getLocalIndex() === focusedIdx;
86
+ });
87
+
88
+ private localIndex = -1;
89
+
90
+ protected readonly computedClass = computed(() =>
91
+ cn(
92
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[selected]:bg-accent data-[selected]:text-accent-foreground data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
93
+ !this.disabled() && 'cursor-pointer hover:bg-accent hover:text-accent-foreground',
94
+ this.class()
95
+ )
96
+ );
97
+
98
+ constructor() {
99
+ // Scroll into view when focused
100
+ effect(() => {
101
+ if (this.isFocused()) {
102
+ this.elementRef.nativeElement.scrollIntoView({ block: 'nearest' });
103
+ }
104
+ });
105
+
106
+ // Update local index after render (browser-only)
107
+ afterNextRender(() => {
108
+ this.updateLocalIndex();
109
+ this.context.itemCount.update(c => c + 1);
110
+ });
111
+ }
112
+
113
+ ngOnInit(): void {
114
+ this.context.registerItem(this.value());
115
+ }
116
+
117
+ ngOnDestroy(): void {
118
+ this.context.unregisterItem(this.value());
119
+ this.context.itemCount.update(c => Math.max(0, c - 1));
120
+ }
121
+
122
+ private updateLocalIndex(): void {
123
+ // Find our position among sibling command items
124
+ const parent = this.elementRef.nativeElement.closest('CommandList, [role="listbox"]');
125
+ if (parent) {
126
+ const items = Array.from(parent.querySelectorAll('CommandItem'));
127
+ this.localIndex = items.indexOf(this.elementRef.nativeElement);
128
+ }
129
+ }
130
+
131
+ private getLocalIndex(): number {
132
+ // Dynamically compute index based on visible DOM position
133
+ const parent = this.elementRef.nativeElement.closest('CommandList, [role="listbox"]');
134
+ if (parent) {
135
+ const visibleItems = Array.from(
136
+ parent.querySelectorAll('CommandItem:not([hidden])')
137
+ );
138
+ return visibleItems.indexOf(this.elementRef.nativeElement);
139
+ }
140
+ return this.localIndex;
141
+ }
142
+
143
+ protected handleClick(): void {
144
+ if (this.disabled() || !this.isVisible()) return;
145
+ this.context.selectedValue.set(this.value());
146
+ this.onSelect.emit(this.value());
147
+ }
148
+ }
@@ -0,0 +1,30 @@
1
+ import { cn } from '@/lib/utils';
2
+ import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';
3
+ import { COMMAND_CONTEXT } from './command-context';
4
+
5
+ /**
6
+ * CommandList component - the scrollable list of items.
7
+ * Matches shadcn/ui React CommandList exactly.
8
+ * Implements listbox role for accessibility.
9
+ */
10
+ @Component({
11
+ selector: 'CommandList',
12
+ template: `<ng-content />`,
13
+ host: {
14
+ '[class]': 'computedClass()',
15
+ '[attr.id]': 'context.listId',
16
+ 'role': 'listbox',
17
+ '[attr.aria-label]': '"Command suggestions"',
18
+ },
19
+ changeDetection: ChangeDetectionStrategy.OnPush,
20
+ })
21
+ export class CommandList {
22
+ protected readonly context = inject(COMMAND_CONTEXT);
23
+
24
+ /** Additional CSS classes */
25
+ readonly class = input<string>('');
26
+
27
+ protected readonly computedClass = computed(() =>
28
+ cn('max-h-[300px] overflow-y-auto overflow-x-hidden', this.class())
29
+ );
30
+ }
@@ -0,0 +1,23 @@
1
+ import { cn } from '@/lib/utils';
2
+ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
3
+
4
+ /**
5
+ * CommandSeparator component - a separator between groups.
6
+ * Matches shadcn/ui React CommandSeparator exactly.
7
+ */
8
+ @Component({
9
+ selector: 'CommandSeparator',
10
+ template: ``,
11
+ host: {
12
+ '[class]': 'computedClass()',
13
+ },
14
+ changeDetection: ChangeDetectionStrategy.OnPush,
15
+ })
16
+ export class CommandSeparator {
17
+ /** Additional CSS classes */
18
+ readonly class = input<string>('');
19
+
20
+ protected readonly computedClass = computed(() =>
21
+ cn('-mx-1 h-px bg-border', this.class())
22
+ );
23
+ }
@@ -0,0 +1,23 @@
1
+ import { cn } from '@/lib/utils';
2
+ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
3
+
4
+ /**
5
+ * CommandShortcut component - displays keyboard shortcut hint.
6
+ * Matches shadcn/ui React CommandShortcut exactly.
7
+ */
8
+ @Component({
9
+ selector: 'CommandShortcut',
10
+ template: `<ng-content />`,
11
+ host: {
12
+ '[class]': 'computedClass()',
13
+ },
14
+ changeDetection: ChangeDetectionStrategy.OnPush,
15
+ })
16
+ export class CommandShortcut {
17
+ /** Additional CSS classes */
18
+ readonly class = input<string>('');
19
+
20
+ protected readonly computedClass = computed(() =>
21
+ cn('ml-auto text-xs tracking-widest text-muted-foreground', this.class())
22
+ );
23
+ }
@@ -0,0 +1,105 @@
1
+ import { cn } from '@/lib/utils';
2
+ import { ChangeDetectionStrategy, Component, computed, forwardRef, input, signal } from '@angular/core';
3
+ import { COMMAND_CONTEXT, type CommandContextValue, type CommandFilterFunction } from './command-context';
4
+
5
+ let commandIdCounter = 0;
6
+
7
+ /**
8
+ * Default filter function for command items.
9
+ */
10
+ const defaultFilterFn: CommandFilterFunction = (value: string, search: string, keywords?: string[]): number => {
11
+ if (!search.trim()) return 1;
12
+
13
+ const extendedValue = keywords ? `${value} ${keywords.join(' ')}` : value;
14
+ const normalizedValue = extendedValue.toLowerCase();
15
+ const normalizedSearch = search.toLowerCase();
16
+
17
+ // Exact match scores highest
18
+ if (normalizedValue === normalizedSearch) return 1;
19
+
20
+ // Prefix match
21
+ if (normalizedValue.startsWith(normalizedSearch)) return 0.8;
22
+
23
+ // Check if any word starts with search
24
+ const words = normalizedValue.split(' ');
25
+ for (const word of words) {
26
+ if (word.startsWith(normalizedSearch)) return 0.7;
27
+ }
28
+
29
+ // Contains match
30
+ if (normalizedValue.includes(normalizedSearch)) return 0.5;
31
+
32
+ // No match
33
+ return 0;
34
+ };
35
+
36
+ /**
37
+ * Command component - a command palette/menu component.
38
+ * Matches shadcn/ui React Command exactly.
39
+ * Implements combobox pattern with proper ARIA roles and keyboard navigation.
40
+ */
41
+ @Component({
42
+ selector: 'Command',
43
+ template: `<ng-content />`,
44
+ providers: [
45
+ {
46
+ provide: COMMAND_CONTEXT,
47
+ useExisting: forwardRef(() => Command),
48
+ },
49
+ ],
50
+ host: {
51
+ '[class]': 'computedClass()',
52
+ },
53
+ changeDetection: ChangeDetectionStrategy.OnPush,
54
+ })
55
+ export class Command implements CommandContextValue {
56
+ /** Additional CSS classes */
57
+ readonly class = input<string>('');
58
+
59
+ /** Custom filter function for search */
60
+ readonly filter = input<CommandFilterFunction | undefined>(undefined);
61
+
62
+ // CommandContextValue implementation
63
+ private readonly _id = commandIdCounter++;
64
+ private readonly _items: string[] = [];
65
+
66
+ readonly search = signal('');
67
+ readonly selectedValue = signal('');
68
+ readonly focusedIndex = signal(-1);
69
+ readonly itemCount = signal(0);
70
+ readonly visibleItemCount = signal(0);
71
+ readonly listId = `command-list-${this._id}`;
72
+ readonly inputId = `command-input-${this._id}`;
73
+
74
+ readonly filterFunction = computed(() => {
75
+ return this.filter() ?? defaultFilterFn;
76
+ });
77
+
78
+ registerItem = (value: string) => {
79
+ if (!this._items.includes(value)) {
80
+ this._items.push(value);
81
+ }
82
+ };
83
+
84
+ unregisterItem = (value: string) => {
85
+ const index = this._items.indexOf(value);
86
+ if (index > -1) {
87
+ this._items.splice(index, 1);
88
+ }
89
+ };
90
+
91
+ getItems = () => this._items;
92
+
93
+ shouldShowItem = (value: string, keywords?: string[]): boolean => {
94
+ const searchValue = this.search();
95
+ if (!searchValue) return true;
96
+ return this.filterFunction()(value, searchValue, keywords) > 0;
97
+ };
98
+
99
+ protected readonly computedClass = computed(() =>
100
+ cn(
101
+ 'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
102
+ this.class()
103
+ )
104
+ );
105
+ }
@@ -0,0 +1,11 @@
1
+ export { COMMAND_CONTEXT, type CommandContextValue } from './command-context';
2
+ export { CommandDialog } from './command-dialog.component';
3
+ export { CommandEmpty } from './command-empty.component';
4
+ export { CommandGroup } from './command-group.component';
5
+ export { CommandInput } from './command-input.component';
6
+ export { CommandItem } from './command-item.component';
7
+ export { CommandList } from './command-list.component';
8
+ export { CommandSeparator } from './command-separator.component';
9
+ export { CommandShortcut } from './command-shortcut.component';
10
+ export { Command } from './command.component';
11
+
@@ -0,0 +1,68 @@
1
+ import { cn } from '@/lib/utils';
2
+ import { ChangeDetectionStrategy, Component, computed, inject, input, model, output } from '@angular/core';
3
+ import { Check, LucideAngularModule } from 'lucide-angular';
4
+ import { CONTEXT_MENU_CONTEXT } from './context-menu-context';
5
+
6
+ /**
7
+ * ContextMenuCheckboxItem component - a checkbox item in the context menu.
8
+ * Matches shadcn/ui React ContextMenuCheckboxItem exactly.
9
+ */
10
+ @Component({
11
+ selector: 'ContextMenuCheckboxItem',
12
+ imports: [LucideAngularModule],
13
+ template: `
14
+ <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
15
+ @if (checked()) {
16
+ <lucide-icon [img]="CheckIcon" class="h-4 w-4" />
17
+ }
18
+ </span>
19
+ <ng-content />
20
+ `,
21
+ host: {
22
+ '[class]': 'computedClass()',
23
+ '[attr.role]': '"menuitemcheckbox"',
24
+ '[attr.aria-checked]': 'checked()',
25
+ '[attr.tabindex]': 'disabled() ? -1 : 0',
26
+ '[attr.aria-disabled]': 'disabled()',
27
+ '[attr.data-disabled]': 'disabled() ? "" : null',
28
+ '[attr.data-state]': 'checked() ? "checked" : "unchecked"',
29
+ '(click)': 'handleClick($event)',
30
+ '(keydown.enter)': 'handleClick($event)',
31
+ '(keydown.space)': 'handleClick($event)',
32
+ },
33
+ changeDetection: ChangeDetectionStrategy.OnPush,
34
+ })
35
+ export class ContextMenuCheckboxItem {
36
+ private readonly context = inject(CONTEXT_MENU_CONTEXT);
37
+ protected readonly CheckIcon = Check;
38
+
39
+ /** Whether the checkbox is checked */
40
+ readonly checked = model<boolean>(false);
41
+
42
+ /** Whether the item is disabled */
43
+ readonly disabled = input<boolean>(false);
44
+
45
+ /** Additional CSS classes */
46
+ readonly class = input<string>('');
47
+
48
+ /** Checked change event */
49
+ readonly onCheckedChange = output<boolean>();
50
+
51
+ protected readonly computedClass = computed(() =>
52
+ cn(
53
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
54
+ !this.disabled() && 'cursor-pointer hover:bg-accent hover:text-accent-foreground',
55
+ this.class()
56
+ )
57
+ );
58
+
59
+ protected handleClick(event: Event): void {
60
+ if (this.disabled()) {
61
+ event.preventDefault();
62
+ return;
63
+ }
64
+ const newValue = !this.checked();
65
+ this.checked.set(newValue);
66
+ this.onCheckedChange.emit(newValue);
67
+ }
68
+ }
@@ -0,0 +1,213 @@
1
+ import { cn, Presence } from '@/lib/utils';
2
+ import {
3
+ afterNextRender,
4
+ ChangeDetectionStrategy,
5
+ Component,
6
+ computed,
7
+ effect,
8
+ ElementRef,
9
+ inject,
10
+ input,
11
+ OnDestroy,
12
+ } from '@angular/core';
13
+ import { CONTEXT_MENU_CONTEXT } from './context-menu-context';
14
+
15
+ /**
16
+ * ContextMenuContent component - the content panel of the context menu.
17
+ * Matches shadcn/ui React ContextMenuContent exactly.
18
+ * Includes full keyboard navigation: Arrow keys, Home/End, typeahead, roving tabindex.
19
+ */
20
+ @Component({
21
+ selector: 'ContextMenuContent',
22
+ imports: [Presence],
23
+ template: `
24
+ <Presence [present]="context.open()">
25
+ <div
26
+ [class]="computedClass()"
27
+ [attr.data-state]="context.open() ? 'open' : 'closed'"
28
+ [style.position]="'fixed'"
29
+ [style.left.px]="context.position().x"
30
+ [style.top.px]="context.position().y"
31
+ role="menu"
32
+ aria-orientation="vertical"
33
+ tabindex="-1"
34
+ (keydown)="onKeydown($event)"
35
+ >
36
+ <ng-content />
37
+ </div>
38
+ </Presence>
39
+ `,
40
+ host: {
41
+ class: 'contents',
42
+ '(document:click)': 'onDocumentClick()',
43
+ '(document:keydown.escape)': 'onEscapeKey()',
44
+ '(document:contextmenu)': 'onAnotherContextMenu()',
45
+ },
46
+ changeDetection: ChangeDetectionStrategy.OnPush,
47
+ })
48
+ export class ContextMenuContent implements OnDestroy {
49
+ protected readonly context = inject(CONTEXT_MENU_CONTEXT);
50
+ private readonly elementRef = inject(ElementRef);
51
+
52
+ /** Additional CSS classes */
53
+ readonly class = input<string>('');
54
+
55
+ private menuItems: HTMLElement[] = [];
56
+ private typeaheadBuffer = '';
57
+ private typeaheadTimeout: ReturnType<typeof setTimeout> | null = null;
58
+
59
+ protected readonly computedClass = computed(() =>
60
+ cn(
61
+ 'z-50 min-w-[12rem] overflow-hidden rounded-xl border bg-popover p-2 text-popover-foreground shadow-lg',
62
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out',
63
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
64
+ 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
65
+ this.class()
66
+ )
67
+ );
68
+
69
+ constructor() {
70
+ // Focus first item when menu opens
71
+ effect(() => {
72
+ if (this.context.open()) {
73
+ setTimeout(() => {
74
+ this.updateMenuItems();
75
+ const focusedIdx = this.context.focusedIndex();
76
+ if (focusedIdx >= 0 && this.menuItems[focusedIdx]) {
77
+ this.menuItems[focusedIdx].focus();
78
+ } else if (this.menuItems.length > 0) {
79
+ this.menuItems[0].focus();
80
+ this.context.focusedIndex.set(0);
81
+ }
82
+ }, 0);
83
+ }
84
+ });
85
+
86
+ // Initial menu items update (browser-only)
87
+ afterNextRender(() => {
88
+ this.updateMenuItems();
89
+ });
90
+ }
91
+
92
+ ngOnDestroy(): void {
93
+ if (this.typeaheadTimeout) {
94
+ clearTimeout(this.typeaheadTimeout);
95
+ }
96
+ }
97
+
98
+ private updateMenuItems(): void {
99
+ const content = this.elementRef.nativeElement.querySelector('[role="menu"]');
100
+ if (content) {
101
+ this.menuItems = Array.from(
102
+ content.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"]):not([data-disabled])')
103
+ );
104
+ }
105
+ }
106
+
107
+ protected onKeydown(event: KeyboardEvent): void {
108
+ this.updateMenuItems();
109
+
110
+ switch (event.key) {
111
+ case 'ArrowDown':
112
+ event.preventDefault();
113
+ this.focusNext();
114
+ break;
115
+ case 'ArrowUp':
116
+ event.preventDefault();
117
+ this.focusPrevious();
118
+ break;
119
+ case 'Home':
120
+ event.preventDefault();
121
+ this.focusFirst();
122
+ break;
123
+ case 'End':
124
+ event.preventDefault();
125
+ this.focusLast();
126
+ break;
127
+ case 'Tab':
128
+ // Close menu and let tab continue naturally
129
+ this.close();
130
+ break;
131
+ default:
132
+ // Typeahead search
133
+ if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
134
+ this.handleTypeahead(event.key);
135
+ }
136
+ break;
137
+ }
138
+ }
139
+
140
+ private focusNext(): void {
141
+ const currentIndex = this.context.focusedIndex();
142
+ const nextIndex = currentIndex < this.menuItems.length - 1 ? currentIndex + 1 : 0;
143
+ this.focusItem(nextIndex);
144
+ }
145
+
146
+ private focusPrevious(): void {
147
+ const currentIndex = this.context.focusedIndex();
148
+ const prevIndex = currentIndex > 0 ? currentIndex - 1 : this.menuItems.length - 1;
149
+ this.focusItem(prevIndex);
150
+ }
151
+
152
+ private focusFirst(): void {
153
+ this.focusItem(0);
154
+ }
155
+
156
+ private focusLast(): void {
157
+ this.focusItem(this.menuItems.length - 1);
158
+ }
159
+
160
+ private focusItem(index: number): void {
161
+ if (index >= 0 && index < this.menuItems.length) {
162
+ // Update roving tabindex
163
+ this.menuItems.forEach((item, i) => {
164
+ item.setAttribute('tabindex', i === index ? '0' : '-1');
165
+ });
166
+ this.menuItems[index].focus();
167
+ this.context.focusedIndex.set(index);
168
+ }
169
+ }
170
+
171
+ private handleTypeahead(key: string): void {
172
+ this.typeaheadBuffer += key.toLowerCase();
173
+
174
+ if (this.typeaheadTimeout) {
175
+ clearTimeout(this.typeaheadTimeout);
176
+ }
177
+
178
+ this.typeaheadTimeout = setTimeout(() => {
179
+ this.typeaheadBuffer = '';
180
+ }, 500);
181
+
182
+ // Find first matching item
183
+ const matchIndex = this.menuItems.findIndex((item) =>
184
+ item.textContent?.toLowerCase().trim().startsWith(this.typeaheadBuffer)
185
+ );
186
+
187
+ if (matchIndex >= 0) {
188
+ this.focusItem(matchIndex);
189
+ }
190
+ }
191
+
192
+ private close(): void {
193
+ this.context.open.set(false);
194
+ this.context.focusedIndex.set(-1);
195
+ // Restore focus to trigger element
196
+ const triggerEl = this.context.triggerElement();
197
+ if (triggerEl) {
198
+ triggerEl.focus();
199
+ }
200
+ }
201
+
202
+ protected onDocumentClick(): void {
203
+ this.close();
204
+ }
205
+
206
+ protected onEscapeKey(): void {
207
+ this.close();
208
+ }
209
+
210
+ protected onAnotherContextMenu(): void {
211
+ // Will be handled by new context menu trigger
212
+ }
213
+ }
@@ -0,0 +1,17 @@
1
+ import { InjectionToken, type WritableSignal } from '@angular/core';
2
+
3
+ export interface ContextMenuPosition {
4
+ x: number;
5
+ y: number;
6
+ }
7
+
8
+ export interface ContextMenuContextValue {
9
+ open: WritableSignal<boolean>;
10
+ position: WritableSignal<ContextMenuPosition>;
11
+ focusedIndex: WritableSignal<number>;
12
+ triggerElement: WritableSignal<HTMLElement | null>;
13
+ }
14
+
15
+ export const CONTEXT_MENU_CONTEXT = new InjectionToken<ContextMenuContextValue>(
16
+ 'CONTEXT_MENU_CONTEXT'
17
+ );