@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,45 @@
1
+ import { ChangeDetectionStrategy, Component, ElementRef, inject } from '@angular/core';
2
+ import { DROPDOWN_MENU_CONTEXT } from './dropdown-menu-context';
3
+
4
+ /**
5
+ * DropdownMenuTrigger component - the trigger that opens the dropdown.
6
+ * Matches shadcn/ui React DropdownMenuTrigger exactly.
7
+ */
8
+ @Component({
9
+ selector: 'DropdownMenuTrigger',
10
+ template: `<ng-content />`,
11
+ host: {
12
+ class: 'cursor-pointer',
13
+ '(click)': 'toggle()',
14
+ '(keydown)': 'onKeyDown($event)',
15
+ '[attr.aria-expanded]': 'context.open()',
16
+ '[attr.aria-haspopup]': '"menu"',
17
+ '[attr.aria-controls]': 'context.open() ? context.contentId : null',
18
+ },
19
+ changeDetection: ChangeDetectionStrategy.OnPush,
20
+ })
21
+ export class DropdownMenuTrigger {
22
+ protected readonly context = inject(DROPDOWN_MENU_CONTEXT);
23
+ private readonly elementRef = inject(ElementRef<HTMLElement>);
24
+
25
+ toggle(): void {
26
+ this.context.triggerElement.set(this.elementRef.nativeElement);
27
+ this.context.open.update(v => !v);
28
+ }
29
+
30
+ onKeyDown(event: KeyboardEvent): void {
31
+ switch (event.key) {
32
+ case 'ArrowDown':
33
+ event.preventDefault();
34
+ this.context.triggerElement.set(this.elementRef.nativeElement);
35
+ this.context.open.set(true);
36
+ this.context.focusedIndex.set(0);
37
+ break;
38
+ case 'Enter':
39
+ case ' ':
40
+ event.preventDefault();
41
+ this.toggle();
42
+ break;
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,32 @@
1
+ import { AriaIdService } from '@/lib/utils/accessibility';
2
+ import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
3
+ import { DROPDOWN_MENU_CONTEXT, type DropdownMenuContextValue } from './dropdown-menu-context';
4
+
5
+ /**
6
+ * DropdownMenu component - root container for dropdown menu.
7
+ * Matches shadcn/ui React DropdownMenu exactly.
8
+ */
9
+ @Component({
10
+ selector: 'DropdownMenu',
11
+ template: `<ng-content />`,
12
+ providers: [
13
+ {
14
+ provide: DROPDOWN_MENU_CONTEXT,
15
+ useFactory: (ariaIdService: AriaIdService): DropdownMenuContextValue => {
16
+ const menuIds = ariaIdService.generateMenuIds('dropdown-menu');
17
+ return {
18
+ open: signal(false),
19
+ contentId: menuIds.contentId,
20
+ triggerElement: signal(null),
21
+ focusedIndex: signal(-1),
22
+ };
23
+ },
24
+ deps: [AriaIdService],
25
+ },
26
+ ],
27
+ host: {
28
+ class: 'relative inline-block',
29
+ },
30
+ changeDetection: ChangeDetectionStrategy.OnPush,
31
+ })
32
+ export class DropdownMenu {}
@@ -0,0 +1,16 @@
1
+ export { DropdownMenuCheckboxItem } from './dropdown-menu-checkbox-item.component';
2
+ export { DropdownMenuContent } from './dropdown-menu-content.component';
3
+ export { DROPDOWN_MENU_CONTEXT, type DropdownMenuContextValue } from './dropdown-menu-context';
4
+ export { DropdownMenuGroup } from './dropdown-menu-group.component';
5
+ export { DropdownMenuItem } from './dropdown-menu-item.component';
6
+ export { DropdownMenuLabel } from './dropdown-menu-label.component';
7
+ export { DROPDOWN_MENU_RADIO_GROUP_CONTEXT, DropdownMenuRadioGroup, type DropdownMenuRadioGroupContext } from './dropdown-menu-radio-group.component';
8
+ export { DropdownMenuRadioItem } from './dropdown-menu-radio-item.component';
9
+ export { DropdownMenuSeparator } from './dropdown-menu-separator.component';
10
+ export { DropdownMenuShortcut } from './dropdown-menu-shortcut.component';
11
+ export { DropdownMenuSubContent } from './dropdown-menu-sub-content.component';
12
+ export { DropdownMenuSubTrigger } from './dropdown-menu-sub-trigger.component';
13
+ export { DROPDOWN_MENU_SUB_CONTEXT, DropdownMenuSub, type DropdownMenuSubContext } from './dropdown-menu-sub.component';
14
+ export { DropdownMenuTrigger } from './dropdown-menu-trigger.component';
15
+ export { DropdownMenu } from './dropdown-menu.component';
16
+
@@ -0,0 +1,28 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ input,
7
+ } from '@angular/core';
8
+
9
+ /**
10
+ * EmptyAction component - container for action buttons in empty state.
11
+ */
12
+ @Component({
13
+ selector: 'EmptyAction',
14
+ template: `<ng-content />`,
15
+ host: {
16
+ '[class]': 'computedClass()',
17
+ },
18
+ changeDetection: ChangeDetectionStrategy.OnPush,
19
+ })
20
+ export class EmptyAction {
21
+ /** Additional CSS classes to apply */
22
+ readonly class = input<string>('');
23
+
24
+ /** Computed class combining base styles and custom classes */
25
+ protected readonly computedClass = computed(() =>
26
+ cn('mt-2', this.class())
27
+ );
28
+ }
@@ -0,0 +1,31 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ input,
7
+ } from '@angular/core';
8
+
9
+ /**
10
+ * EmptyDescription component - description for the empty state.
11
+ */
12
+ @Component({
13
+ selector: 'EmptyDescription',
14
+ template: `<ng-content />`,
15
+ host: {
16
+ '[class]': 'computedClass()',
17
+ },
18
+ changeDetection: ChangeDetectionStrategy.OnPush,
19
+ })
20
+ export class EmptyDescription {
21
+ /** Additional CSS classes to apply */
22
+ readonly class = input<string>('');
23
+
24
+ /** Computed class combining base styles and custom classes */
25
+ protected readonly computedClass = computed(() =>
26
+ cn(
27
+ 'mb-4 mt-2 text-sm text-muted-foreground max-w-sm mx-auto',
28
+ this.class()
29
+ )
30
+ );
31
+ }
@@ -0,0 +1,31 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ input,
7
+ } from '@angular/core';
8
+
9
+ /**
10
+ * EmptyIcon component - container for the empty state icon.
11
+ */
12
+ @Component({
13
+ selector: 'EmptyIcon',
14
+ template: `<ng-content />`,
15
+ host: {
16
+ '[class]': 'computedClass()',
17
+ },
18
+ changeDetection: ChangeDetectionStrategy.OnPush,
19
+ })
20
+ export class EmptyIcon {
21
+ /** Additional CSS classes to apply */
22
+ readonly class = input<string>('');
23
+
24
+ /** Computed class combining base styles and custom classes */
25
+ protected readonly computedClass = computed(() =>
26
+ cn(
27
+ 'mx-auto flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground [&>svg]:size-6',
28
+ this.class()
29
+ )
30
+ );
31
+ }
@@ -0,0 +1,28 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ input,
7
+ } from '@angular/core';
8
+
9
+ /**
10
+ * EmptyTitle component - title for the empty state.
11
+ */
12
+ @Component({
13
+ selector: 'EmptyTitle',
14
+ template: `<ng-content />`,
15
+ host: {
16
+ '[class]': 'computedClass()',
17
+ },
18
+ changeDetection: ChangeDetectionStrategy.OnPush,
19
+ })
20
+ export class EmptyTitle {
21
+ /** Additional CSS classes to apply */
22
+ readonly class = input<string>('');
23
+
24
+ /** Computed class combining base styles and custom classes */
25
+ protected readonly computedClass = computed(() =>
26
+ cn('mt-4 text-lg font-semibold', this.class())
27
+ );
28
+ }
@@ -0,0 +1,53 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ input,
7
+ } from '@angular/core';
8
+
9
+ /**
10
+ * Empty component - empty state placeholder for when there's no content.
11
+ *
12
+ * @example
13
+ * <!-- Basic empty state -->
14
+ * <Empty>
15
+ * <EmptyIcon>
16
+ * <svg>...</svg>
17
+ * </EmptyIcon>
18
+ * <EmptyTitle>No results found</EmptyTitle>
19
+ * <EmptyDescription>Try adjusting your search or filters.</EmptyDescription>
20
+ * </Empty>
21
+ *
22
+ * <!-- With action -->
23
+ * <Empty>
24
+ * <EmptyIcon>
25
+ * <svg>...</svg>
26
+ * </EmptyIcon>
27
+ * <EmptyTitle>No projects yet</EmptyTitle>
28
+ * <EmptyDescription>Create your first project to get started.</EmptyDescription>
29
+ * <EmptyAction>
30
+ * <Button>Create Project</Button>
31
+ * </EmptyAction>
32
+ * </Empty>
33
+ */
34
+ @Component({
35
+ selector: 'Empty',
36
+ template: `<ng-content />`,
37
+ host: {
38
+ '[class]': 'computedClass()',
39
+ },
40
+ changeDetection: ChangeDetectionStrategy.OnPush,
41
+ })
42
+ export class Empty {
43
+ /** Additional CSS classes to apply */
44
+ readonly class = input<string>('');
45
+
46
+ /** Computed class combining base styles and custom classes */
47
+ protected readonly computedClass = computed(() =>
48
+ cn(
49
+ 'flex min-h-[400px] flex-col items-center justify-center rounded-md border border-dashed p-8 text-center animate-in fade-in-50',
50
+ this.class()
51
+ )
52
+ );
53
+ }
@@ -0,0 +1,6 @@
1
+ export { EmptyAction } from './empty-action.component';
2
+ export { EmptyDescription } from './empty-description.component';
3
+ export { EmptyIcon } from './empty-icon.component';
4
+ export { EmptyTitle } from './empty-title.component';
5
+ export { Empty } from './empty.component';
6
+
@@ -0,0 +1,34 @@
1
+ import { InjectionToken, WritableSignal } from '@angular/core';
2
+ import { AbstractControl, FormGroup } from '@angular/forms';
3
+
4
+ // ============================================================================
5
+ // Types
6
+ // ============================================================================
7
+
8
+ export interface FormFieldContext {
9
+ /** The name of the form field */
10
+ name: WritableSignal<string>;
11
+ /** The form control for this field */
12
+ control: WritableSignal<AbstractControl | null>;
13
+ /** Unique ID for the form control element */
14
+ id: WritableSignal<string>;
15
+ /** ID for the form description element */
16
+ formDescriptionId: WritableSignal<string>;
17
+ /** ID for the form message element */
18
+ formMessageId: WritableSignal<string>;
19
+ }
20
+
21
+ export interface FormContext {
22
+ /** The reactive form group */
23
+ form: WritableSignal<FormGroup | null>;
24
+ }
25
+
26
+ // ============================================================================
27
+ // Injection Tokens
28
+ // ============================================================================
29
+
30
+ export const FORM_FIELD_CONTEXT = new InjectionToken<FormFieldContext>(
31
+ 'FormFieldContext'
32
+ );
33
+
34
+ export const FORM_CONTEXT = new InjectionToken<FormContext>('FormContext');
@@ -0,0 +1,137 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ AfterContentInit,
4
+ ChangeDetectionStrategy,
5
+ Component,
6
+ computed,
7
+ ContentChild,
8
+ DestroyRef,
9
+ Directive,
10
+ ElementRef,
11
+ inject,
12
+ input,
13
+ } from '@angular/core';
14
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
15
+ import { FORM_FIELD_CONTEXT } from './form-context';
16
+
17
+ /**
18
+ * Directive applied to form inputs within FormControl.
19
+ * Automatically sets id, aria-describedby, and aria-invalid attributes.
20
+ */
21
+ @Directive({
22
+ selector: 'input, select, textarea, [formControlInput]',
23
+ })
24
+ export class FormControlInput {
25
+ readonly elementRef = inject(ElementRef<HTMLInputElement>);
26
+ }
27
+
28
+ /**
29
+ * FormControl component - wrapper for form input elements.
30
+ * Automatically applies accessibility attributes to child inputs.
31
+ *
32
+ * @example
33
+ * <FormControl>
34
+ * <input type="email" formControlName="email" />
35
+ * </FormControl>
36
+ */
37
+ @Component({
38
+ selector: 'FormControl',
39
+ template: `<ng-content />`,
40
+ host: {
41
+ '[class]': 'computedClass()',
42
+ 'data-slot': 'form-control',
43
+ },
44
+ changeDetection: ChangeDetectionStrategy.OnPush,
45
+ })
46
+ export class FormControl implements AfterContentInit {
47
+ protected readonly fieldContext = inject(FORM_FIELD_CONTEXT, { optional: true });
48
+ private readonly destroyRef = inject(DestroyRef);
49
+
50
+ @ContentChild(FormControlInput, { static: false }) inputDirective?: FormControlInput;
51
+
52
+ /** Additional CSS classes to apply */
53
+ readonly class = input<string>('');
54
+
55
+ /** Check if field has error */
56
+ protected readonly hasError = computed(() => {
57
+ const control = this.fieldContext?.control();
58
+ return control?.invalid && (control?.dirty || control?.touched);
59
+ });
60
+
61
+ /** Compute aria-describedby attribute */
62
+ protected readonly ariaDescribedBy = computed(() => {
63
+ const descId = this.fieldContext?.formDescriptionId();
64
+ const msgId = this.fieldContext?.formMessageId();
65
+ const hasError = this.hasError();
66
+
67
+ if (!descId && !msgId) return null;
68
+
69
+ const parts: string[] = [];
70
+ if (descId) parts.push(descId);
71
+ if (hasError && msgId) parts.push(msgId);
72
+
73
+ return parts.join(' ') || null;
74
+ });
75
+
76
+ /** Computed class combining base styles and custom classes */
77
+ protected readonly computedClass = computed(() =>
78
+ cn('relative', this.class())
79
+ );
80
+
81
+ ngAfterContentInit(): void {
82
+ this.applyAccessibilityAttributes();
83
+ }
84
+
85
+ private applyAccessibilityAttributes(): void {
86
+ if (!this.inputDirective || !this.fieldContext) return;
87
+
88
+ const element = this.inputDirective.elementRef.nativeElement;
89
+
90
+ // Set the id to match the label's 'for' attribute
91
+ const id = this.fieldContext.id();
92
+ if (id) {
93
+ element.setAttribute('id', id);
94
+ }
95
+
96
+ // Apply aria-describedby
97
+ const describedBy = this.ariaDescribedBy();
98
+ if (describedBy) {
99
+ element.setAttribute('aria-describedby', describedBy);
100
+ }
101
+
102
+ // Apply aria-invalid when there's an error
103
+ if (this.hasError()) {
104
+ element.setAttribute('aria-invalid', 'true');
105
+ }
106
+
107
+ // Update attributes when control state changes
108
+ const control = this.fieldContext.control();
109
+ if (control?.statusChanges) {
110
+ control.statusChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
111
+ this.updateAriaInvalid();
112
+ });
113
+ }
114
+ }
115
+
116
+ private updateAriaInvalid(): void {
117
+ if (!this.inputDirective) return;
118
+ const element = this.inputDirective.elementRef.nativeElement;
119
+
120
+ if (this.hasError()) {
121
+ element.setAttribute('aria-invalid', 'true');
122
+ const describedBy = this.ariaDescribedBy();
123
+ if (describedBy) {
124
+ element.setAttribute('aria-describedby', describedBy);
125
+ }
126
+ } else {
127
+ element.removeAttribute('aria-invalid');
128
+ // Keep description but remove message ID from describedby
129
+ const descId = this.fieldContext?.formDescriptionId();
130
+ if (descId) {
131
+ element.setAttribute('aria-describedby', descId);
132
+ } else {
133
+ element.removeAttribute('aria-describedby');
134
+ }
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,37 @@
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
+ * FormDescription component - helper text for a form field.
13
+ *
14
+ * @example
15
+ * <FormDescription>Enter your email address</FormDescription>
16
+ */
17
+ @Component({
18
+ selector: 'FormDescription',
19
+ template: `<ng-content />`,
20
+ host: {
21
+ '[class]': 'computedClass()',
22
+ '[attr.id]': 'fieldContext?.formDescriptionId()',
23
+ 'data-slot': 'form-description',
24
+ },
25
+ changeDetection: ChangeDetectionStrategy.OnPush,
26
+ })
27
+ export class FormDescription {
28
+ protected readonly fieldContext = inject(FORM_FIELD_CONTEXT, { optional: true });
29
+
30
+ /** Additional CSS classes to apply */
31
+ readonly class = input<string>('');
32
+
33
+ /** Computed class combining base styles and custom classes */
34
+ protected readonly computedClass = computed(() =>
35
+ cn('text-muted-foreground text-[0.8rem]', this.class())
36
+ );
37
+ }
@@ -0,0 +1,84 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ forwardRef,
7
+ inject,
8
+ input,
9
+ signal,
10
+ } from '@angular/core';
11
+ import { FORM_CONTEXT, FORM_FIELD_CONTEXT, type FormFieldContext } from './form-context';
12
+
13
+ /**
14
+ * FormField component - provides context for a single form field.
15
+ *
16
+ * @example
17
+ * <FormField name="email">
18
+ * <FormItem>
19
+ * <FormLabel>Email</FormLabel>
20
+ * <FormControl>
21
+ * <Input type="email" formControlName="email" />
22
+ * </FormControl>
23
+ * <FormMessage />
24
+ * </FormItem>
25
+ * </FormField>
26
+ */
27
+ @Component({
28
+ selector: 'FormField',
29
+ template: `<ng-content />`,
30
+ host: {
31
+ '[class]': 'computedClass()',
32
+ 'data-slot': 'form-field',
33
+ },
34
+ providers: [
35
+ {
36
+ provide: FORM_FIELD_CONTEXT,
37
+ useFactory: (component: FormField) => component.fieldContext,
38
+ deps: [forwardRef(() => FormField)],
39
+ },
40
+ ],
41
+ changeDetection: ChangeDetectionStrategy.OnPush,
42
+ })
43
+ export class FormField {
44
+ private readonly formContext = inject(FORM_CONTEXT, { optional: true });
45
+
46
+ /** The name of the form control */
47
+ readonly name = input.required<string>();
48
+
49
+ /** Additional CSS classes to apply */
50
+ readonly class = input<string>('');
51
+
52
+ /** Generate unique IDs */
53
+ private readonly uniqueId = `form-field-${Math.random().toString(36).substring(7)}`;
54
+
55
+ /** Context for child components */
56
+ readonly fieldContext: FormFieldContext = {
57
+ name: signal(''),
58
+ control: signal(null),
59
+ id: signal(this.uniqueId),
60
+ formDescriptionId: signal(`${this.uniqueId}-description`),
61
+ formMessageId: signal(`${this.uniqueId}-message`),
62
+ };
63
+
64
+ /** Computed class combining base styles and custom classes */
65
+ protected readonly computedClass = computed(() =>
66
+ cn('space-y-2', this.class())
67
+ );
68
+
69
+ ngOnInit() {
70
+ this.fieldContext.name.set(this.name());
71
+ const form = this.formContext?.form();
72
+ if (form) {
73
+ this.fieldContext.control.set(form.get(this.name()));
74
+ }
75
+ }
76
+
77
+ ngOnChanges() {
78
+ this.fieldContext.name.set(this.name());
79
+ const form = this.formContext?.form();
80
+ if (form) {
81
+ this.fieldContext.control.set(form.get(this.name()));
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,42 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ input,
7
+ } from '@angular/core';
8
+
9
+ /**
10
+ * FormItem component - container for form field elements.
11
+ *
12
+ * @example
13
+ * <FormItem>
14
+ * <FormLabel>Email</FormLabel>
15
+ * <FormControl>
16
+ * <Input type="email" />
17
+ * </FormControl>
18
+ * <FormDescription>Enter your email</FormDescription>
19
+ * <FormMessage />
20
+ * </FormItem>
21
+ */
22
+ @Component({
23
+ selector: 'FormItem',
24
+ template: `<ng-content />`,
25
+ host: {
26
+ '[class]': 'computedClass()',
27
+ 'data-slot': 'form-item',
28
+ },
29
+ changeDetection: ChangeDetectionStrategy.OnPush,
30
+ })
31
+ export class FormItem {
32
+ /** Additional CSS classes to apply */
33
+ readonly class = input<string>('');
34
+
35
+ /** Computed class combining base styles and custom classes */
36
+ protected readonly computedClass = computed(() =>
37
+ cn(
38
+ 'flex flex-col gap-2',
39
+ this.class()
40
+ )
41
+ );
42
+ }
@@ -0,0 +1,58 @@
1
+ import { cn } from '@/lib/utils';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ computed,
6
+ ElementRef,
7
+ inject,
8
+ input,
9
+ viewChild
10
+ } from '@angular/core';
11
+ import { FORM_FIELD_CONTEXT } from './form-context';
12
+
13
+ /**
14
+ * FormLabel component - accessible label for form fields.
15
+ * Uses a native <label> element to ensure clicking focuses the associated input.
16
+ *
17
+ * @example
18
+ * <FormLabel>Email</FormLabel>
19
+ */
20
+ @Component({
21
+ selector: 'FormLabel',
22
+ template: `<label #labelElement [attr.for]="fieldContext?.id()" [class]="computedClass()"><ng-content /></label>`,
23
+ host: {
24
+ '[attr.data-error]': 'hasError() ? "" : null',
25
+ '[attr.data-disabled]': 'isDisabled() ? "" : null',
26
+ 'data-slot': 'form-label',
27
+ 'class': 'contents',
28
+ },
29
+ changeDetection: ChangeDetectionStrategy.OnPush,
30
+ })
31
+ export class FormLabel {
32
+ protected readonly fieldContext = inject(FORM_FIELD_CONTEXT, { optional: true });
33
+
34
+ private readonly labelElement = viewChild<ElementRef<HTMLLabelElement>>('labelElement');
35
+
36
+ /** Additional CSS classes to apply */
37
+ readonly class = input<string>('');
38
+
39
+ /** Check if field has error */
40
+ protected readonly hasError = computed(() => {
41
+ const control = this.fieldContext?.control();
42
+ return control?.invalid && (control?.dirty || control?.touched);
43
+ });
44
+
45
+ /** Check if field is disabled */
46
+ protected readonly isDisabled = computed(() => {
47
+ return this.fieldContext?.control()?.disabled;
48
+ });
49
+
50
+ /** Computed class combining base styles and custom classes */
51
+ protected readonly computedClass = computed(() =>
52
+ cn(
53
+ 'flex items-center gap-2 text-sm font-medium leading-none select-none cursor-pointer group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
54
+ this.hasError() && 'text-destructive',
55
+ this.class()
56
+ )
57
+ );
58
+ }