@joel_jsp/vortex-ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -2
  3. package/ai/README.md +18 -0
  4. package/ai/ai-assistant-dialog.component.d.ts +25 -0
  5. package/ai/ai-prompt-editor.component.d.ts +14 -0
  6. package/ai/ai.types.d.ts +109 -0
  7. package/ai/ai.utils.d.ts +3 -0
  8. package/ai/index.d.ts +8 -0
  9. package/ai/mock-ai-integration.d.ts +8 -0
  10. package/ai/vortex-ui-ai.d.ts +5 -0
  11. package/esm2022/ai/ai-assistant-dialog.component.js +226 -0
  12. package/esm2022/ai/ai-assistant-dialog.component.js.map +1 -0
  13. package/esm2022/ai/ai-prompt-editor.component.js +112 -0
  14. package/esm2022/ai/ai-prompt-editor.component.js.map +1 -0
  15. package/esm2022/ai/ai.types.js +2 -0
  16. package/esm2022/ai/ai.types.js.map +1 -0
  17. package/esm2022/ai/ai.utils.js +24 -0
  18. package/esm2022/ai/ai.utils.js.map +1 -0
  19. package/esm2022/ai/index.js +9 -0
  20. package/esm2022/ai/index.js.map +1 -0
  21. package/esm2022/ai/mock-ai-integration.js +169 -0
  22. package/esm2022/ai/mock-ai-integration.js.map +1 -0
  23. package/esm2022/ai/vortex-ui-ai.js +5 -0
  24. package/esm2022/ai/vortex-ui-ai.js.map +1 -0
  25. package/esm2022/index.js +4 -0
  26. package/esm2022/index.js.map +1 -0
  27. package/esm2022/lib/components/accordion/accordion.component.js +104 -0
  28. package/esm2022/lib/components/accordion/accordion.component.js.map +1 -0
  29. package/esm2022/lib/components/action-sheet/action-sheet.component.js +91 -0
  30. package/esm2022/lib/components/action-sheet/action-sheet.component.js.map +1 -0
  31. package/esm2022/lib/components/autocomplete/autocomplete.component.js +79 -0
  32. package/esm2022/lib/components/autocomplete/autocomplete.component.js.map +1 -0
  33. package/esm2022/lib/components/box/box.component.js +49 -0
  34. package/esm2022/lib/components/box/box.component.js.map +1 -0
  35. package/esm2022/lib/components/bullet/bullet.component.js +74 -0
  36. package/esm2022/lib/components/bullet/bullet.component.js.map +1 -0
  37. package/esm2022/lib/components/button/button.component.js +57 -0
  38. package/esm2022/lib/components/button/button.component.js.map +1 -0
  39. package/esm2022/lib/components/button-group/button-group.component.js +48 -0
  40. package/esm2022/lib/components/button-group/button-group.component.js.map +1 -0
  41. package/esm2022/lib/components/calendar/calendar.component.js +104 -0
  42. package/esm2022/lib/components/calendar/calendar.component.js.map +1 -0
  43. package/esm2022/lib/components/card/card.component.js +52 -0
  44. package/esm2022/lib/components/card/card.component.js.map +1 -0
  45. package/esm2022/lib/components/card-view/card-view.component.js +160 -0
  46. package/esm2022/lib/components/card-view/card-view.component.js.map +1 -0
  47. package/esm2022/lib/components/chart/chart.component.js +471 -0
  48. package/esm2022/lib/components/chart/chart.component.js.map +1 -0
  49. package/esm2022/lib/components/chat/chat.component.js +75 -0
  50. package/esm2022/lib/components/chat/chat.component.js.map +1 -0
  51. package/esm2022/lib/components/checkbox/checkbox.component.js +48 -0
  52. package/esm2022/lib/components/checkbox/checkbox.component.js.map +1 -0
  53. package/esm2022/lib/components/color-box/color-box.component.js +36 -0
  54. package/esm2022/lib/components/color-box/color-box.component.js.map +1 -0
  55. package/esm2022/lib/components/context-menu/context-menu.component.js +76 -0
  56. package/esm2022/lib/components/context-menu/context-menu.component.js.map +1 -0
  57. package/esm2022/lib/components/data-grid/data-grid.component.js +1203 -0
  58. package/esm2022/lib/components/data-grid/data-grid.component.js.map +1 -0
  59. package/esm2022/lib/components/data-grid/data-grid.types.js +2 -0
  60. package/esm2022/lib/components/data-grid/data-grid.types.js.map +1 -0
  61. package/esm2022/lib/components/data-grid/data-source.js +121 -0
  62. package/esm2022/lib/components/data-grid/data-source.js.map +1 -0
  63. package/esm2022/lib/components/data-grid/export-csv.js +28 -0
  64. package/esm2022/lib/components/data-grid/export-csv.js.map +1 -0
  65. package/esm2022/lib/components/date-box/date-box.component.js +67 -0
  66. package/esm2022/lib/components/date-box/date-box.component.js.map +1 -0
  67. package/esm2022/lib/components/date-range-box/date-range-box.component.js +48 -0
  68. package/esm2022/lib/components/date-range-box/date-range-box.component.js.map +1 -0
  69. package/esm2022/lib/components/diagram/diagram.component.js +103 -0
  70. package/esm2022/lib/components/diagram/diagram.component.js.map +1 -0
  71. package/esm2022/lib/components/dialog/dialog.component.js +93 -0
  72. package/esm2022/lib/components/dialog/dialog.component.js.map +1 -0
  73. package/esm2022/lib/components/drawer/drawer.component.js +98 -0
  74. package/esm2022/lib/components/drawer/drawer.component.js.map +1 -0
  75. package/esm2022/lib/components/drop-down-button/drop-down-button.component.js +71 -0
  76. package/esm2022/lib/components/drop-down-button/drop-down-button.component.js.map +1 -0
  77. package/esm2022/lib/components/fab/fab.component.js +46 -0
  78. package/esm2022/lib/components/fab/fab.component.js.map +1 -0
  79. package/esm2022/lib/components/field-set/field-set.component.js +25 -0
  80. package/esm2022/lib/components/field-set/field-set.component.js.map +1 -0
  81. package/esm2022/lib/components/file-manager/file-manager.component.js +862 -0
  82. package/esm2022/lib/components/file-manager/file-manager.component.js.map +1 -0
  83. package/esm2022/lib/components/file-manager/file-manager.types.js +2 -0
  84. package/esm2022/lib/components/file-manager/file-manager.types.js.map +1 -0
  85. package/esm2022/lib/components/file-uploader/file-uploader.component.js +43 -0
  86. package/esm2022/lib/components/file-uploader/file-uploader.component.js.map +1 -0
  87. package/esm2022/lib/components/filter-builder/filter-builder.component.js +261 -0
  88. package/esm2022/lib/components/filter-builder/filter-builder.component.js.map +1 -0
  89. package/esm2022/lib/components/form/form.component.js +54 -0
  90. package/esm2022/lib/components/form/form.component.js.map +1 -0
  91. package/esm2022/lib/components/funnel/funnel.component.js +85 -0
  92. package/esm2022/lib/components/funnel/funnel.component.js.map +1 -0
  93. package/esm2022/lib/components/gallery/gallery.component.js +54 -0
  94. package/esm2022/lib/components/gallery/gallery.component.js.map +1 -0
  95. package/esm2022/lib/components/gantt/gantt.component.js +130 -0
  96. package/esm2022/lib/components/gantt/gantt.component.js.map +1 -0
  97. package/esm2022/lib/components/gauge/bar-gauge.component.js +59 -0
  98. package/esm2022/lib/components/gauge/bar-gauge.component.js.map +1 -0
  99. package/esm2022/lib/components/gauge/circular-gauge.component.js +68 -0
  100. package/esm2022/lib/components/gauge/circular-gauge.component.js.map +1 -0
  101. package/esm2022/lib/components/gauge/linear-gauge.component.js +54 -0
  102. package/esm2022/lib/components/gauge/linear-gauge.component.js.map +1 -0
  103. package/esm2022/lib/components/html-editor/html-editor.component.js +186 -0
  104. package/esm2022/lib/components/html-editor/html-editor.component.js.map +1 -0
  105. package/esm2022/lib/components/index.js +73 -0
  106. package/esm2022/lib/components/index.js.map +1 -0
  107. package/esm2022/lib/components/list/list.component.js +121 -0
  108. package/esm2022/lib/components/list/list.component.js.map +1 -0
  109. package/esm2022/lib/components/load-panel/load-panel.component.js +31 -0
  110. package/esm2022/lib/components/load-panel/load-panel.component.js.map +1 -0
  111. package/esm2022/lib/components/lookup/lookup.component.js +66 -0
  112. package/esm2022/lib/components/lookup/lookup.component.js.map +1 -0
  113. package/esm2022/lib/components/map/map.component.js +73 -0
  114. package/esm2022/lib/components/map/map.component.js.map +1 -0
  115. package/esm2022/lib/components/map/vector-map.component.js +47 -0
  116. package/esm2022/lib/components/map/vector-map.component.js.map +1 -0
  117. package/esm2022/lib/components/menu/menu.component.js +107 -0
  118. package/esm2022/lib/components/menu/menu.component.js.map +1 -0
  119. package/esm2022/lib/components/multi-view/multi-view.component.js +82 -0
  120. package/esm2022/lib/components/multi-view/multi-view.component.js.map +1 -0
  121. package/esm2022/lib/components/number-box/number-box.component.js +57 -0
  122. package/esm2022/lib/components/number-box/number-box.component.js.map +1 -0
  123. package/esm2022/lib/components/pagination/pagination.component.js +62 -0
  124. package/esm2022/lib/components/pagination/pagination.component.js.map +1 -0
  125. package/esm2022/lib/components/pivot-grid/pivot-field-chooser.component.js +60 -0
  126. package/esm2022/lib/components/pivot-grid/pivot-field-chooser.component.js.map +1 -0
  127. package/esm2022/lib/components/pivot-grid/pivot-grid.component.js +102 -0
  128. package/esm2022/lib/components/pivot-grid/pivot-grid.component.js.map +1 -0
  129. package/esm2022/lib/components/popover/popover.component.js +42 -0
  130. package/esm2022/lib/components/popover/popover.component.js.map +1 -0
  131. package/esm2022/lib/components/progress/index.js +3 -0
  132. package/esm2022/lib/components/progress/index.js.map +1 -0
  133. package/esm2022/lib/components/progress/load-indicator.component.js +33 -0
  134. package/esm2022/lib/components/progress/load-indicator.component.js.map +1 -0
  135. package/esm2022/lib/components/progress/progress-bar.component.js +63 -0
  136. package/esm2022/lib/components/progress/progress-bar.component.js.map +1 -0
  137. package/esm2022/lib/components/radio-group/radio-group.component.js +42 -0
  138. package/esm2022/lib/components/radio-group/radio-group.component.js.map +1 -0
  139. package/esm2022/lib/components/range-slider/range-slider.component.js +60 -0
  140. package/esm2022/lib/components/range-slider/range-slider.component.js.map +1 -0
  141. package/esm2022/lib/components/sankey/sankey.component.js +97 -0
  142. package/esm2022/lib/components/sankey/sankey.component.js.map +1 -0
  143. package/esm2022/lib/components/scheduler/scheduler.component.js +377 -0
  144. package/esm2022/lib/components/scheduler/scheduler.component.js.map +1 -0
  145. package/esm2022/lib/components/scroll-view/scroll-view.component.js +25 -0
  146. package/esm2022/lib/components/scroll-view/scroll-view.component.js.map +1 -0
  147. package/esm2022/lib/components/select-box/select-box.component.js +77 -0
  148. package/esm2022/lib/components/select-box/select-box.component.js.map +1 -0
  149. package/esm2022/lib/components/slider/slider.component.js +59 -0
  150. package/esm2022/lib/components/slider/slider.component.js.map +1 -0
  151. package/esm2022/lib/components/sparkline/sparkline.component.js +95 -0
  152. package/esm2022/lib/components/sparkline/sparkline.component.js.map +1 -0
  153. package/esm2022/lib/components/splitter/splitter.component.js +123 -0
  154. package/esm2022/lib/components/splitter/splitter.component.js.map +1 -0
  155. package/esm2022/lib/components/stepper/stepper.component.js +120 -0
  156. package/esm2022/lib/components/stepper/stepper.component.js.map +1 -0
  157. package/esm2022/lib/components/switch/switch.component.js +54 -0
  158. package/esm2022/lib/components/switch/switch.component.js.map +1 -0
  159. package/esm2022/lib/components/tabs/tabs.component.js +118 -0
  160. package/esm2022/lib/components/tabs/tabs.component.js.map +1 -0
  161. package/esm2022/lib/components/tag-box/tag-box.component.js +75 -0
  162. package/esm2022/lib/components/tag-box/tag-box.component.js.map +1 -0
  163. package/esm2022/lib/components/text-area/text-area.component.js +50 -0
  164. package/esm2022/lib/components/text-area/text-area.component.js.map +1 -0
  165. package/esm2022/lib/components/text-box/text-box.component.js +64 -0
  166. package/esm2022/lib/components/text-box/text-box.component.js.map +1 -0
  167. package/esm2022/lib/components/tile-view/tile-view.component.js +34 -0
  168. package/esm2022/lib/components/tile-view/tile-view.component.js.map +1 -0
  169. package/esm2022/lib/components/toast/index.js +3 -0
  170. package/esm2022/lib/components/toast/index.js.map +1 -0
  171. package/esm2022/lib/components/toast/toast-outlet.component.js +35 -0
  172. package/esm2022/lib/components/toast/toast-outlet.component.js.map +1 -0
  173. package/esm2022/lib/components/toast/toast.service.js +42 -0
  174. package/esm2022/lib/components/toast/toast.service.js.map +1 -0
  175. package/esm2022/lib/components/toolbar/toolbar.component.js +37 -0
  176. package/esm2022/lib/components/toolbar/toolbar.component.js.map +1 -0
  177. package/esm2022/lib/components/tooltip/tooltip.component.js +21 -0
  178. package/esm2022/lib/components/tooltip/tooltip.component.js.map +1 -0
  179. package/esm2022/lib/components/tree-list/tree-list.component.js +166 -0
  180. package/esm2022/lib/components/tree-list/tree-list.component.js.map +1 -0
  181. package/esm2022/lib/components/tree-map/tree-map.component.js +94 -0
  182. package/esm2022/lib/components/tree-map/tree-map.component.js.map +1 -0
  183. package/esm2022/lib/components/tree-view/tree-view.component.js +140 -0
  184. package/esm2022/lib/components/tree-view/tree-view.component.js.map +1 -0
  185. package/esm2022/lib/components/validation/validation-summary.component.js +37 -0
  186. package/esm2022/lib/components/validation/validation-summary.component.js.map +1 -0
  187. package/esm2022/lib/components/wrappers/draggable.component.js +64 -0
  188. package/esm2022/lib/components/wrappers/draggable.component.js.map +1 -0
  189. package/esm2022/lib/components/wrappers/index.js +4 -0
  190. package/esm2022/lib/components/wrappers/index.js.map +1 -0
  191. package/esm2022/lib/components/wrappers/resizable.component.js +90 -0
  192. package/esm2022/lib/components/wrappers/resizable.component.js.map +1 -0
  193. package/esm2022/lib/components/wrappers/sortable.component.js +88 -0
  194. package/esm2022/lib/components/wrappers/sortable.component.js.map +1 -0
  195. package/esm2022/lib/core/index.js +3 -0
  196. package/esm2022/lib/core/index.js.map +1 -0
  197. package/esm2022/lib/core/theme/theme.service.js +84 -0
  198. package/esm2022/lib/core/theme/theme.service.js.map +1 -0
  199. package/esm2022/lib/core/validation/validators.js +53 -0
  200. package/esm2022/lib/core/validation/validators.js.map +1 -0
  201. package/esm2022/vortex-ui.js +5 -0
  202. package/esm2022/vortex-ui.js.map +1 -0
  203. package/index.d.ts +2 -0
  204. package/lib/components/accordion/accordion.component.d.ts +19 -0
  205. package/lib/components/action-sheet/action-sheet.component.d.ts +18 -0
  206. package/lib/components/autocomplete/autocomplete.component.d.ts +14 -0
  207. package/lib/components/box/box.component.d.ts +16 -0
  208. package/lib/components/bullet/bullet.component.d.ts +15 -0
  209. package/lib/components/button/button.component.d.ts +13 -0
  210. package/lib/components/button-group/button-group.component.d.ts +10 -0
  211. package/lib/components/calendar/calendar.component.d.ts +19 -0
  212. package/lib/components/card/card.component.d.ts +10 -0
  213. package/lib/components/card-view/card-view.component.d.ts +31 -0
  214. package/lib/components/chart/chart.component.d.ts +85 -0
  215. package/lib/components/chat/chat.component.d.ts +18 -0
  216. package/lib/components/checkbox/checkbox.component.d.ts +9 -0
  217. package/lib/components/color-box/color-box.component.d.ts +9 -0
  218. package/lib/components/context-menu/context-menu.component.d.ts +18 -0
  219. package/lib/components/data-grid/data-grid.component.d.ts +162 -0
  220. package/lib/components/data-grid/data-grid.types.d.ts +51 -0
  221. package/lib/components/data-grid/data-source.d.ts +41 -0
  222. package/lib/components/data-grid/export-csv.d.ts +3 -0
  223. package/lib/components/date-box/date-box.component.d.ts +14 -0
  224. package/lib/components/date-range-box/date-range-box.component.d.ts +16 -0
  225. package/lib/components/diagram/diagram.component.d.ts +30 -0
  226. package/lib/components/dialog/dialog.component.d.ts +19 -0
  227. package/lib/components/drawer/drawer.component.d.ts +16 -0
  228. package/lib/components/drop-down-button/drop-down-button.component.d.ts +11 -0
  229. package/lib/components/fab/fab.component.d.ts +10 -0
  230. package/lib/components/field-set/field-set.component.d.ts +7 -0
  231. package/lib/components/file-manager/file-manager.component.d.ts +86 -0
  232. package/lib/components/file-manager/file-manager.types.d.ts +33 -0
  233. package/lib/components/file-uploader/file-uploader.component.d.ts +12 -0
  234. package/lib/components/filter-builder/filter-builder.component.d.ts +38 -0
  235. package/lib/components/form/form.component.d.ts +9 -0
  236. package/lib/components/funnel/funnel.component.d.ts +21 -0
  237. package/lib/components/gallery/gallery.component.d.ts +15 -0
  238. package/lib/components/gantt/gantt.component.d.ts +29 -0
  239. package/lib/components/gauge/bar-gauge.component.d.ts +19 -0
  240. package/lib/components/gauge/circular-gauge.component.d.ts +12 -0
  241. package/lib/components/gauge/linear-gauge.component.d.ts +10 -0
  242. package/lib/components/html-editor/html-editor.component.d.ts +22 -0
  243. package/lib/components/index.d.ts +72 -0
  244. package/lib/components/list/list.component.d.ts +23 -0
  245. package/lib/components/load-panel/load-panel.component.d.ts +8 -0
  246. package/lib/components/lookup/lookup.component.d.ts +18 -0
  247. package/lib/components/map/map.component.d.ts +19 -0
  248. package/lib/components/map/vector-map.component.d.ts +16 -0
  249. package/lib/components/menu/menu.component.d.ts +17 -0
  250. package/lib/components/multi-view/multi-view.component.d.ts +16 -0
  251. package/lib/components/number-box/number-box.component.d.ts +12 -0
  252. package/lib/components/pagination/pagination.component.d.ts +12 -0
  253. package/lib/components/pivot-grid/pivot-field-chooser.component.d.ts +28 -0
  254. package/lib/components/pivot-grid/pivot-grid.component.d.ts +14 -0
  255. package/lib/components/popover/popover.component.d.ts +8 -0
  256. package/lib/components/progress/index.d.ts +2 -0
  257. package/lib/components/progress/load-indicator.component.d.ts +8 -0
  258. package/lib/components/progress/progress-bar.component.d.ts +10 -0
  259. package/lib/components/radio-group/radio-group.component.d.ts +11 -0
  260. package/lib/components/range-slider/range-slider.component.d.ts +18 -0
  261. package/lib/components/sankey/sankey.component.d.ts +34 -0
  262. package/lib/components/scheduler/scheduler.component.d.ts +55 -0
  263. package/lib/components/scroll-view/scroll-view.component.d.ts +8 -0
  264. package/lib/components/select-box/select-box.component.d.ts +20 -0
  265. package/lib/components/slider/slider.component.d.ts +14 -0
  266. package/lib/components/sparkline/sparkline.component.d.ts +13 -0
  267. package/lib/components/splitter/splitter.component.d.ts +13 -0
  268. package/lib/components/stepper/stepper.component.d.ts +18 -0
  269. package/lib/components/switch/switch.component.d.ts +9 -0
  270. package/lib/components/tabs/tabs.component.d.ts +28 -0
  271. package/lib/components/tag-box/tag-box.component.d.ts +13 -0
  272. package/lib/components/text-area/text-area.component.d.ts +11 -0
  273. package/lib/components/text-box/text-box.component.d.ts +13 -0
  274. package/lib/components/tile-view/tile-view.component.d.ts +13 -0
  275. package/lib/components/toast/index.d.ts +2 -0
  276. package/lib/components/toast/toast-outlet.component.d.ts +7 -0
  277. package/lib/components/toast/toast.service.d.ts +22 -0
  278. package/lib/components/toolbar/toolbar.component.d.ts +6 -0
  279. package/lib/components/tooltip/tooltip.component.d.ts +6 -0
  280. package/lib/components/tree-list/tree-list.component.d.ts +35 -0
  281. package/lib/components/tree-map/tree-map.component.d.ts +24 -0
  282. package/lib/components/tree-view/tree-view.component.d.ts +30 -0
  283. package/lib/components/validation/validation-summary.component.d.ts +7 -0
  284. package/lib/components/wrappers/draggable.component.d.ts +15 -0
  285. package/lib/components/wrappers/index.d.ts +3 -0
  286. package/lib/components/wrappers/resizable.component.d.ts +16 -0
  287. package/lib/components/wrappers/sortable.component.d.ts +18 -0
  288. package/lib/core/index.d.ts +2 -0
  289. package/lib/core/theme/theme.service.d.ts +33 -0
  290. package/lib/core/validation/validators.d.ts +12 -0
  291. package/package.json +58 -4
  292. package/src/lib/core/tokens/design-tokens.css +71 -0
  293. package/src/lib/styles/themes/dark.css +50 -0
  294. package/src/lib/styles/themes/fluent-blue-dark.css +77 -0
  295. package/src/lib/styles/themes/fluent-blue-light.css +79 -0
  296. package/src/lib/styles/themes/fluent-saas-dark.css +77 -0
  297. package/src/lib/styles/themes/fluent-saas-light.css +77 -0
  298. package/src/lib/styles/themes/fluent.css +5 -0
  299. package/src/lib/styles/themes/lds.css +78 -0
  300. package/src/lib/styles/themes/light.css +60 -0
  301. package/src/lib/styles/themes/material.css +55 -0
  302. package/src/lib/styles/vortex-ui.css +20 -0
  303. package/vortex-ui.d.ts +5 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joel Schecheleski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the Software), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,49 @@
1
- # Temporary Holding Version
1
+ # @joel_jsp/vortex-ui
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **VortexUI** — suite de componentes Angular 22+ (Standalone, Signals, zoneless-ready), com DataGrid de alta performance, AI opt-in e temas Fluent / LDS.
4
+
5
+ Repositório: [JoelSchecheleski/vortex-ui](https://github.com/JoelSchecheleski/vortex-ui)
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @joel_jsp/vortex-ui
11
+ ```
12
+
13
+ ## Uso
14
+
15
+ ```ts
16
+ import { VxButtonComponent, VxDataGridComponent, VortexThemeService } from '@joel_jsp/vortex-ui';
17
+ import { VortexMockAIIntegration, VortexAIConfig } from '@joel_jsp/vortex-ui/ai';
18
+ ```
19
+
20
+ ```css
21
+ @import '@joel_jsp/vortex-ui/styles/vortex-ui.css';
22
+ ```
23
+
24
+ ```ts
25
+ inject(VortexThemeService).setTheme('fluent-blue-light');
26
+ // fluent-blue-dark | fluent-saas-light | fluent-saas-dark | lds
27
+ ```
28
+
29
+ ## Temas
30
+
31
+ | ID | Descrição |
32
+ |----|-----------|
33
+ | `fluent-blue-light` | Default (alias `fluent`) |
34
+ | `fluent-blue-dark` | Fluent Blue Dark |
35
+ | `fluent-saas-light` | Fluent SaaS Light |
36
+ | `fluent-saas-dark` | Fluent SaaS Dark |
37
+ | `lds` | LDS (Poppins) |
38
+
39
+ ## Dev (monorepo)
40
+
41
+ ```bash
42
+ npm start # Widgets Gallery :4200
43
+ npm run build # build da lib
44
+ npm run storybook # Storybook
45
+ ```
46
+
47
+ ## License
48
+
49
+ MIT
package/ai/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # vortex-ui/ai
2
+
3
+ Secondary entry point for VortexUI AI Foundation.
4
+
5
+ ## Usage
6
+
7
+ ```ts
8
+ import {
9
+ VortexAIIntegration,
10
+ VortexMockAIIntegration,
11
+ VxAiAssistantDialogComponent,
12
+ VxAiPromptEditorComponent,
13
+ } from 'vortex-ui/ai';
14
+ // monorepo alias:
15
+ // import { ... } from '@vortex-ui/ai';
16
+ ```
17
+
18
+ Keep this entry opt-in: apps that never enable AI should import only from `vortex-ui`.
@@ -0,0 +1,25 @@
1
+ import { VortexAIMessage, VortexAISuggestion } from './ai.types';
2
+ import * as i0 from "@angular/core";
3
+ export interface VxAIChatMessage extends VortexAIMessage {
4
+ title?: string;
5
+ }
6
+ export declare class VxAIAssistantDialogComponent {
7
+ readonly open: import("@angular/core").ModelSignal<boolean>;
8
+ readonly title: import("@angular/core").InputSignal<string>;
9
+ readonly placeholder: import("@angular/core").InputSignal<string>;
10
+ readonly messages: import("@angular/core").InputSignal<VxAIChatMessage[]>;
11
+ readonly suggestions: import("@angular/core").InputSignal<VortexAISuggestion[]>;
12
+ readonly busy: import("@angular/core").InputSignal<boolean>;
13
+ readonly sendMessage: import("@angular/core").OutputEmitterRef<string>;
14
+ readonly suggestionSelect: import("@angular/core").OutputEmitterRef<VortexAISuggestion>;
15
+ readonly clear: import("@angular/core").OutputEmitterRef<void>;
16
+ readonly closed: import("@angular/core").OutputEmitterRef<void>;
17
+ draft: string;
18
+ close(): void;
19
+ onOverlayClick(_: MouseEvent): void;
20
+ onEnter(event: Event): void;
21
+ send(): void;
22
+ onSuggestion(s: VortexAISuggestion): void;
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<VxAIAssistantDialogComponent, never>;
24
+ static ɵcmp: i0.ɵɵComponentDeclaration<VxAIAssistantDialogComponent, "vx-ai-assistant-dialog", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "messages": { "alias": "messages"; "required": false; "isSignal": true; }; "suggestions": { "alias": "suggestions"; "required": false; "isSignal": true; }; "busy": { "alias": "busy"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "sendMessage": "sendMessage"; "suggestionSelect": "suggestionSelect"; "clear": "clear"; "closed": "closed"; }, never, never, true, never>;
25
+ }
@@ -0,0 +1,14 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class VxAIPromptEditorComponent {
3
+ readonly open: import("@angular/core").ModelSignal<boolean>;
4
+ readonly title: import("@angular/core").InputSignal<string>;
5
+ readonly placeholder: import("@angular/core").InputSignal<string>;
6
+ readonly prompt: import("@angular/core").ModelSignal<string>;
7
+ readonly canApply: import("@angular/core").InputSignal<boolean>;
8
+ readonly regenerate: import("@angular/core").OutputEmitterRef<string>;
9
+ readonly apply: import("@angular/core").OutputEmitterRef<string>;
10
+ readonly closed: import("@angular/core").OutputEmitterRef<void>;
11
+ close(): void;
12
+ static ɵfac: i0.ɵɵFactoryDeclaration<VxAIPromptEditorComponent, never>;
13
+ static ɵcmp: i0.ɵɵComponentDeclaration<VxAIPromptEditorComponent, "vx-ai-prompt-editor", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "prompt": { "alias": "prompt"; "required": false; "isSignal": true; }; "canApply": { "alias": "canApply"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "prompt": "promptChange"; "regenerate": "regenerate"; "apply": "apply"; "closed": "closed"; }, never, never, true, never>;
14
+ }
@@ -0,0 +1,109 @@
1
+ /** Config opt-in por componente (deny by default). */
2
+ export interface VortexAIConfig {
3
+ enabled?: boolean;
4
+ assistant?: {
5
+ enabled?: boolean;
6
+ title?: string;
7
+ };
8
+ /** Campos permitidos no contexto enviado ao modelo (R2). */
9
+ contextFields?: string[];
10
+ /** Cap de linhas no contexto (R3). Default: 100. */
11
+ maxRowsInContext?: number;
12
+ }
13
+ export interface VortexAIMessage {
14
+ role: 'user' | 'assistant' | 'system';
15
+ content: string;
16
+ }
17
+ export interface VortexAIContext {
18
+ schemaVersion: 1;
19
+ componentType: string;
20
+ columns?: Array<{
21
+ field: string;
22
+ header: string;
23
+ }>;
24
+ sort?: {
25
+ field: string;
26
+ direction: 'asc' | 'desc';
27
+ } | null;
28
+ filter?: VortexAIFilterState | null;
29
+ /** Linhas já projetadas (só campos allowlist). */
30
+ rows?: Record<string, unknown>[];
31
+ totalRows?: number;
32
+ meta?: Record<string, unknown>;
33
+ }
34
+ export interface VortexAIFilterState {
35
+ field: string;
36
+ value: string;
37
+ operator?: 'contains' | 'equals';
38
+ }
39
+ export interface VortexAIToolDefinition {
40
+ name: string;
41
+ description: string;
42
+ parameters?: Record<string, unknown>;
43
+ }
44
+ export interface VortexAIRequest {
45
+ feature: 'assistant' | 'ai-column' | 'smart-paste' | 'semantic-search' | 'editor' | string;
46
+ componentType: string;
47
+ componentId?: string;
48
+ messages?: VortexAIMessage[];
49
+ prompt?: string;
50
+ context: VortexAIContext;
51
+ tools?: VortexAIToolDefinition[];
52
+ signal?: AbortSignal;
53
+ }
54
+ export interface VortexAICommand {
55
+ type: string;
56
+ payload?: Record<string, unknown>;
57
+ }
58
+ export interface VortexAIResponse {
59
+ title?: string;
60
+ text: string;
61
+ commands?: VortexAICommand[];
62
+ /** Resultados estruturados (ex.: AI Column cells). */
63
+ data?: {
64
+ cells?: Array<{
65
+ rowKey: string;
66
+ value: string;
67
+ }>;
68
+ };
69
+ }
70
+ export type VortexAIStreamEvent = {
71
+ type: 'token';
72
+ text: string;
73
+ } | {
74
+ type: 'command';
75
+ command: VortexAICommand;
76
+ } | {
77
+ type: 'done';
78
+ response: VortexAIResponse;
79
+ };
80
+ export interface VortexAISuggestion {
81
+ id: string;
82
+ label: string;
83
+ /** Prompt enviado ao adapter se não houver command direto. */
84
+ prompt?: string;
85
+ command?: VortexAICommand;
86
+ }
87
+ export interface VortexAIRequestCreatingEvent {
88
+ request: VortexAIRequest;
89
+ cancel: boolean;
90
+ }
91
+ export interface VortexAIPrivacyPolicy {
92
+ contextFields?: string[];
93
+ maxRowsInContext?: number;
94
+ }
95
+ export interface VortexAICommandSpec {
96
+ type: string;
97
+ description: string;
98
+ }
99
+ export interface VortexAICapability {
100
+ componentType: string;
101
+ commands: VortexAICommandSpec[];
102
+ projectContext(state: unknown, policy: VortexAIPrivacyPolicy): VortexAIContext;
103
+ execute(command: VortexAICommand): void | Promise<void>;
104
+ suggest?(state: unknown): VortexAISuggestion[];
105
+ }
106
+ export interface VortexAIIntegration {
107
+ sendRequest(req: VortexAIRequest): Promise<VortexAIResponse>;
108
+ stream?(req: VortexAIRequest): AsyncIterable<VortexAIStreamEvent>;
109
+ }
@@ -0,0 +1,3 @@
1
+ import { VortexAIContext, VortexAIPrivacyPolicy } from './ai.types';
2
+ export declare function projectRowsForAI(rows: Record<string, unknown>[], policy: VortexAIPrivacyPolicy): Record<string, unknown>[];
3
+ export declare function emptyAIContext(componentType: string): VortexAIContext;
package/ai/index.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Secondary entry: `vortex-ui/ai` (alias monorepo `@vortex-ui/ai`).
3
+ */
4
+ export * from './ai.types';
5
+ export * from './ai.utils';
6
+ export * from './mock-ai-integration';
7
+ export * from './ai-assistant-dialog.component';
8
+ export * from './ai-prompt-editor.component';
@@ -0,0 +1,8 @@
1
+ import { VortexAIIntegration, VortexAIRequest, VortexAIResponse } from './ai.types';
2
+ /**
3
+ * Adapter local sem LLM — interpreta intents simples (PT/EN)
4
+ * e devolve commands tipados da allowlist do DataGrid.
5
+ */
6
+ export declare class VortexMockAIIntegration implements VortexAIIntegration {
7
+ sendRequest(req: VortexAIRequest): Promise<VortexAIResponse>;
8
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="vortex-ui/ai" />
5
+ export * from './index';
@@ -0,0 +1,226 @@
1
+ import { Component, ChangeDetectionStrategy, input, model, output, } from '@angular/core';
2
+ import { FormsModule } from '@angular/forms';
3
+ import * as i0 from "@angular/core";
4
+ import * as i1 from "@angular/forms";
5
+ export class VxAIAssistantDialogComponent {
6
+ open = model(false, /* @ts-ignore */
7
+ ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
8
+ title = input('AI Assistant', /* @ts-ignore */
9
+ ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
10
+ placeholder = input('Digite uma mensagem', /* @ts-ignore */
11
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
12
+ messages = input([], /* @ts-ignore */
13
+ ...(ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []));
14
+ suggestions = input([], /* @ts-ignore */
15
+ ...(ngDevMode ? [{ debugName: "suggestions" }] : /* istanbul ignore next */ []));
16
+ busy = input(false, /* @ts-ignore */
17
+ ...(ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []));
18
+ sendMessage = output();
19
+ suggestionSelect = output();
20
+ clear = output();
21
+ closed = output();
22
+ draft = '';
23
+ close() {
24
+ this.open.set(false);
25
+ this.closed.emit();
26
+ }
27
+ onOverlayClick(_) {
28
+ this.close();
29
+ }
30
+ onEnter(event) {
31
+ const ke = event;
32
+ if (ke.shiftKey)
33
+ return;
34
+ ke.preventDefault();
35
+ this.send();
36
+ }
37
+ send() {
38
+ const text = this.draft.trim();
39
+ if (!text || this.busy())
40
+ return;
41
+ this.sendMessage.emit(text);
42
+ this.draft = '';
43
+ }
44
+ onSuggestion(s) {
45
+ this.suggestionSelect.emit(s);
46
+ }
47
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.6", ngImport: i0, type: VxAIAssistantDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
48
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.6", type: VxAIAssistantDialogComponent, isStandalone: true, selector: "vx-ai-assistant-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", sendMessage: "sendMessage", suggestionSelect: "suggestionSelect", clear: "clear", closed: "closed" }, ngImport: i0, template: `
49
+ @if (open()) {
50
+ <div class="vx-ai-overlay" (click)="onOverlayClick($event)" role="presentation">
51
+ <div
52
+ class="vx-ai-dialog"
53
+ role="dialog"
54
+ aria-modal="true"
55
+ [attr.aria-label]="title()"
56
+ (click)="$event.stopPropagation()"
57
+ >
58
+ <header class="vx-ai-dialog__header">
59
+ <h2 class="vx-ai-dialog__title">{{ title() }}</h2>
60
+ <div class="vx-ai-dialog__actions">
61
+ <button
62
+ type="button"
63
+ class="vx-ai-icon-btn"
64
+ aria-label="Limpar conversa"
65
+ title="Limpar conversa"
66
+ (click)="clear.emit()"
67
+ >
68
+ ⌫
69
+ </button>
70
+ <button
71
+ type="button"
72
+ class="vx-ai-icon-btn"
73
+ aria-label="Fechar"
74
+ (click)="close()"
75
+ >
76
+ ✕
77
+ </button>
78
+ </div>
79
+ </header>
80
+
81
+ <div class="vx-ai-dialog__body">
82
+ @if (messages().length === 0) {
83
+ <div class="vx-ai-empty">
84
+ <div class="vx-ai-empty__icon" aria-hidden="true">✦</div>
85
+ <p class="vx-ai-empty__text">
86
+ Chat vazio. O assistente está pronto para responder.
87
+ </p>
88
+ @if (suggestions().length) {
89
+ <div class="vx-ai-chips">
90
+ @for (s of suggestions(); track s.id) {
91
+ <button type="button" class="vx-ai-chip" (click)="onSuggestion(s)">
92
+ {{ s.label }}
93
+ </button>
94
+ }
95
+ </div>
96
+ }
97
+ </div>
98
+ } @else {
99
+ <div class="vx-ai-messages">
100
+ @for (m of messages(); track $index) {
101
+ <div class="vx-ai-msg" [class.vx-ai-msg--user]="m.role === 'user'">
102
+ @if (m.title) {
103
+ <div class="vx-ai-msg__title">{{ m.title }}</div>
104
+ }
105
+ <div class="vx-ai-msg__text">{{ m.content }}</div>
106
+ </div>
107
+ }
108
+ </div>
109
+ }
110
+ </div>
111
+
112
+ <footer class="vx-ai-dialog__footer">
113
+ <textarea
114
+ class="vx-ai-input"
115
+ rows="2"
116
+ [placeholder]="placeholder()"
117
+ [(ngModel)]="draft"
118
+ (keydown.enter)="onEnter($event)"
119
+ [disabled]="busy()"
120
+ ></textarea>
121
+ <button
122
+ type="button"
123
+ class="vx-ai-send"
124
+ [disabled]="busy() || !draft.trim()"
125
+ aria-label="Enviar"
126
+ (click)="send()"
127
+ >
128
+ ➤
129
+ </button>
130
+ </footer>
131
+ </div>
132
+ </div>
133
+ }
134
+ `, isInline: true, styles: [".vx-ai-overlay{position:fixed;inset:0;z-index:var(--vx-z-modal);display:flex;justify-content:flex-end;align-items:stretch;padding:var(--vx-space-4);background:#00000040}.vx-ai-dialog{width:min(380px,100%);max-height:calc(100vh - 2rem);display:flex;flex-direction:column;background:var(--vx-color-surface);color:var(--vx-color-text);border:1px solid var(--vx-color-border);border-radius:var(--vx-radius-lg);box-shadow:var(--vx-shadow-xl);font-family:var(--vx-font-sans);overflow:hidden}.vx-ai-dialog__header{display:flex;align-items:center;justify-content:space-between;gap:var(--vx-space-2);padding:var(--vx-space-3) var(--vx-space-4);border-bottom:1px solid var(--vx-color-border);flex-shrink:0}.vx-ai-dialog__title{margin:0;font-size:var(--vx-font-size-md);font-weight:var(--vx-font-weight-semibold)}.vx-ai-dialog__actions{display:flex;gap:var(--vx-space-1)}.vx-ai-icon-btn{border:none;background:transparent;color:var(--vx-color-text-secondary);width:2rem;height:2rem;border-radius:var(--vx-radius-md);cursor:pointer;font-size:1rem}.vx-ai-icon-btn:hover{background:var(--vx-color-bg-hover);color:var(--vx-color-text)}.vx-ai-dialog__body{flex:1;overflow:auto;padding:var(--vx-space-4);min-height:220px}.vx-ai-empty{display:flex;flex-direction:column;align-items:center;text-align:center;gap:var(--vx-space-3);padding:var(--vx-space-6) var(--vx-space-2)}.vx-ai-empty__icon{width:3rem;height:3rem;border-radius:999px;display:grid;place-items:center;background:var(--vx-color-primary-subtle);color:var(--vx-color-primary);font-size:1.25rem}.vx-ai-empty__text{margin:0;color:var(--vx-color-text-secondary);font-size:var(--vx-font-size-sm);max-width:16rem}.vx-ai-chips{display:flex;flex-wrap:wrap;gap:var(--vx-space-2);justify-content:center}.vx-ai-chip{border:1px solid var(--vx-color-border);background:var(--vx-color-bg-elevated);color:var(--vx-color-text);border-radius:var(--vx-radius-md);padding:.4rem .75rem;font-size:var(--vx-font-size-xs);font-family:inherit;cursor:pointer}.vx-ai-chip:hover{border-color:var(--vx-color-primary);color:var(--vx-color-primary-ink, var(--vx-color-primary))}.vx-ai-messages{display:flex;flex-direction:column;gap:var(--vx-space-3)}.vx-ai-msg{align-self:flex-start;max-width:95%;padding:var(--vx-space-3);border-radius:var(--vx-radius-md);background:var(--vx-color-bg-muted);font-size:var(--vx-font-size-sm)}.vx-ai-msg--user{align-self:flex-end;background:var(--vx-color-primary-subtle);color:var(--vx-color-primary-ink, var(--vx-color-text))}.vx-ai-msg__title{font-weight:var(--vx-font-weight-semibold);margin-bottom:var(--vx-space-1)}.vx-ai-dialog__footer{display:flex;gap:var(--vx-space-2);padding:var(--vx-space-3);border-top:1px solid var(--vx-color-border);flex-shrink:0}.vx-ai-input{flex:1;resize:none;border:1px solid var(--vx-color-border-strong);border-radius:var(--vx-radius-md);padding:var(--vx-space-2) var(--vx-space-3);font-family:inherit;font-size:var(--vx-font-size-sm);background:var(--vx-color-bg-elevated);color:var(--vx-color-text)}.vx-ai-input:focus{outline:none;box-shadow:var(--vx-focus-ring);border-color:var(--vx-color-border-focus)}.vx-ai-send{width:2.5rem;border:none;border-radius:var(--vx-radius-md);background:var(--vx-color-primary);color:var(--vx-color-primary-text);cursor:pointer;font-size:1rem}.vx-ai-send:disabled{opacity:.45;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
135
+ }
136
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.6", ngImport: i0, type: VxAIAssistantDialogComponent, decorators: [{
137
+ type: Component,
138
+ args: [{ selector: 'vx-ai-assistant-dialog', standalone: true, imports: [FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
139
+ @if (open()) {
140
+ <div class="vx-ai-overlay" (click)="onOverlayClick($event)" role="presentation">
141
+ <div
142
+ class="vx-ai-dialog"
143
+ role="dialog"
144
+ aria-modal="true"
145
+ [attr.aria-label]="title()"
146
+ (click)="$event.stopPropagation()"
147
+ >
148
+ <header class="vx-ai-dialog__header">
149
+ <h2 class="vx-ai-dialog__title">{{ title() }}</h2>
150
+ <div class="vx-ai-dialog__actions">
151
+ <button
152
+ type="button"
153
+ class="vx-ai-icon-btn"
154
+ aria-label="Limpar conversa"
155
+ title="Limpar conversa"
156
+ (click)="clear.emit()"
157
+ >
158
+ ⌫
159
+ </button>
160
+ <button
161
+ type="button"
162
+ class="vx-ai-icon-btn"
163
+ aria-label="Fechar"
164
+ (click)="close()"
165
+ >
166
+ ✕
167
+ </button>
168
+ </div>
169
+ </header>
170
+
171
+ <div class="vx-ai-dialog__body">
172
+ @if (messages().length === 0) {
173
+ <div class="vx-ai-empty">
174
+ <div class="vx-ai-empty__icon" aria-hidden="true">✦</div>
175
+ <p class="vx-ai-empty__text">
176
+ Chat vazio. O assistente está pronto para responder.
177
+ </p>
178
+ @if (suggestions().length) {
179
+ <div class="vx-ai-chips">
180
+ @for (s of suggestions(); track s.id) {
181
+ <button type="button" class="vx-ai-chip" (click)="onSuggestion(s)">
182
+ {{ s.label }}
183
+ </button>
184
+ }
185
+ </div>
186
+ }
187
+ </div>
188
+ } @else {
189
+ <div class="vx-ai-messages">
190
+ @for (m of messages(); track $index) {
191
+ <div class="vx-ai-msg" [class.vx-ai-msg--user]="m.role === 'user'">
192
+ @if (m.title) {
193
+ <div class="vx-ai-msg__title">{{ m.title }}</div>
194
+ }
195
+ <div class="vx-ai-msg__text">{{ m.content }}</div>
196
+ </div>
197
+ }
198
+ </div>
199
+ }
200
+ </div>
201
+
202
+ <footer class="vx-ai-dialog__footer">
203
+ <textarea
204
+ class="vx-ai-input"
205
+ rows="2"
206
+ [placeholder]="placeholder()"
207
+ [(ngModel)]="draft"
208
+ (keydown.enter)="onEnter($event)"
209
+ [disabled]="busy()"
210
+ ></textarea>
211
+ <button
212
+ type="button"
213
+ class="vx-ai-send"
214
+ [disabled]="busy() || !draft.trim()"
215
+ aria-label="Enviar"
216
+ (click)="send()"
217
+ >
218
+ ➤
219
+ </button>
220
+ </footer>
221
+ </div>
222
+ </div>
223
+ }
224
+ `, styles: [".vx-ai-overlay{position:fixed;inset:0;z-index:var(--vx-z-modal);display:flex;justify-content:flex-end;align-items:stretch;padding:var(--vx-space-4);background:#00000040}.vx-ai-dialog{width:min(380px,100%);max-height:calc(100vh - 2rem);display:flex;flex-direction:column;background:var(--vx-color-surface);color:var(--vx-color-text);border:1px solid var(--vx-color-border);border-radius:var(--vx-radius-lg);box-shadow:var(--vx-shadow-xl);font-family:var(--vx-font-sans);overflow:hidden}.vx-ai-dialog__header{display:flex;align-items:center;justify-content:space-between;gap:var(--vx-space-2);padding:var(--vx-space-3) var(--vx-space-4);border-bottom:1px solid var(--vx-color-border);flex-shrink:0}.vx-ai-dialog__title{margin:0;font-size:var(--vx-font-size-md);font-weight:var(--vx-font-weight-semibold)}.vx-ai-dialog__actions{display:flex;gap:var(--vx-space-1)}.vx-ai-icon-btn{border:none;background:transparent;color:var(--vx-color-text-secondary);width:2rem;height:2rem;border-radius:var(--vx-radius-md);cursor:pointer;font-size:1rem}.vx-ai-icon-btn:hover{background:var(--vx-color-bg-hover);color:var(--vx-color-text)}.vx-ai-dialog__body{flex:1;overflow:auto;padding:var(--vx-space-4);min-height:220px}.vx-ai-empty{display:flex;flex-direction:column;align-items:center;text-align:center;gap:var(--vx-space-3);padding:var(--vx-space-6) var(--vx-space-2)}.vx-ai-empty__icon{width:3rem;height:3rem;border-radius:999px;display:grid;place-items:center;background:var(--vx-color-primary-subtle);color:var(--vx-color-primary);font-size:1.25rem}.vx-ai-empty__text{margin:0;color:var(--vx-color-text-secondary);font-size:var(--vx-font-size-sm);max-width:16rem}.vx-ai-chips{display:flex;flex-wrap:wrap;gap:var(--vx-space-2);justify-content:center}.vx-ai-chip{border:1px solid var(--vx-color-border);background:var(--vx-color-bg-elevated);color:var(--vx-color-text);border-radius:var(--vx-radius-md);padding:.4rem .75rem;font-size:var(--vx-font-size-xs);font-family:inherit;cursor:pointer}.vx-ai-chip:hover{border-color:var(--vx-color-primary);color:var(--vx-color-primary-ink, var(--vx-color-primary))}.vx-ai-messages{display:flex;flex-direction:column;gap:var(--vx-space-3)}.vx-ai-msg{align-self:flex-start;max-width:95%;padding:var(--vx-space-3);border-radius:var(--vx-radius-md);background:var(--vx-color-bg-muted);font-size:var(--vx-font-size-sm)}.vx-ai-msg--user{align-self:flex-end;background:var(--vx-color-primary-subtle);color:var(--vx-color-primary-ink, var(--vx-color-text))}.vx-ai-msg__title{font-weight:var(--vx-font-weight-semibold);margin-bottom:var(--vx-space-1)}.vx-ai-dialog__footer{display:flex;gap:var(--vx-space-2);padding:var(--vx-space-3);border-top:1px solid var(--vx-color-border);flex-shrink:0}.vx-ai-input{flex:1;resize:none;border:1px solid var(--vx-color-border-strong);border-radius:var(--vx-radius-md);padding:var(--vx-space-2) var(--vx-space-3);font-family:inherit;font-size:var(--vx-font-size-sm);background:var(--vx-color-bg-elevated);color:var(--vx-color-text)}.vx-ai-input:focus{outline:none;box-shadow:var(--vx-focus-ring);border-color:var(--vx-color-border-focus)}.vx-ai-send{width:2.5rem;border:none;border-radius:var(--vx-radius-md);background:var(--vx-color-primary);color:var(--vx-color-primary-text);cursor:pointer;font-size:1rem}.vx-ai-send:disabled{opacity:.45;cursor:not-allowed}\n"] }]
225
+ }], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], busy: [{ type: i0.Input, args: [{ isSignal: true, alias: "busy", required: false }] }], sendMessage: [{ type: i0.Output, args: ["sendMessage"] }], suggestionSelect: [{ type: i0.Output, args: ["suggestionSelect"] }], clear: [{ type: i0.Output, args: ["clear"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
226
+ //# sourceMappingURL=ai-assistant-dialog.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-assistant-dialog.component.js","sourceRoot":"","sources":["../../../../../libs/vortex-ui/ai/src/ai-assistant-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,uBAAuB,EACvB,KAAK,EACL,KAAK,EACL,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;;;AA+R7C,MAAM,OAAO,4BAA4B;IAC9B,IAAI,GAAG,KAAK,CAAC,KAAK;6EAAC,CAAC;IACpB,KAAK,GAAG,KAAK,CAAC,cAAc;8EAAC,CAAC;IAC9B,WAAW,GAAG,KAAK,CAAC,qBAAqB;oFAAC,CAAC;IAC3C,QAAQ,GAAG,KAAK,CAAoB,EAAE;iFAAC,CAAC;IACxC,WAAW,GAAG,KAAK,CAAuB,EAAE;oFAAC,CAAC;IAC9C,IAAI,GAAG,KAAK,CAAC,KAAK;6EAAC,CAAC;IAEpB,WAAW,GAAG,MAAM,EAAU,CAAC;IAC/B,gBAAgB,GAAG,MAAM,EAAsB,CAAC;IAChD,KAAK,GAAG,MAAM,EAAQ,CAAC;IACvB,MAAM,GAAG,MAAM,EAAQ,CAAC;IAEjC,KAAK,GAAG,EAAE,CAAC;IAEX,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;IAED,cAAc,CAAC,CAAa;QAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,OAAO,CAAC,KAAY;QAClB,MAAM,EAAE,GAAG,KAAsB,CAAC;QAClC,IAAI,EAAE,CAAC,QAAQ;YAAE,OAAO;QACxB,EAAE,CAAC,cAAc,EAAE,CAAC;QACpB,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,IAAI;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;QACjC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;IAClB,CAAC;IAED,YAAY,CAAC,CAAqB;QAChC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;uGAxCU,4BAA4B;2FAA5B,4BAA4B,09BAnR7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFT,g0GAxFS,WAAW;;2FAqRV,4BAA4B;kBAxRxC,SAAS;+BACE,wBAAwB,cACtB,IAAI,WACP,CAAC,WAAW,CAAC,mBACL,uBAAuB,CAAC,MAAM,YACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFT","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n model,\n output,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { VortexAIMessage, VortexAISuggestion } from './ai.types';\n\nexport interface VxAIChatMessage extends VortexAIMessage {\n title?: string;\n}\n\n@Component({\n selector: 'vx-ai-assistant-dialog',\n standalone: true,\n imports: [FormsModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (open()) {\n <div class=\"vx-ai-overlay\" (click)=\"onOverlayClick($event)\" role=\"presentation\">\n <div\n class=\"vx-ai-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"title()\"\n (click)=\"$event.stopPropagation()\"\n >\n <header class=\"vx-ai-dialog__header\">\n <h2 class=\"vx-ai-dialog__title\">{{ title() }}</h2>\n <div class=\"vx-ai-dialog__actions\">\n <button\n type=\"button\"\n class=\"vx-ai-icon-btn\"\n aria-label=\"Limpar conversa\"\n title=\"Limpar conversa\"\n (click)=\"clear.emit()\"\n >\n ⌫\n </button>\n <button\n type=\"button\"\n class=\"vx-ai-icon-btn\"\n aria-label=\"Fechar\"\n (click)=\"close()\"\n >\n ✕\n </button>\n </div>\n </header>\n\n <div class=\"vx-ai-dialog__body\">\n @if (messages().length === 0) {\n <div class=\"vx-ai-empty\">\n <div class=\"vx-ai-empty__icon\" aria-hidden=\"true\">✦</div>\n <p class=\"vx-ai-empty__text\">\n Chat vazio. O assistente está pronto para responder.\n </p>\n @if (suggestions().length) {\n <div class=\"vx-ai-chips\">\n @for (s of suggestions(); track s.id) {\n <button type=\"button\" class=\"vx-ai-chip\" (click)=\"onSuggestion(s)\">\n {{ s.label }}\n </button>\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"vx-ai-messages\">\n @for (m of messages(); track $index) {\n <div class=\"vx-ai-msg\" [class.vx-ai-msg--user]=\"m.role === 'user'\">\n @if (m.title) {\n <div class=\"vx-ai-msg__title\">{{ m.title }}</div>\n }\n <div class=\"vx-ai-msg__text\">{{ m.content }}</div>\n </div>\n }\n </div>\n }\n </div>\n\n <footer class=\"vx-ai-dialog__footer\">\n <textarea\n class=\"vx-ai-input\"\n rows=\"2\"\n [placeholder]=\"placeholder()\"\n [(ngModel)]=\"draft\"\n (keydown.enter)=\"onEnter($event)\"\n [disabled]=\"busy()\"\n ></textarea>\n <button\n type=\"button\"\n class=\"vx-ai-send\"\n [disabled]=\"busy() || !draft.trim()\"\n aria-label=\"Enviar\"\n (click)=\"send()\"\n >\n ➤\n </button>\n </footer>\n </div>\n </div>\n }\n `,\n styles: `\n .vx-ai-overlay {\n position: fixed;\n inset: 0;\n z-index: var(--vx-z-modal);\n display: flex;\n justify-content: flex-end;\n align-items: stretch;\n padding: var(--vx-space-4);\n background: rgb(0 0 0 / 0.25);\n }\n\n .vx-ai-dialog {\n width: min(380px, 100%);\n max-height: calc(100vh - 2rem);\n display: flex;\n flex-direction: column;\n background: var(--vx-color-surface);\n color: var(--vx-color-text);\n border: 1px solid var(--vx-color-border);\n border-radius: var(--vx-radius-lg);\n box-shadow: var(--vx-shadow-xl);\n font-family: var(--vx-font-sans);\n overflow: hidden;\n }\n\n .vx-ai-dialog__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--vx-space-2);\n padding: var(--vx-space-3) var(--vx-space-4);\n border-bottom: 1px solid var(--vx-color-border);\n flex-shrink: 0;\n }\n\n .vx-ai-dialog__title {\n margin: 0;\n font-size: var(--vx-font-size-md);\n font-weight: var(--vx-font-weight-semibold);\n }\n\n .vx-ai-dialog__actions {\n display: flex;\n gap: var(--vx-space-1);\n }\n\n .vx-ai-icon-btn {\n border: none;\n background: transparent;\n color: var(--vx-color-text-secondary);\n width: 2rem;\n height: 2rem;\n border-radius: var(--vx-radius-md);\n cursor: pointer;\n font-size: 1rem;\n }\n\n .vx-ai-icon-btn:hover {\n background: var(--vx-color-bg-hover);\n color: var(--vx-color-text);\n }\n\n .vx-ai-dialog__body {\n flex: 1;\n overflow: auto;\n padding: var(--vx-space-4);\n min-height: 220px;\n }\n\n .vx-ai-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n gap: var(--vx-space-3);\n padding: var(--vx-space-6) var(--vx-space-2);\n }\n\n .vx-ai-empty__icon {\n width: 3rem;\n height: 3rem;\n border-radius: 999px;\n display: grid;\n place-items: center;\n background: var(--vx-color-primary-subtle);\n color: var(--vx-color-primary);\n font-size: 1.25rem;\n }\n\n .vx-ai-empty__text {\n margin: 0;\n color: var(--vx-color-text-secondary);\n font-size: var(--vx-font-size-sm);\n max-width: 16rem;\n }\n\n .vx-ai-chips {\n display: flex;\n flex-wrap: wrap;\n gap: var(--vx-space-2);\n justify-content: center;\n }\n\n .vx-ai-chip {\n border: 1px solid var(--vx-color-border);\n background: var(--vx-color-bg-elevated);\n color: var(--vx-color-text);\n border-radius: var(--vx-radius-md);\n padding: 0.4rem 0.75rem;\n font-size: var(--vx-font-size-xs);\n font-family: inherit;\n cursor: pointer;\n }\n\n .vx-ai-chip:hover {\n border-color: var(--vx-color-primary);\n color: var(--vx-color-primary-ink, var(--vx-color-primary));\n }\n\n .vx-ai-messages {\n display: flex;\n flex-direction: column;\n gap: var(--vx-space-3);\n }\n\n .vx-ai-msg {\n align-self: flex-start;\n max-width: 95%;\n padding: var(--vx-space-3);\n border-radius: var(--vx-radius-md);\n background: var(--vx-color-bg-muted);\n font-size: var(--vx-font-size-sm);\n }\n\n .vx-ai-msg--user {\n align-self: flex-end;\n background: var(--vx-color-primary-subtle);\n color: var(--vx-color-primary-ink, var(--vx-color-text));\n }\n\n .vx-ai-msg__title {\n font-weight: var(--vx-font-weight-semibold);\n margin-bottom: var(--vx-space-1);\n }\n\n .vx-ai-dialog__footer {\n display: flex;\n gap: var(--vx-space-2);\n padding: var(--vx-space-3);\n border-top: 1px solid var(--vx-color-border);\n flex-shrink: 0;\n }\n\n .vx-ai-input {\n flex: 1;\n resize: none;\n border: 1px solid var(--vx-color-border-strong);\n border-radius: var(--vx-radius-md);\n padding: var(--vx-space-2) var(--vx-space-3);\n font-family: inherit;\n font-size: var(--vx-font-size-sm);\n background: var(--vx-color-bg-elevated);\n color: var(--vx-color-text);\n }\n\n .vx-ai-input:focus {\n outline: none;\n box-shadow: var(--vx-focus-ring);\n border-color: var(--vx-color-border-focus);\n }\n\n .vx-ai-send {\n width: 2.5rem;\n border: none;\n border-radius: var(--vx-radius-md);\n background: var(--vx-color-primary);\n color: var(--vx-color-primary-text);\n cursor: pointer;\n font-size: 1rem;\n }\n\n .vx-ai-send:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n }\n `,\n})\nexport class VxAIAssistantDialogComponent {\n readonly open = model(false);\n readonly title = input('AI Assistant');\n readonly placeholder = input('Digite uma mensagem');\n readonly messages = input<VxAIChatMessage[]>([]);\n readonly suggestions = input<VortexAISuggestion[]>([]);\n readonly busy = input(false);\n\n readonly sendMessage = output<string>();\n readonly suggestionSelect = output<VortexAISuggestion>();\n readonly clear = output<void>();\n readonly closed = output<void>();\n\n draft = '';\n\n close(): void {\n this.open.set(false);\n this.closed.emit();\n }\n\n onOverlayClick(_: MouseEvent): void {\n this.close();\n }\n\n onEnter(event: Event): void {\n const ke = event as KeyboardEvent;\n if (ke.shiftKey) return;\n ke.preventDefault();\n this.send();\n }\n\n send(): void {\n const text = this.draft.trim();\n if (!text || this.busy()) return;\n this.sendMessage.emit(text);\n this.draft = '';\n }\n\n onSuggestion(s: VortexAISuggestion): void {\n this.suggestionSelect.emit(s);\n }\n}\n"]}