pixelon 0.3.24 → 0.3.26

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 (231) hide show
  1. package/dist/components/atoms/chat/AudioWaves/AudioWaves(1).d.ts +21 -0
  2. package/dist/components/atoms/chat/AudioWaves/index(1).d.ts +2 -0
  3. package/dist/components/atoms/chat/DateDivider/DateDivider(1).d.ts +7 -0
  4. package/dist/components/atoms/chat/Loader/Loader(1).d.ts +10 -0
  5. package/dist/components/atoms/chat/Loader/index(1).d.ts +2 -0
  6. package/dist/components/atoms/chat/Select/index(1).d.ts +2 -0
  7. package/dist/components/atoms/lumi/Button/Button(1).d.ts +17 -0
  8. package/dist/components/atoms/lumi/Checkbox/Checkbox(1).d.ts +5 -0
  9. package/dist/components/atoms/lumi/Checkbox/index(1).d.ts +2 -0
  10. package/dist/components/atoms/lumi/Checkbox/index(2).d.ts +2 -0
  11. package/dist/components/atoms/lumi/Checkbox/types(1).d.ts +93 -0
  12. package/dist/components/atoms/lumi/CurrencyDisplay/index(1).d.ts +2 -0
  13. package/dist/components/atoms/lumi/DateDisplay/index(1).d.ts +2 -0
  14. package/dist/components/atoms/lumi/DateDisplay/index(2).d.ts +2 -0
  15. package/dist/components/atoms/lumi/DateInput/DateInput(1).d.ts +27 -0
  16. package/dist/components/atoms/lumi/DateInput/WebDatePicker(1).d.ts +19 -0
  17. package/dist/components/atoms/lumi/DateInput/WebDatePicker(2).d.ts +19 -0
  18. package/dist/components/atoms/lumi/Icon/Icon(1).d.ts +52 -0
  19. package/dist/components/atoms/lumi/Input/index(1).d.ts +3 -0
  20. package/dist/components/atoms/lumi/Popover/index(1).d.ts +2 -0
  21. package/dist/components/atoms/lumi/Popover/types(1).d.ts +62 -0
  22. package/dist/components/atoms/lumi/TextArea/index(1).d.ts +2 -0
  23. package/dist/components/atoms/lumi/TextArea/types(1).d.ts +35 -0
  24. package/dist/components/atoms/lumi/TimeInput/TimeInput(1).d.ts +27 -0
  25. package/dist/components/atoms/lumi/TimeInput/TimeInput(2).d.ts +27 -0
  26. package/dist/components/molecules/chat/Drawer/Drawer.d.ts +2 -0
  27. package/dist/components/molecules/chat/FullscreenViewer/hooks/useSwipeGestures(1).d.ts +12 -0
  28. package/dist/components/molecules/chat/StructuredContent/StructuredContent(1).d.ts +10 -0
  29. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/CarouselDisplay.d.ts +4 -0
  30. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/components/CarouselCard/CarouselCard.d.ts +15 -0
  31. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/components/CarouselConfirm/CarouselConfirm.d.ts +10 -0
  32. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/components/CarouselSearch/CarouselSearch.d.ts +8 -0
  33. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/components/CarouselTrack/CarouselTrack.d.ts +11 -0
  34. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/store/actions.d.ts +26 -0
  35. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/store/carouselStore.d.ts +8 -0
  36. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/store/index.d.ts +6 -0
  37. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/store/storeKeys.d.ts +10 -0
  38. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/store/types.d.ts +11 -0
  39. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/types.d.ts +43 -0
  40. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/useCarouselSearch.d.ts +15 -0
  41. package/dist/components/molecules/chat/StructuredContent/components/CarouselDisplay/useStoreState.d.ts +3 -0
  42. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/DynamicField(1).d.ts +13 -0
  43. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/DynamicField.d.ts +13 -0
  44. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/ReactiveForm.d.ts +4 -0
  45. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/ReactiveFormView.d.ts +10 -0
  46. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/buildYupSchema(1).d.ts +4 -0
  47. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/buildYupSchema.d.ts +4 -0
  48. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/resolveVariables.d.ts +20 -0
  49. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/types(1).d.ts +91 -0
  50. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/types.d.ts +100 -0
  51. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/useReactiveEndpoints(1).d.ts +17 -0
  52. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/useReactiveEndpoints(2).d.ts +23 -0
  53. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/useReactiveEndpoints.d.ts +23 -0
  54. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/useReactiveForm(1).d.ts +38 -0
  55. package/dist/components/molecules/chat/StructuredContent/components/ReactiveForm/useReactiveForm.d.ts +38 -0
  56. package/dist/components/molecules/chat/StructuredContent/components/index.d.ts +2 -0
  57. package/dist/components/molecules/chat/StructuredContent/helpers/contentParser(1).d.ts +7 -0
  58. package/dist/components/molecules/chat/StructuredContent/helpers/fetchViaEventBus.d.ts +2 -0
  59. package/dist/components/molecules/chat/StructuredContent/index(1).d.ts +2 -0
  60. package/dist/components/molecules/lumi/Breadcrumb/Breadcrumb(1).d.ts +10 -0
  61. package/dist/components/molecules/lumi/Breadcrumb/Breadcrumb(2).d.ts +10 -0
  62. package/dist/components/molecules/lumi/Breadcrumb/types(1).d.ts +105 -0
  63. package/dist/components/molecules/lumi/Checkbox/Checkbox(1).d.ts +11 -0
  64. package/dist/components/molecules/lumi/Checkbox/index(1).d.ts +4 -0
  65. package/dist/components/molecules/lumi/Checkbox/use-cases/index(1).d.ts +1 -0
  66. package/dist/components/molecules/lumi/Checkbox/validation-helpers(1).d.ts +151 -0
  67. package/dist/components/molecules/lumi/DateInput/FormDateInput(1).d.ts +12 -0
  68. package/dist/components/molecules/lumi/DateInput/index(1).d.ts +2 -0
  69. package/dist/components/molecules/lumi/DateInput/use-cases/FormDateInputClearWithResetUseCase(1).d.ts +21 -0
  70. package/dist/components/molecules/lumi/DateInput/use-cases/FormDateInputErrorVisibilityUseCase(1).d.ts +21 -0
  71. package/dist/components/molecules/lumi/Drawer/Drawer(1).d.ts +39 -0
  72. package/dist/components/molecules/lumi/Drawer/index(1).d.ts +2 -0
  73. package/dist/components/molecules/lumi/DropdownMenu/DropdownMenu(1).d.ts +22 -0
  74. package/dist/components/molecules/lumi/DropdownMenu/index(1).d.ts +2 -0
  75. package/dist/components/molecules/lumi/DropdownMenu/types(1).d.ts +29 -0
  76. package/dist/components/molecules/lumi/Filter/FilterRow(1).d.ts +13 -0
  77. package/dist/components/molecules/lumi/Filter/helpers/conditionHelpers(1).d.ts +14 -0
  78. package/dist/components/molecules/lumi/Filter/index(1).d.ts +5 -0
  79. package/dist/components/molecules/lumi/Filter/types(1).d.ts +115 -0
  80. package/dist/components/molecules/lumi/Input/Input(1).d.ts +12 -0
  81. package/dist/components/molecules/lumi/Menu/Menu(1).d.ts +18 -0
  82. package/dist/components/molecules/lumi/Menu/MenuContext(1).d.ts +41 -0
  83. package/dist/components/molecules/lumi/Menu/MenuItem(1).d.ts +6 -0
  84. package/dist/components/molecules/lumi/Menu/MenuItem(2).d.ts +6 -0
  85. package/dist/components/molecules/lumi/Menu/MenuItemGroup(1).d.ts +6 -0
  86. package/dist/components/molecules/lumi/Menu/SubMenu(1).d.ts +6 -0
  87. package/dist/components/molecules/lumi/Menu/iconHelper(1).d.ts +15 -0
  88. package/dist/components/molecules/lumi/Menu/index(1).d.ts +8 -0
  89. package/dist/components/molecules/lumi/Menu/index(2).d.ts +8 -0
  90. package/dist/components/molecules/lumi/Menu/types(1).d.ts +119 -0
  91. package/dist/components/molecules/lumi/Pagination/Pagination(1).d.ts +4 -0
  92. package/dist/components/molecules/lumi/Pagination/index(1).d.ts +2 -0
  93. package/dist/components/molecules/lumi/Select/Select(1).d.ts +14 -0
  94. package/dist/components/molecules/lumi/Select/Select(2).d.ts +14 -0
  95. package/dist/components/molecules/lumi/Select/Select(3).d.ts +14 -0
  96. package/dist/components/molecules/lumi/Select/index(1).d.ts +2 -0
  97. package/dist/components/molecules/lumi/Select/index(2).d.ts +2 -0
  98. package/dist/components/molecules/lumi/Select/use-cases/FormSelectClearWithResetUseCase(1).d.ts +21 -0
  99. package/dist/components/molecules/lumi/Select/use-cases/FormSelectClearWithResetUseCase(2).d.ts +21 -0
  100. package/dist/components/molecules/lumi/Select/use-cases/index(1).d.ts +2 -0
  101. package/dist/components/molecules/lumi/Select/use-cases/index(2).d.ts +2 -0
  102. package/dist/components/molecules/lumi/Table/Table(1).d.ts +6 -0
  103. package/dist/components/molecules/lumi/Table/Table(2).d.ts +6 -0
  104. package/dist/components/molecules/lumi/Table/index(1).d.ts +2 -0
  105. package/dist/components/molecules/lumi/Table/types(1).d.ts +177 -0
  106. package/dist/components/molecules/lumi/Table/types(2).d.ts +177 -0
  107. package/dist/components/molecules/lumi/Tabs/Tabs(1).d.ts +4 -0
  108. package/dist/components/molecules/lumi/Tabs/Tabs(2).d.ts +4 -0
  109. package/dist/components/molecules/lumi/Tabs/index(1).d.ts +2 -0
  110. package/dist/components/molecules/lumi/Tabs/index(2).d.ts +2 -0
  111. package/dist/components/molecules/lumi/TimeInput/FormTimeInput(1).d.ts +12 -0
  112. package/dist/components/molecules/lumi/TimeInput/use-cases/FormTimeInputClearWithResetUseCase(1).d.ts +21 -0
  113. package/dist/components/molecules/lumi/TimeInput/use-cases/FormTimeInputErrorVisibilityUseCase(1).d.ts +21 -0
  114. package/dist/components/molecules/lumi/TimeInput/use-cases/index(1).d.ts +4 -0
  115. package/dist/components/organisms/chat/Chat/Chat(1).d.ts +12 -0
  116. package/dist/components/organisms/chat/Chat/hooks/useChatHandlers(1).d.ts +15 -0
  117. package/dist/components/organisms/chat/Chat/hooks/useChatStore.d.ts +3 -0
  118. package/dist/components/organisms/chat/Chat/hooks/useKeyboardLock(1).d.ts +15 -0
  119. package/dist/components/organisms/chat/Chat/index(1).d.ts +3 -0
  120. package/dist/components/organisms/chat/Chat/store/actions.d.ts +3 -0
  121. package/dist/components/organisms/chat/Chat/store/index(1).d.ts +4 -0
  122. package/dist/components/organisms/chat/Chat/store/types.d.ts +3 -0
  123. package/dist/components/organisms/chat/Chat/use-cases/GroupMessagesByDateUseCase(1).d.ts +20 -0
  124. package/dist/components/organisms/chat/index(1).d.ts +3 -0
  125. package/dist/components/organisms/chat/index(2).d.ts +3 -0
  126. package/dist/components/organisms/lumi/ActionBar/ActionBar(1).d.ts +18 -0
  127. package/dist/components/organisms/lumi/ActionBar/types(1).d.ts +57 -0
  128. package/dist/components/organisms/lumi/BaseNavbar/types(1).d.ts +34 -0
  129. package/dist/components/organisms/lumi/BaseWorkspace/BaseWorkspace(1).d.ts +28 -0
  130. package/dist/components/organisms/lumi/BaseWorkspace/index(1).d.ts +2 -0
  131. package/dist/components/organisms/lumi/Calendar/components/CalendarEvent(1).d.ts +18 -0
  132. package/dist/components/organisms/lumi/Calendar/components/CalendarEvent(2).d.ts +18 -0
  133. package/dist/components/organisms/lumi/Calendar/components/CalendarEvent(3).d.ts +18 -0
  134. package/dist/components/organisms/lumi/Calendar/components/CalendarHeader(1).d.ts +14 -0
  135. package/dist/components/organisms/lumi/Calendar/components/TimeGutter(1).d.ts +10 -0
  136. package/dist/components/organisms/lumi/Calendar/components/TimeGutter(2).d.ts +10 -0
  137. package/dist/components/organisms/lumi/Calendar/hooks/index(1).d.ts +4 -0
  138. package/dist/components/organisms/lumi/Calendar/hooks/useCalendarHeight(1).d.ts +58 -0
  139. package/dist/components/organisms/lumi/Calendar/hooks/useCalendarHeight(2).d.ts +58 -0
  140. package/dist/components/organisms/lumi/Calendar/hooks/useEventLayout(1).d.ts +21 -0
  141. package/dist/components/organisms/lumi/Calendar/hooks/useEventLayout(2).d.ts +21 -0
  142. package/dist/components/organisms/lumi/Calendar/hooks/useTimeSlots(1).d.ts +14 -0
  143. package/dist/components/organisms/lumi/Calendar/hooks/useTimeSlots(2).d.ts +14 -0
  144. package/dist/components/organisms/lumi/Calendar/hooks/useTimeSlots(3).d.ts +14 -0
  145. package/dist/components/organisms/lumi/Calendar/i18n/index(1).d.ts +1 -0
  146. package/dist/components/organisms/lumi/Calendar/i18n/index(2).d.ts +1 -0
  147. package/dist/components/organisms/lumi/Calendar/i18n/translations(1).d.ts +34 -0
  148. package/dist/components/organisms/lumi/Calendar/index(1).d.ts +2 -0
  149. package/dist/components/organisms/lumi/Calendar/utils/dateUtils(1).d.ts +140 -0
  150. package/dist/components/organisms/lumi/Calendar/utils/dateUtils(2).d.ts +140 -0
  151. package/dist/components/organisms/lumi/Calendar/utils/index(1).d.ts +2 -0
  152. package/dist/components/organisms/lumi/Calendar/utils/multiDayUtils(1).d.ts +73 -0
  153. package/dist/components/organisms/lumi/Calendar/views/DayView(1).d.ts +17 -0
  154. package/dist/components/organisms/lumi/Calendar/views/DayView(2).d.ts +17 -0
  155. package/dist/components/organisms/lumi/Calendar/views/MonthView(1).d.ts +17 -0
  156. package/dist/components/organisms/lumi/Calendar/views/MonthView(2).d.ts +17 -0
  157. package/dist/components/organisms/lumi/Calendar/views/WeekView(1).d.ts +19 -0
  158. package/dist/components/organisms/lumi/Calendar/views/WeekView(2).d.ts +19 -0
  159. package/dist/components/organisms/lumi/Calendar/views/YearView(1).d.ts +13 -0
  160. package/dist/components/organisms/lumi/Calendar/views/index(1).d.ts +4 -0
  161. package/dist/components/organisms/lumi/Calendar/views/index(2).d.ts +4 -0
  162. package/dist/components/organisms/lumi/DashboardNavbar/index(1).d.ts +7 -0
  163. package/dist/components/organisms/lumi/DashboardNavbar/types(1).d.ts +52 -0
  164. package/dist/components/organisms/lumi/DashboardWorkspace/DashboardWorkspace(1).d.ts +23 -0
  165. package/dist/components/organisms/lumi/DashboardWorkspace/DashboardWorkspace(2).d.ts +23 -0
  166. package/dist/components/organisms/lumi/DashboardWorkspace/index(1).d.ts +7 -0
  167. package/dist/components/organisms/lumi/DashboardWorkspace/index(2).d.ts +7 -0
  168. package/dist/components/organisms/lumi/DashboardWorkspace/types(1).d.ts +60 -0
  169. package/dist/components/organisms/lumi/DashboardWorkspace/types(2).d.ts +60 -0
  170. package/dist/components/organisms/lumi/DynamicForm/DynamicForm(1).d.ts +21 -0
  171. package/dist/components/organisms/lumi/DynamicForm/helpers/fieldMapper(1).d.ts +17 -0
  172. package/dist/components/organisms/lumi/DynamicForm/helpers/fieldMapper(2).d.ts +17 -0
  173. package/dist/components/organisms/lumi/DynamicForm/helpers/fieldRenderer(1).d.ts +6 -0
  174. package/dist/components/organisms/lumi/DynamicForm/helpers/fieldRenderer(2).d.ts +6 -0
  175. package/dist/components/organisms/lumi/DynamicForm/index(1).d.ts +2 -0
  176. package/dist/components/organisms/lumi/DynamicForm/index(2).d.ts +2 -0
  177. package/dist/components/organisms/lumi/DynamicForm/types(1).d.ts +96 -0
  178. package/dist/components/organisms/lumi/DynamicForm/types(2).d.ts +96 -0
  179. package/dist/components/organisms/lumi/FormDrawer/FormDrawer(1).d.ts +5 -0
  180. package/dist/components/organisms/lumi/FormDrawer/index(1).d.ts +3 -0
  181. package/dist/components/organisms/lumi/FormDrawer/types(1).d.ts +61 -0
  182. package/dist/components/organisms/lumi/FormDrawer/types(2).d.ts +61 -0
  183. package/dist/components/organisms/lumi/Stepper/StepIndicator(1).d.ts +4 -0
  184. package/dist/components/organisms/lumi/Stepper/Stepper(1).d.ts +5 -0
  185. package/dist/components/organisms/lumi/Stepper/index(1).d.ts +3 -0
  186. package/dist/components/organisms/lumi/Stepper/types(1).d.ts +96 -0
  187. package/dist/components/organisms/lumi/Stepper/types(2).d.ts +96 -0
  188. package/dist/components/organisms/lumi/index(1).d.ts +10 -0
  189. package/dist/components/organisms/lumi/index(2).d.ts +10 -0
  190. package/dist/components/templates/chat/ChatWidget/ChatWidget(1).d.ts +10 -0
  191. package/dist/components/templates/chat/ChatWidget/hooks/index(1).d.ts +1 -0
  192. package/dist/components/templates/chat/ChatWidget/index(1).d.ts +2 -0
  193. package/dist/components/templates/chat/ChatWidget/index(2).d.ts +2 -0
  194. package/dist/components/templates/chat/ChatWidget/types(1).d.ts +90 -0
  195. package/dist/components/templates/lumi/Base/hooks/index(1).d.ts +2 -0
  196. package/dist/components/templates/lumi/Base/hooks/useAppHeight(1).d.ts +21 -0
  197. package/dist/components/templates/lumi/Base/index(1).d.ts +2 -0
  198. package/dist/components/templates/lumi/Base/types(1).d.ts +54 -0
  199. package/dist/components/templates/lumi/Crud/Crud(1).d.ts +6 -0
  200. package/dist/components/templates/lumi/Crud/Crud(2).d.ts +6 -0
  201. package/dist/components/templates/lumi/Crud/helpers/fieldMapper(1).d.ts +13 -0
  202. package/dist/components/templates/lumi/Crud/hooks/useCrudActions(1).d.ts +11 -0
  203. package/dist/components/templates/lumi/Crud/index(1).d.ts +2 -0
  204. package/dist/components/templates/lumi/Crud/store/actions(1).d.ts +45 -0
  205. package/dist/components/templates/lumi/Crud/store/crudStore(1).d.ts +8 -0
  206. package/dist/components/templates/lumi/Crud/store/index(1).d.ts +5 -0
  207. package/dist/components/templates/lumi/Crud/store/types(1).d.ts +71 -0
  208. package/dist/components/templates/lumi/Dashboard/Dashboard(1).d.ts +25 -0
  209. package/dist/components/templates/lumi/Dashboard/hooks/index(1).d.ts +12 -0
  210. package/dist/components/templates/lumi/Dashboard/hooks/index(2).d.ts +12 -0
  211. package/dist/components/templates/lumi/Dashboard/hooks/useDashboardStore(1).d.ts +34 -0
  212. package/dist/components/templates/lumi/Dashboard/hooks/useScrollToTop(1).d.ts +47 -0
  213. package/dist/components/templates/lumi/Dashboard/index(1).d.ts +10 -0
  214. package/dist/components/templates/lumi/Dashboard/store/storeKeys(1).d.ts +13 -0
  215. package/dist/components/templates/lumi/Dashboard/store/types(1).d.ts +73 -0
  216. package/dist/components/templates/lumi/Dashboard/store/types(2).d.ts +73 -0
  217. package/dist/components/templates/lumi/Dashboard/types(1).d.ts +114 -0
  218. package/dist/components/templates/lumi/Dashboard/types(2).d.ts +114 -0
  219. package/dist/components/templates/lumi/index(1).d.ts +3 -0
  220. package/dist/core/chat/ChatConfigContext(1).d.ts +36 -0
  221. package/dist/core/chat/chatMessage.d.ts +1 -1
  222. package/dist/core/eventBus/chatEventBus.d.ts +72 -0
  223. package/dist/index(1).esm.js +19378 -0
  224. package/dist/index(1).js +19487 -0
  225. package/dist/index.esm.js +2260 -382
  226. package/dist/index.js +2260 -382
  227. package/dist/styles(1).css +1 -0
  228. package/dist/styles.css +1 -1
  229. package/dist/styles.css.map +1 -1
  230. package/package.json +1 -1
  231. package/src/styles/index.scss +7 -0
package/dist/index.esm.js CHANGED
@@ -6,9 +6,9 @@ import ReactMarkdown from 'react-markdown';
6
6
  import DatePicker, { registerLocale } from 'react-datepicker';
7
7
  import { es } from 'date-fns/locale';
8
8
  import 'react-datepicker/dist/react-datepicker.css';
9
+ import * as yup from 'yup';
9
10
  import { QRCodeCanvas, QRCodeSVG } from 'qrcode.react';
10
11
  import { Controller, useFormContext, useForm, useWatch, FormProvider } from 'react-hook-form';
11
- import * as yup from 'yup';
12
12
  import { Link as Link$1 } from 'react-router-dom';
13
13
  import { yupResolver } from '@hookform/resolvers/yup';
14
14
 
@@ -1618,7 +1618,7 @@ function parseContent(content) {
1618
1618
  return null;
1619
1619
  }
1620
1620
 
1621
- const DISPLAY_COMPONENTS = /* @__PURE__ */ new Set(["card", "badge"]);
1621
+ const DISPLAY_COMPONENTS = /* @__PURE__ */ new Set(["card", "badge", "reactive_form", "carousel"]);
1622
1622
 
1623
1623
  const useAppHeight$5 = () => {
1624
1624
  useEffect(() => {
@@ -1658,6 +1658,7 @@ const Drawer$1 = ({
1658
1658
  title,
1659
1659
  headerExtra,
1660
1660
  footer,
1661
+ placement = "bottom",
1661
1662
  showCloseButton = true,
1662
1663
  closeOnOverlayClick = true,
1663
1664
  closeOnEscape = true,
@@ -1709,6 +1710,7 @@ const Drawer$1 = ({
1709
1710
  const drawerClasses = [
1710
1711
  `${prefix}drawer`,
1711
1712
  animating && `${prefix}drawer--open`,
1713
+ `${prefix}drawer--${placement}`,
1712
1714
  className
1713
1715
  ].filter(Boolean).join(" ");
1714
1716
  return createPortal(
@@ -1774,7 +1776,15 @@ const CHAT_EVENT = {
1774
1776
  RETRY_MESSAGE: "retryMessage",
1775
1777
  PLACEHOLDER_UPDATED: "placeholderUpdated",
1776
1778
  THINKING_UPDATED: "thinkingUpdated",
1777
- CLOSE: "close"
1779
+ INPUT_DISABLED: "inputDisabled",
1780
+ CLOSE: "close",
1781
+ FETCH_REQUEST: "fetchRequest",
1782
+ FETCH_RESPONSE: "fetchResponse",
1783
+ FORM_SUBMIT: "formSubmit",
1784
+ FORM_TRACE: "formTrace",
1785
+ AGENT_EVENT: "agentEvent",
1786
+ STREAM_CHUNK: "streamChunk",
1787
+ MESSAGE_SAVED: "messageSaved"
1778
1788
  };
1779
1789
  const chatEventBus = createEventBus();
1780
1790
 
@@ -1801,13 +1811,13 @@ function useComponentInteraction({
1801
1811
  return { emitInteraction, isConfirmed };
1802
1812
  }
1803
1813
 
1804
- const MOBILE_BREAKPOINT$3 = 640;
1805
- const useIsMobile$4 = () => {
1814
+ const MOBILE_BREAKPOINT$4 = 640;
1815
+ const useIsMobile$5 = () => {
1806
1816
  const [isMobile, setIsMobile] = useState(
1807
- typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT$3 : false
1817
+ typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT$4 : false
1808
1818
  );
1809
1819
  useEffect(() => {
1810
- const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT$3 - 1}px)`);
1820
+ const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT$4 - 1}px)`);
1811
1821
  const handler = (e) => setIsMobile(e.matches);
1812
1822
  mq.addEventListener("change", handler);
1813
1823
  return () => mq.removeEventListener("change", handler);
@@ -1823,7 +1833,7 @@ const SelectWithConfirm = ({
1823
1833
  const [isDrawerOpen, setIsDrawerOpen] = useState(false);
1824
1834
  const [searchValue, setSearchValue] = useState("");
1825
1835
  const searchInputRef = useRef(null);
1826
- const isMobile = useIsMobile$4();
1836
+ const isMobile = useIsMobile$5();
1827
1837
  const { field_name, value, ...componentProps } = component.props;
1828
1838
  const options = componentProps.options || [];
1829
1839
  const placeholder = componentProps.placeholder || "Seleccionar...";
@@ -1990,13 +2000,13 @@ const SelectWithConfirm = ({
1990
2000
  ] });
1991
2001
  };
1992
2002
 
1993
- const MOBILE_BREAKPOINT$2 = 640;
1994
- const useIsMobile$3 = () => {
2003
+ const MOBILE_BREAKPOINT$3 = 640;
2004
+ const useIsMobile$4 = () => {
1995
2005
  const [isMobile, setIsMobile] = useState(
1996
- typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT$2 : false
2006
+ typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT$3 : false
1997
2007
  );
1998
2008
  useEffect(() => {
1999
- const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT$2 - 1}px)`);
2009
+ const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT$3 - 1}px)`);
2000
2010
  const handler = (e) => setIsMobile(e.matches);
2001
2011
  mq.addEventListener("change", handler);
2002
2012
  return () => mq.removeEventListener("change", handler);
@@ -2012,7 +2022,7 @@ const SelectMultipleWithConfirm = ({
2012
2022
  const [isDrawerOpen, setIsDrawerOpen] = useState(false);
2013
2023
  const [searchValue, setSearchValue] = useState("");
2014
2024
  const searchInputRef = useRef(null);
2015
- const isMobile = useIsMobile$3();
2025
+ const isMobile = useIsMobile$4();
2016
2026
  const { field_name, value, ...componentProps } = component.props;
2017
2027
  const options = componentProps.options || [];
2018
2028
  const placeholder = componentProps.placeholder || "Seleccionar...";
@@ -2255,8 +2265,8 @@ const ChatConfigProvider = ({ value, children }) => /* @__PURE__ */ jsx(ChatConf
2255
2265
  const useChatConfig = () => useContext(ChatConfigContext);
2256
2266
 
2257
2267
  registerLocale("es", es);
2258
- const MOBILE_BREAKPOINT$1 = 640;
2259
- const parseDate$2 = (dateString) => {
2268
+ const MOBILE_BREAKPOINT$2 = 640;
2269
+ const parseDate$3 = (dateString) => {
2260
2270
  if (!dateString) return null;
2261
2271
  try {
2262
2272
  if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
@@ -2269,14 +2279,14 @@ const parseDate$2 = (dateString) => {
2269
2279
  return null;
2270
2280
  }
2271
2281
  };
2272
- const formatDateToISO = (date) => {
2282
+ const formatDateToISO$1 = (date) => {
2273
2283
  if (!date) return "";
2274
2284
  const year = date.getFullYear();
2275
2285
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
2276
2286
  const day = date.getDate().toString().padStart(2, "0");
2277
2287
  return `${year}-${month}-${day}`;
2278
2288
  };
2279
- const formatDateDisplay = (date, locale, timezone) => {
2289
+ const formatDateDisplay$1 = (date, locale, timezone) => {
2280
2290
  if (!date) return "";
2281
2291
  return date.toLocaleDateString(locale, {
2282
2292
  day: "2-digit",
@@ -2325,12 +2335,12 @@ const CustomHeader$1 = ({
2325
2335
  )
2326
2336
  ] });
2327
2337
  };
2328
- const useIsMobile$2 = () => {
2338
+ const useIsMobile$3 = () => {
2329
2339
  const [isMobile, setIsMobile] = useState(
2330
- typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT$1 : false
2340
+ typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT$2 : false
2331
2341
  );
2332
2342
  useEffect(() => {
2333
- const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT$1 - 1}px)`);
2343
+ const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT$2 - 1}px)`);
2334
2344
  const handler = (e) => setIsMobile(e.matches);
2335
2345
  mq.addEventListener("change", handler);
2336
2346
  return () => mq.removeEventListener("change", handler);
@@ -2346,15 +2356,15 @@ const DateInputWithConfirm = ({
2346
2356
  const [selectedDate, setSelectedDate] = useState(null);
2347
2357
  const [isOpen, setIsOpen] = useState(false);
2348
2358
  const triggerRef = useRef(null);
2349
- const isMobile = useIsMobile$2();
2359
+ const isMobile = useIsMobile$3();
2350
2360
  const { emitInteraction, isConfirmed } = useComponentInteraction({
2351
2361
  eventBus,
2352
2362
  fieldName: component.props.field_name,
2353
2363
  componentType: component.type,
2354
2364
  assistantMessageId
2355
2365
  });
2356
- const minDate = component.props.min_date ? parseDate$2(component.props.min_date) : void 0;
2357
- const maxDate = component.props.max_date ? parseDate$2(component.props.max_date) : void 0;
2366
+ const minDate = component.props.min_date ? parseDate$3(component.props.min_date) : void 0;
2367
+ const maxDate = component.props.max_date ? parseDate$3(component.props.max_date) : void 0;
2358
2368
  useEffect(() => {
2359
2369
  if (!isOpen || isMobile) return;
2360
2370
  const handleKey = (e) => {
@@ -2371,12 +2381,12 @@ const DateInputWithConfirm = ({
2371
2381
  };
2372
2382
  const handleConfirm = useCallback(() => {
2373
2383
  if (!selectedDate) return;
2374
- const isoValue = formatDateToISO(selectedDate);
2375
- const displayValue2 = formatDateDisplay(selectedDate, locale, timezone);
2384
+ const isoValue = formatDateToISO$1(selectedDate);
2385
+ const displayValue2 = formatDateDisplay$1(selectedDate, locale, timezone);
2376
2386
  emitInteraction(isoValue, displayValue2);
2377
2387
  setIsOpen(false);
2378
2388
  }, [selectedDate, emitInteraction, locale, timezone]);
2379
- const displayValue = formatDateDisplay(selectedDate, locale, timezone);
2389
+ const displayValue = formatDateDisplay$1(selectedDate, locale, timezone);
2380
2390
  const placeholder = component.props.placeholder || "Selecciona una fecha";
2381
2391
  const label = component.props.label || "Selecciona una fecha";
2382
2392
  const calendarContent = /* @__PURE__ */ jsx(
@@ -2515,13 +2525,14 @@ const ConfirmButton = ({
2515
2525
  };
2516
2526
 
2517
2527
  const CardDisplay = ({ component }) => {
2518
- const { title, rows, variant = "default" } = component.props;
2528
+ const { title, rows, content, variant = "default" } = component.props;
2519
2529
  return /* @__PURE__ */ jsxs("div", { className: `px-chat-card px-chat-card--${variant}`, children: [
2520
2530
  /* @__PURE__ */ jsx("div", { className: "px-chat-card__title", children: title }),
2521
- /* @__PURE__ */ jsx("div", { className: "px-chat-card__rows", children: rows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: "px-chat-card__row", children: [
2531
+ content && !rows?.length && /* @__PURE__ */ jsx("div", { className: "px-chat-card__content", children: content }),
2532
+ rows?.length ? /* @__PURE__ */ jsx("div", { className: "px-chat-card__rows", children: rows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: "px-chat-card__row", children: [
2522
2533
  /* @__PURE__ */ jsx("span", { className: "px-chat-card__row-label", children: row.label }),
2523
2534
  /* @__PURE__ */ jsx("span", { className: "px-chat-card__row-value", children: row.value })
2524
- ] }, i)) })
2535
+ ] }, i)) }) : null
2525
2536
  ] });
2526
2537
  };
2527
2538
 
@@ -2672,13 +2683,13 @@ const ScrollableColumn$1 = ({
2672
2683
  ] });
2673
2684
  };
2674
2685
 
2675
- const MOBILE_BREAKPOINT = 640;
2676
- const useIsMobile$1 = () => {
2686
+ const MOBILE_BREAKPOINT$1 = 640;
2687
+ const useIsMobile$2 = () => {
2677
2688
  const [isMobile, setIsMobile] = useState(
2678
- typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT : false
2689
+ typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT$1 : false
2679
2690
  );
2680
2691
  useEffect(() => {
2681
- const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
2692
+ const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT$1 - 1}px)`);
2682
2693
  const handler = (e) => setIsMobile(e.matches);
2683
2694
  mq.addEventListener("change", handler);
2684
2695
  return () => mq.removeEventListener("change", handler);
@@ -2731,7 +2742,7 @@ const TimeInputWithConfirm = ({
2731
2742
  assistantMessageId = ""
2732
2743
  }) => {
2733
2744
  const { timezone, locale } = useChatConfig();
2734
- const isMobile = useIsMobile$1();
2745
+ const isMobile = useIsMobile$2();
2735
2746
  const [isOpen, setIsOpen] = useState(false);
2736
2747
  const [confirmedTime, setConfirmedTime] = useState("");
2737
2748
  const triggerRef = useRef(null);
@@ -2972,130 +2983,1926 @@ const TimeInputWithConfirm = ({
2972
2983
  ] });
2973
2984
  };
2974
2985
 
2975
- const COMPONENT_MAP = {
2976
- select: SelectWithConfirm,
2977
- select_multiple: SelectMultipleWithConfirm,
2978
- confirm: ConfirmButton,
2979
- date_input: DateInputWithConfirm,
2980
- time_input: TimeInputWithConfirm,
2981
- input: InputWithConfirm,
2982
- card: CardDisplay,
2983
- badge: BadgeDisplay
2984
- };
2985
- function renderComponent(props) {
2986
- const { component } = props;
2987
- if (component.answered && !DISPLAY_COMPONENTS.has(component.type)) {
2986
+ registerLocale("es", es);
2987
+ const parseDate$2 = (dateString) => {
2988
+ if (!dateString) return null;
2989
+ try {
2990
+ if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
2991
+ const [year, month, day] = dateString.split("-").map(Number);
2992
+ return new Date(year, month - 1, day);
2993
+ }
2994
+ const parsed = new Date(dateString);
2995
+ return isNaN(parsed.getTime()) ? null : parsed;
2996
+ } catch {
2988
2997
  return null;
2989
2998
  }
2990
- const Component = COMPONENT_MAP[component.type];
2991
- if (!Component) return null;
2992
- return /* @__PURE__ */ jsx(Component, { ...props });
2993
- }
2994
-
2995
- const StructuredContent = ({
2996
- content,
2997
- eventBus,
2998
- assistantMessageId,
2999
- className = ""
2999
+ };
3000
+ const formatDateToISO = (date) => {
3001
+ if (!date) return "";
3002
+ const year = date.getFullYear();
3003
+ const month = (date.getMonth() + 1).toString().padStart(2, "0");
3004
+ const day = date.getDate().toString().padStart(2, "0");
3005
+ return `${year}-${month}-${day}`;
3006
+ };
3007
+ const formatDateDisplay = (date) => {
3008
+ if (!date) return "";
3009
+ return date.toLocaleDateString("es", { day: "2-digit", month: "long", year: "numeric" });
3010
+ };
3011
+ const DynamicField = ({
3012
+ field,
3013
+ value,
3014
+ error,
3015
+ disabled,
3016
+ fieldState,
3017
+ onChange,
3018
+ drawerPlacement = "bottom"
3000
3019
  }) => {
3001
- const structured = parseContent(content);
3002
- const markdownContent = structured ? structured.message : content;
3003
- const rawComponent = structured?.component || null;
3004
- const components = rawComponent ? Array.isArray(rawComponent) ? rawComponent : [rawComponent] : [];
3005
- const hasVisibleComponents = components.some((comp) => !comp.answered || DISPLAY_COMPONENTS.has(comp.type));
3006
- return /* @__PURE__ */ jsxs("div", { className: `${COMPONENT_PREFIX$1}structured-content ${className}`, children: [
3007
- markdownContent && /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX$1}assistant-message__markdown${hasVisibleComponents ? ` ${COMPONENT_PREFIX$1}assistant-message__markdown--with-component` : ``}`, children: /* @__PURE__ */ jsx(
3008
- ReactMarkdown,
3020
+ const { loading, options } = fieldState;
3021
+ if (field.type === "hidden") return null;
3022
+ const renderField = () => {
3023
+ switch (field.type) {
3024
+ case "select":
3025
+ return /* @__PURE__ */ jsx(
3026
+ SelectField$1,
3027
+ {
3028
+ field,
3029
+ value,
3030
+ disabled,
3031
+ loading,
3032
+ options,
3033
+ onChange,
3034
+ drawerPlacement
3035
+ }
3036
+ );
3037
+ case "select_multiple":
3038
+ return /* @__PURE__ */ jsx(
3039
+ SelectMultipleField,
3040
+ {
3041
+ field,
3042
+ value,
3043
+ disabled,
3044
+ loading,
3045
+ options,
3046
+ onChange,
3047
+ drawerPlacement
3048
+ }
3049
+ );
3050
+ case "date":
3051
+ return /* @__PURE__ */ jsx(
3052
+ DateField,
3053
+ {
3054
+ field,
3055
+ value,
3056
+ disabled,
3057
+ onChange,
3058
+ drawerPlacement
3059
+ }
3060
+ );
3061
+ default:
3062
+ return /* @__PURE__ */ jsx(
3063
+ "input",
3064
+ {
3065
+ type: field.type === "email" ? "email" : field.type === "number" ? "number" : "text",
3066
+ className: "px-chat-rf__input",
3067
+ placeholder: field.placeholder,
3068
+ value: value || "",
3069
+ disabled,
3070
+ onChange: (e) => onChange(e.target.value, e.target.value)
3071
+ }
3072
+ );
3073
+ }
3074
+ };
3075
+ return /* @__PURE__ */ jsxs("div", { className: `px-chat-rf__field ${error ? "px-chat-rf__field--error" : ""} ${disabled ? "px-chat-rf__field--disabled" : ""}`, children: [
3076
+ /* @__PURE__ */ jsx("label", { className: "px-chat-rf__field-label", children: field.label }),
3077
+ renderField(),
3078
+ error && /* @__PURE__ */ jsx("span", { className: "px-chat-rf__field-error", children: error })
3079
+ ] });
3080
+ };
3081
+ const SelectField$1 = ({ field, value, disabled, loading, options, onChange, drawerPlacement }) => {
3082
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
3083
+ const [searchValue, setSearchValue] = useState("");
3084
+ const searchInputRef = useRef(null);
3085
+ const selectedLabel = options.find((o) => o.value === value)?.label || "";
3086
+ const placeholder = loading ? "Cargando..." : field.placeholder || "Seleccionar...";
3087
+ const filteredOptions = searchValue ? options.filter((opt) => opt.label.toLowerCase().includes(searchValue.toLowerCase())) : options;
3088
+ useEffect(() => {
3089
+ if (isDrawerOpen && searchInputRef.current) {
3090
+ setTimeout(() => searchInputRef.current?.focus(), 350);
3091
+ }
3092
+ }, [isDrawerOpen]);
3093
+ const handleSelect = (opt) => {
3094
+ const { value: v, label, ...extra } = opt;
3095
+ onChange(v, label, Object.keys(extra).length > 0 ? extra : void 0);
3096
+ };
3097
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3098
+ /* @__PURE__ */ jsxs(
3099
+ "div",
3009
3100
  {
3010
- components: {
3011
- a: ({ href, children }) => /* @__PURE__ */ jsx(
3012
- Link,
3013
- {
3014
- href: href || "#",
3015
- variant: "primary",
3016
- size: "medium",
3017
- weight: "bold",
3018
- underline: false,
3019
- children
3020
- }
3021
- )
3101
+ className: `px-chat-select-with-confirm__trigger ${isDrawerOpen ? "px-chat-select-with-confirm__trigger--open" : ""}`,
3102
+ onClick: () => !disabled && !loading && setIsDrawerOpen(true),
3103
+ role: "button",
3104
+ tabIndex: disabled ? -1 : 0,
3105
+ onKeyDown: (e) => {
3106
+ if (!disabled && (e.key === "Enter" || e.key === " ")) setIsDrawerOpen(true);
3022
3107
  },
3023
- children: markdownContent
3108
+ children: [
3109
+ /* @__PURE__ */ jsx("span", { className: `px-chat-select-with-confirm__trigger-text ${!value ? "px-chat-select-with-confirm__trigger-text--placeholder" : ""}`, children: value ? selectedLabel : placeholder }),
3110
+ /* @__PURE__ */ jsx("span", { className: "px-chat-select-with-confirm__chevron", children: loading ? /* @__PURE__ */ jsx(Loader$1, { size: "small" }) : /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.CHEVRON_DOWN, size: "small" }) })
3111
+ ]
3024
3112
  }
3025
- ) }),
3026
- components.length > 0 && /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX$1}structured-content__component`, children: components.map((comp, index) => /* @__PURE__ */ jsx(React.Fragment, { children: renderComponent({ component: comp, eventBus, assistantMessageId }) }, `${comp.type}-${index}`)) })
3113
+ ),
3114
+ /* @__PURE__ */ jsx(
3115
+ Drawer$1,
3116
+ {
3117
+ isOpen: isDrawerOpen,
3118
+ onClose: () => {
3119
+ setIsDrawerOpen(false);
3120
+ setSearchValue("");
3121
+ },
3122
+ title: field.label,
3123
+ placement: drawerPlacement,
3124
+ children: /* @__PURE__ */ jsxs("div", { className: "px-chat-select-drawer px-chat-rf-select-drawer", children: [
3125
+ /* @__PURE__ */ jsxs("div", { className: "px-chat-select-drawer__search", children: [
3126
+ /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.SEARCH, size: "small" }),
3127
+ /* @__PURE__ */ jsx(
3128
+ "input",
3129
+ {
3130
+ ref: searchInputRef,
3131
+ type: "text",
3132
+ className: "px-chat-select-drawer__search-input",
3133
+ value: searchValue,
3134
+ onChange: (e) => setSearchValue(e.target.value),
3135
+ placeholder: "Buscar..."
3136
+ }
3137
+ ),
3138
+ searchValue && /* @__PURE__ */ jsx("button", { type: "button", className: "px-chat-select-drawer__search-clear", onClick: () => setSearchValue(""), children: /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.CLOSE, size: "small" }) })
3139
+ ] }),
3140
+ /* @__PURE__ */ jsx("ul", { className: "px-chat-select-drawer__options", role: "listbox", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("li", { className: "px-chat-select-drawer__empty", children: "No hay opciones disponibles" }) : filteredOptions.map((opt) => {
3141
+ const isSelected = opt.value === value;
3142
+ return /* @__PURE__ */ jsxs(
3143
+ "li",
3144
+ {
3145
+ className: `px-chat-select-drawer__option ${isSelected ? "px-chat-select-drawer__option--selected" : ""}`,
3146
+ onClick: () => {
3147
+ handleSelect(opt);
3148
+ setIsDrawerOpen(false);
3149
+ setSearchValue("");
3150
+ },
3151
+ role: "option",
3152
+ "aria-selected": isSelected,
3153
+ children: [
3154
+ /* @__PURE__ */ jsx("span", { className: "px-chat-select-drawer__option-label", children: opt.label }),
3155
+ isSelected && /* @__PURE__ */ jsx("span", { className: "px-chat-select-drawer__option-check", children: /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.CHECK, size: "small" }) })
3156
+ ]
3157
+ },
3158
+ opt.value
3159
+ );
3160
+ }) })
3161
+ ] })
3162
+ }
3163
+ )
3027
3164
  ] });
3028
3165
  };
3029
-
3030
- const getAttachmentType = (file) => {
3031
- const mimeType = file.type.toLowerCase();
3032
- if (mimeType.startsWith(MIME_PREFIXES.AUDIO)) {
3033
- return AttachmentType.AUDIO;
3034
- }
3035
- if (mimeType.startsWith(MIME_PREFIXES.VIDEO)) {
3036
- return AttachmentType.VIDEO;
3037
- }
3038
- if (mimeType.startsWith(MIME_PREFIXES.IMAGE)) {
3039
- return AttachmentType.IMAGE;
3040
- }
3041
- if (mimeType === MIME_TYPES.PDF) {
3042
- return AttachmentType.PDF;
3043
- }
3044
- if (mimeType.includes(MIME_KEYWORDS.DOCUMENT) || mimeType.includes(MIME_KEYWORDS.WORD) || mimeType.includes(MIME_KEYWORDS.EXCEL) || mimeType.includes(MIME_KEYWORDS.POWERPOINT) || mimeType.startsWith(MIME_PREFIXES.TEXT)) {
3045
- return AttachmentType.DOCUMENT;
3046
- }
3047
- return AttachmentType.OTHER;
3048
- };
3049
- const filterFilesByType = (files, type) => {
3050
- const types = Array.isArray(type) ? type : [type];
3051
- return files.filter((file) => {
3052
- const fileType = getAttachmentType(file);
3053
- return types.includes(fileType);
3054
- });
3055
- };
3056
- const getFileUrl = (file) => {
3057
- if (file.url) {
3058
- return file.url;
3059
- }
3060
- return URL.createObjectURL(file);
3061
- };
3062
- const getAudioFiles = (files) => {
3063
- return filterFilesByType(files, [AttachmentType.AUDIO]);
3064
- };
3065
- const getNonAudioFiles = (files) => {
3066
- return filterFilesByType(files, [
3067
- AttachmentType.IMAGE,
3068
- AttachmentType.PDF,
3069
- AttachmentType.DOCUMENT,
3070
- AttachmentType.OTHER
3071
- ]);
3072
- };
3073
-
3074
- function createStore(initial) {
3075
- const state = { ...initial };
3076
- const listeners = {};
3077
- const notify = (key, value) => {
3078
- const keyStr = String(key);
3079
- listeners[keyStr]?.forEach((l) => l(value));
3080
- };
3081
- const subscribe = (key, listener) => {
3082
- const keyStr = String(key);
3083
- if (!listeners[keyStr]) listeners[keyStr] = /* @__PURE__ */ new Set();
3084
- listeners[keyStr].add(listener);
3085
- listener(state[key]);
3086
- return () => {
3087
- listeners[keyStr].delete(listener);
3088
- };
3089
- };
3090
- const set = (key, value) => {
3091
- state[key] = value;
3092
- notify(key, value);
3166
+ const SelectMultipleField = ({ field, value, disabled, loading, options, onChange, drawerPlacement }) => {
3167
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
3168
+ const [searchValue, setSearchValue] = useState("");
3169
+ const searchInputRef = useRef(null);
3170
+ const selected = value || [];
3171
+ const placeholder = loading ? "Cargando..." : field.placeholder || "Seleccionar...";
3172
+ const filteredOptions = searchValue ? options.filter((opt) => opt.label.toLowerCase().includes(searchValue.toLowerCase())) : options;
3173
+ useEffect(() => {
3174
+ if (isDrawerOpen && searchInputRef.current) {
3175
+ setTimeout(() => searchInputRef.current?.focus(), 350);
3176
+ }
3177
+ }, [isDrawerOpen]);
3178
+ const toggleOption = (optValue) => {
3179
+ const isChecked = selected.includes(optValue);
3180
+ const next = isChecked ? selected.filter((v) => v !== optValue) : [...selected, optValue];
3181
+ const labels = next.map((v) => options.find((o) => o.value === v)?.label || v).join(", ");
3182
+ onChange(next, labels);
3093
3183
  };
3094
- const get = (key) => state[key];
3095
- return { set, get, subscribe };
3096
- }
3097
-
3098
- function deepMerge(target, source) {
3184
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3185
+ /* @__PURE__ */ jsxs(
3186
+ "div",
3187
+ {
3188
+ className: `px-chat-select-with-confirm__trigger ${isDrawerOpen ? "px-chat-select-with-confirm__trigger--open" : ""}`,
3189
+ onClick: () => !disabled && !loading && setIsDrawerOpen(true),
3190
+ role: "button",
3191
+ tabIndex: disabled ? -1 : 0,
3192
+ onKeyDown: (e) => {
3193
+ if (!disabled && (e.key === "Enter" || e.key === " ")) setIsDrawerOpen(true);
3194
+ },
3195
+ children: [
3196
+ selected.length === 0 ? /* @__PURE__ */ jsx("span", { className: "px-chat-select-with-confirm__trigger-text px-chat-select-with-confirm__trigger-text--placeholder", children: placeholder }) : /* @__PURE__ */ jsx("div", { className: "px-chat-select-with-confirm__trigger-tags", children: selected.map((v) => {
3197
+ const opt = options.find((o) => o.value === v);
3198
+ return /* @__PURE__ */ jsxs("span", { className: "px-chat-select-with-confirm__trigger-tag", children: [
3199
+ opt?.label || v,
3200
+ /* @__PURE__ */ jsx(
3201
+ "button",
3202
+ {
3203
+ type: "button",
3204
+ className: "px-chat-select-with-confirm__trigger-tag-remove",
3205
+ onClick: (e) => {
3206
+ e.stopPropagation();
3207
+ toggleOption(v);
3208
+ },
3209
+ "aria-label": `Quitar ${opt?.label || v}`,
3210
+ children: /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.CLOSE, size: "small" })
3211
+ }
3212
+ )
3213
+ ] }, v);
3214
+ }) }),
3215
+ /* @__PURE__ */ jsx("span", { className: "px-chat-select-with-confirm__chevron", children: loading ? /* @__PURE__ */ jsx(Loader$1, { size: "small" }) : /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.CHEVRON_DOWN, size: "small" }) })
3216
+ ]
3217
+ }
3218
+ ),
3219
+ /* @__PURE__ */ jsx(
3220
+ Drawer$1,
3221
+ {
3222
+ isOpen: isDrawerOpen,
3223
+ onClose: () => {
3224
+ setIsDrawerOpen(false);
3225
+ setSearchValue("");
3226
+ },
3227
+ title: field.label,
3228
+ placement: drawerPlacement,
3229
+ footer: /* @__PURE__ */ jsxs(
3230
+ "button",
3231
+ {
3232
+ type: "button",
3233
+ className: "px-chat-rf__btn px-chat-rf__btn--primary",
3234
+ style: { width: "100%" },
3235
+ onClick: () => {
3236
+ setIsDrawerOpen(false);
3237
+ setSearchValue("");
3238
+ },
3239
+ children: [
3240
+ "Listo",
3241
+ selected.length > 0 ? ` (${selected.length})` : ""
3242
+ ]
3243
+ }
3244
+ ),
3245
+ children: /* @__PURE__ */ jsxs("div", { className: "px-chat-select-drawer px-chat-rf-select-drawer", children: [
3246
+ /* @__PURE__ */ jsxs("div", { className: "px-chat-select-drawer__search", children: [
3247
+ /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.SEARCH, size: "small" }),
3248
+ /* @__PURE__ */ jsx(
3249
+ "input",
3250
+ {
3251
+ ref: searchInputRef,
3252
+ type: "text",
3253
+ className: "px-chat-select-drawer__search-input",
3254
+ value: searchValue,
3255
+ onChange: (e) => setSearchValue(e.target.value),
3256
+ placeholder: "Buscar..."
3257
+ }
3258
+ ),
3259
+ searchValue && /* @__PURE__ */ jsx("button", { type: "button", className: "px-chat-select-drawer__search-clear", onClick: () => setSearchValue(""), children: /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.CLOSE, size: "small" }) })
3260
+ ] }),
3261
+ /* @__PURE__ */ jsx("ul", { className: "px-chat-select-drawer__options", role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("li", { className: "px-chat-select-drawer__empty", children: "No hay opciones disponibles" }) : filteredOptions.map((opt) => {
3262
+ const isChecked = selected.includes(opt.value);
3263
+ return /* @__PURE__ */ jsxs(
3264
+ "li",
3265
+ {
3266
+ className: `px-chat-select-drawer__option ${isChecked ? "px-chat-select-drawer__option--selected" : ""}`,
3267
+ onClick: () => toggleOption(opt.value),
3268
+ role: "option",
3269
+ "aria-selected": isChecked,
3270
+ children: [
3271
+ /* @__PURE__ */ jsx("span", { className: `px-chat-select-drawer__checkbox ${isChecked ? "px-chat-select-drawer__checkbox--checked" : ""}`, children: isChecked && /* @__PURE__ */ jsx(Icon$1, { type: ICON_TYPES.CHECK, size: "small" }) }),
3272
+ /* @__PURE__ */ jsx("span", { className: "px-chat-select-drawer__option-label", children: opt.label })
3273
+ ]
3274
+ },
3275
+ opt.value
3276
+ );
3277
+ }) })
3278
+ ] })
3279
+ }
3280
+ )
3281
+ ] });
3282
+ };
3283
+ const DateField = ({ field, value, disabled, onChange, drawerPlacement }) => {
3284
+ const [isOpen, setIsOpen] = useState(false);
3285
+ const selectedDate = value ? parseDate$2(value) : null;
3286
+ const displayValue = formatDateDisplay(selectedDate);
3287
+ const placeholder = field.placeholder || "Selecciona una fecha";
3288
+ const minDateRaw = field.validation?.min_date ? String(field.validation.min_date.value ?? field.validation.min_date) : field.min_date ? String(field.min_date) : void 0;
3289
+ const maxDateRaw = field.validation?.max_date ? String(field.validation.max_date.value ?? field.validation.max_date) : field.max_date ? String(field.max_date) : void 0;
3290
+ const minDate = minDateRaw ? parseDate$2(minDateRaw) : void 0;
3291
+ const maxDate = maxDateRaw ? parseDate$2(maxDateRaw) : void 0;
3292
+ const handleDateChange = (date) => {
3293
+ if (!date) return;
3294
+ const isoValue = formatDateToISO(date);
3295
+ const display = formatDateDisplay(date);
3296
+ onChange(isoValue, display);
3297
+ };
3298
+ const calendarContent = /* @__PURE__ */ jsx(
3299
+ DatePicker,
3300
+ {
3301
+ selected: selectedDate,
3302
+ onChange: handleDateChange,
3303
+ inline: true,
3304
+ locale: "es",
3305
+ minDate: minDate || void 0,
3306
+ maxDate: maxDate || void 0,
3307
+ renderCustomHeader: ({ date, decreaseMonth, increaseMonth, prevMonthButtonDisabled, nextMonthButtonDisabled }) => /* @__PURE__ */ jsxs("div", { className: "px-chat-datepicker__header", children: [
3308
+ /* @__PURE__ */ jsx("button", { type: "button", className: "px-chat-datepicker__nav-btn", onClick: decreaseMonth, disabled: prevMonthButtonDisabled, children: "\u2039" }),
3309
+ /* @__PURE__ */ jsx("span", { className: "px-chat-datepicker__month-year", children: date.toLocaleDateString("es", { month: "long", year: "numeric" }) }),
3310
+ /* @__PURE__ */ jsx("button", { type: "button", className: "px-chat-datepicker__nav-btn", onClick: increaseMonth, disabled: nextMonthButtonDisabled, children: "\u203A" })
3311
+ ] })
3312
+ }
3313
+ );
3314
+ const calendarIcon = /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M5 1V3M11 1V3M1 6H15M2 2.5H14C14.5523 2.5 15 2.94772 15 3.5V14C15 14.5523 14.5523 15 14 15H2C1.44772 15 1 14.5523 1 14V3.5C1 2.94772 1.44772 2.5 2 2.5Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
3315
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3316
+ /* @__PURE__ */ jsxs(
3317
+ "div",
3318
+ {
3319
+ className: `px-chat-rf__date-trigger ${isOpen ? "px-chat-rf__date-trigger--open" : ""}`,
3320
+ onClick: () => !disabled && setIsOpen(!isOpen),
3321
+ role: "button",
3322
+ tabIndex: disabled ? -1 : 0,
3323
+ onKeyDown: (e) => {
3324
+ if (!disabled && (e.key === "Enter" || e.key === " ")) setIsOpen(!isOpen);
3325
+ },
3326
+ children: [
3327
+ /* @__PURE__ */ jsx("span", { className: `px-chat-rf__date-trigger-text ${!selectedDate ? "px-chat-rf__date-trigger-text--placeholder" : ""}`, children: selectedDate ? displayValue : placeholder }),
3328
+ /* @__PURE__ */ jsx("span", { className: "px-chat-rf__date-trigger-icon", children: calendarIcon })
3329
+ ]
3330
+ }
3331
+ ),
3332
+ /* @__PURE__ */ jsxs(
3333
+ Drawer$1,
3334
+ {
3335
+ isOpen,
3336
+ onClose: () => setIsOpen(false),
3337
+ title: field.label,
3338
+ placement: drawerPlacement,
3339
+ footer: /* @__PURE__ */ jsx(
3340
+ "button",
3341
+ {
3342
+ type: "button",
3343
+ className: "px-chat-rf__btn px-chat-rf__btn--primary",
3344
+ style: { width: "100%" },
3345
+ disabled: !selectedDate,
3346
+ onClick: () => setIsOpen(false),
3347
+ children: "Confirmar"
3348
+ }
3349
+ ),
3350
+ children: [
3351
+ /* @__PURE__ */ jsx("div", { className: "px-chat-datepicker px-chat-datepicker--mobile", children: calendarContent }),
3352
+ selectedDate && /* @__PURE__ */ jsx("div", { className: "px-chat-datepicker__selected-date", children: displayValue })
3353
+ ]
3354
+ }
3355
+ )
3356
+ ] });
3357
+ };
3358
+
3359
+ const checkIcon = /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M2.5 6L5 8.5L9.5 3.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
3360
+ const calendarIcon = /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
3361
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "3", width: "12", height: "11", rx: "1.5", stroke: "currentColor", strokeWidth: "1.2" }),
3362
+ /* @__PURE__ */ jsx("path", { d: "M2 6.5H14", stroke: "currentColor", strokeWidth: "1.2" }),
3363
+ /* @__PURE__ */ jsx("path", { d: "M5.5 1.5V4", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" }),
3364
+ /* @__PURE__ */ jsx("path", { d: "M10.5 1.5V4", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
3365
+ ] });
3366
+ const formIcon = /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
3367
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "1.5", width: "12", height: "13", rx: "1.5", stroke: "currentColor", strokeWidth: "1.2" }),
3368
+ /* @__PURE__ */ jsx("path", { d: "M5 5.5H11", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" }),
3369
+ /* @__PURE__ */ jsx("path", { d: "M5 8.5H11", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" }),
3370
+ /* @__PURE__ */ jsx("path", { d: "M5 11.5H8.5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
3371
+ ] });
3372
+ const chevronDown = /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M3 4.5L6 7.5L9 4.5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" }) });
3373
+ const chevronRight = /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M4.5 3L7.5 6L4.5 9", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" }) });
3374
+ const ReactiveFormView = ({ title, trigger, steps, fields, submit, summary, form, drawerPlacement = "bottom" }) => {
3375
+ const {
3376
+ formStatus,
3377
+ setFormStatus,
3378
+ currentStep,
3379
+ setCurrentStep,
3380
+ values,
3381
+ errors,
3382
+ touched,
3383
+ fieldStates,
3384
+ totalSteps,
3385
+ handleTriggerClick,
3386
+ handleFieldChange,
3387
+ handleNext,
3388
+ handleBack,
3389
+ handleSubmit,
3390
+ getDependencies,
3391
+ allDepsResolved,
3392
+ resolveSummaryRows
3393
+ } = form;
3394
+ const renderTrigger = () => {
3395
+ const isOpen = formStatus === "open";
3396
+ const isFinished = formStatus === "completed" || formStatus === "warning" || formStatus === "error";
3397
+ const statusClass = isFinished ? `px-chat-rf__trigger--${formStatus}` : "";
3398
+ return /* @__PURE__ */ jsxs(
3399
+ "button",
3400
+ {
3401
+ type: "button",
3402
+ className: `px-chat-rf__trigger ${isOpen ? "px-chat-rf__trigger--open" : ""} ${statusClass}`,
3403
+ onClick: handleTriggerClick,
3404
+ children: [
3405
+ /* @__PURE__ */ jsx("span", { className: "px-chat-rf__trigger-icon", children: isFinished ? checkIcon : trigger.icon === "calendar" ? calendarIcon : formIcon }),
3406
+ /* @__PURE__ */ jsx("span", { className: "px-chat-rf__trigger-label", children: isFinished ? form.submitMessage : trigger.label }),
3407
+ !isFinished && /* @__PURE__ */ jsx("span", { className: "px-chat-rf__trigger-arrow", children: isOpen ? chevronDown : chevronRight })
3408
+ ]
3409
+ }
3410
+ );
3411
+ };
3412
+ const renderStepIndicator = () => /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__steps-indicator", children: [
3413
+ steps.map((step, i) => {
3414
+ const isCompleted = i < currentStep;
3415
+ const isActive = i === currentStep;
3416
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
3417
+ i > 0 && /* @__PURE__ */ jsx("div", { className: `px-chat-rf__step-line ${isCompleted ? "px-chat-rf__step-line--done" : ""}` }),
3418
+ /* @__PURE__ */ jsx(
3419
+ "button",
3420
+ {
3421
+ type: "button",
3422
+ className: `px-chat-rf__step-dot ${isActive ? "px-chat-rf__step-dot--active" : ""} ${isCompleted ? "px-chat-rf__step-dot--done" : ""}`,
3423
+ onClick: () => isCompleted && setCurrentStep(i),
3424
+ disabled: !isCompleted && !isActive,
3425
+ title: step.title,
3426
+ children: isCompleted ? checkIcon : i + 1
3427
+ }
3428
+ )
3429
+ ] }, i);
3430
+ }),
3431
+ /* @__PURE__ */ jsx("div", { className: `px-chat-rf__step-line ${currentStep >= steps.length ? "px-chat-rf__step-line--done" : ""}` }),
3432
+ /* @__PURE__ */ jsx(
3433
+ "button",
3434
+ {
3435
+ type: "button",
3436
+ className: `px-chat-rf__step-dot ${currentStep >= steps.length ? "px-chat-rf__step-dot--active" : ""}`,
3437
+ disabled: currentStep < steps.length,
3438
+ children: currentStep >= steps.length ? checkIcon : totalSteps
3439
+ }
3440
+ )
3441
+ ] });
3442
+ const renderNavButtons = () => /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__nav", children: [
3443
+ currentStep > 0 && /* @__PURE__ */ jsx("button", { type: "button", className: "px-chat-rf__btn px-chat-rf__btn--secondary", onClick: handleBack, children: "Atras" }),
3444
+ /* @__PURE__ */ jsx("button", { type: "button", className: "px-chat-rf__btn px-chat-rf__btn--primary", onClick: handleNext, children: "Siguiente" })
3445
+ ] });
3446
+ const renderSummaryActions = () => {
3447
+ const actions = summary.actions;
3448
+ if (!actions || actions.length === 0) {
3449
+ return /* @__PURE__ */ jsx("button", { type: "button", className: "px-chat-rf__btn px-chat-rf__btn--primary px-chat-rf__btn--full", onClick: handleSubmit, children: submit.label });
3450
+ }
3451
+ const actionHandlers = {
3452
+ submit: handleSubmit,
3453
+ close: () => setFormStatus("closed"),
3454
+ back: handleBack
3455
+ };
3456
+ return /* @__PURE__ */ jsx("div", { className: "px-chat-rf__nav", children: actions.map((act, i) => /* @__PURE__ */ jsx(
3457
+ "button",
3458
+ {
3459
+ type: "button",
3460
+ className: `px-chat-rf__btn px-chat-rf__btn--${act.variant || "primary"}`,
3461
+ onClick: actionHandlers[act.action] || (() => {
3462
+ }),
3463
+ children: act.label
3464
+ },
3465
+ i
3466
+ )) });
3467
+ };
3468
+ const renderStepContent = () => {
3469
+ if (currentStep >= steps.length) {
3470
+ const resolvedRows = resolveSummaryRows(summary.rows);
3471
+ return /* @__PURE__ */ jsx("div", { className: "px-chat-rf__summary", children: /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__summary-card", children: [
3472
+ /* @__PURE__ */ jsx("div", { className: "px-chat-rf__summary-title", children: summary.title }),
3473
+ resolvedRows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__summary-row", children: [
3474
+ /* @__PURE__ */ jsx("span", { className: "px-chat-rf__summary-label", children: row.label }),
3475
+ /* @__PURE__ */ jsx("span", { className: "px-chat-rf__summary-value", children: row.value })
3476
+ ] }, i))
3477
+ ] }) });
3478
+ }
3479
+ const step = steps[currentStep];
3480
+ const stepFields = step.fields.map((name) => fields.find((f) => f.name === name)).filter(Boolean);
3481
+ return /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__step-content", children: [
3482
+ currentStep > 0 && /* @__PURE__ */ jsx("div", { className: "px-chat-rf__completed-steps", children: steps.slice(0, currentStep).map((prevStep, si) => /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__completed-step", children: [
3483
+ /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__completed-step-header", children: [
3484
+ /* @__PURE__ */ jsx("span", { className: "px-chat-rf__completed-step-title", children: prevStep.title }),
3485
+ /* @__PURE__ */ jsx(
3486
+ "button",
3487
+ {
3488
+ type: "button",
3489
+ className: "px-chat-rf__edit-btn",
3490
+ onClick: () => setCurrentStep(si),
3491
+ children: "editar"
3492
+ }
3493
+ )
3494
+ ] }),
3495
+ prevStep.fields.map((fname) => {
3496
+ const fs = fieldStates[fname];
3497
+ const fld = fields.find((f) => f.name === fname);
3498
+ return /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__completed-field", children: [
3499
+ /* @__PURE__ */ jsxs("span", { className: "px-chat-rf__completed-field-label", children: [
3500
+ fld?.label,
3501
+ ":"
3502
+ ] }),
3503
+ /* @__PURE__ */ jsx("span", { className: "px-chat-rf__completed-field-value", children: fs?.label || String(values[fname] || "") })
3504
+ ] }, fname);
3505
+ })
3506
+ ] }, si)) }),
3507
+ /* @__PURE__ */ jsxs("div", { className: "px-chat-rf__active-step", children: [
3508
+ /* @__PURE__ */ jsx("div", { className: "px-chat-rf__step-title", children: step.title }),
3509
+ stepFields.map((field) => {
3510
+ const deps = getDependencies(field);
3511
+ const isDisabled = !allDepsResolved(deps, values);
3512
+ return /* @__PURE__ */ jsx(
3513
+ DynamicField,
3514
+ {
3515
+ field,
3516
+ value: values[field.name],
3517
+ error: touched[field.name] ? errors[field.name] : void 0,
3518
+ disabled: isDisabled,
3519
+ fieldState: fieldStates[field.name],
3520
+ drawerPlacement,
3521
+ onChange: (val, label, extra) => handleFieldChange(field.name, val, label, extra)
3522
+ },
3523
+ field.name
3524
+ );
3525
+ })
3526
+ ] })
3527
+ ] });
3528
+ };
3529
+ const renderDrawerFooter = () => {
3530
+ if (currentStep >= steps.length) return renderSummaryActions();
3531
+ return renderNavButtons();
3532
+ };
3533
+ return /* @__PURE__ */ jsxs("div", { className: "px-chat-rf", children: [
3534
+ renderTrigger(),
3535
+ /* @__PURE__ */ jsxs(
3536
+ Drawer$1,
3537
+ {
3538
+ isOpen: formStatus === "open",
3539
+ onClose: () => setFormStatus("closed"),
3540
+ title,
3541
+ placement: drawerPlacement,
3542
+ className: "px-chat-rf-drawer--mobile",
3543
+ footer: renderDrawerFooter(),
3544
+ children: [
3545
+ renderStepIndicator(),
3546
+ renderStepContent()
3547
+ ]
3548
+ }
3549
+ )
3550
+ ] });
3551
+ };
3552
+
3553
+ function buildYupSchema(fields) {
3554
+ const shape = {};
3555
+ for (const field of fields) {
3556
+ if (field.type === "hidden") continue;
3557
+ const v = field.validation;
3558
+ if (!v) continue;
3559
+ if (field.type === "select_multiple") {
3560
+ let s = yup.array().of(yup.string());
3561
+ if (v.required) s = s.min(1, v.required);
3562
+ if (v.min) s = s.min(Number(v.min.value), v.min.message);
3563
+ if (v.max) s = s.max(Number(v.max.value), v.max.message);
3564
+ shape[field.name] = s;
3565
+ } else if (field.type === "date") {
3566
+ let s = yup.string().typeError(`${field.label || field.name}: fecha inv\xE1lida`);
3567
+ if (v.required) s = s.required(v.required);
3568
+ const minDateRule = v.min_date ?? field.min_date;
3569
+ if (minDateRule) {
3570
+ const minVal = typeof minDateRule === "object" && minDateRule !== null ? String(minDateRule.value) : String(minDateRule);
3571
+ const minMsg = typeof minDateRule === "object" && minDateRule !== null ? minDateRule.message || `La fecha debe ser ${minVal} o posterior` : `La fecha debe ser ${minVal} o posterior`;
3572
+ s = s.test("min-date", minMsg, (val) => !val || val >= minVal);
3573
+ }
3574
+ const maxDateRule = v.max_date ?? field.max_date;
3575
+ if (maxDateRule) {
3576
+ const maxVal = typeof maxDateRule === "object" && maxDateRule !== null ? String(maxDateRule.value) : String(maxDateRule);
3577
+ const maxMsg = typeof maxDateRule === "object" && maxDateRule !== null ? maxDateRule.message || `La fecha debe ser ${maxVal} o anterior` : `La fecha debe ser ${maxVal} o anterior`;
3578
+ s = s.test("max-date", maxMsg, (val) => !val || val <= maxVal);
3579
+ }
3580
+ shape[field.name] = s;
3581
+ } else {
3582
+ let s = yup.string();
3583
+ if (v.required) s = s.required(v.required);
3584
+ if (v.pattern) s = s.matches(new RegExp(v.pattern.value), v.pattern.message);
3585
+ if (v.email) s = s.email(v.email);
3586
+ if (v.min) s = s.min(Number(v.min.value), v.min.message);
3587
+ if (v.max) s = s.max(Number(v.max.value), v.max.message);
3588
+ shape[field.name] = s;
3589
+ }
3590
+ }
3591
+ return yup.object().shape(shape);
3592
+ }
3593
+ function buildInitialValues(fields) {
3594
+ const values = {};
3595
+ for (const field of fields) {
3596
+ if (field.type === "hidden") {
3597
+ values[field.name] = field.default_value ?? "";
3598
+ } else {
3599
+ values[field.name] = field.type === "select_multiple" ? [] : "";
3600
+ }
3601
+ }
3602
+ return values;
3603
+ }
3604
+
3605
+ function resolveVariable(template, formValues, fieldStates) {
3606
+ if (!template.startsWith("$")) return template;
3607
+ const withoutDollar = template.slice(1);
3608
+ const dotIndex = withoutDollar.indexOf(".");
3609
+ const fieldName = dotIndex >= 0 ? withoutDollar.slice(0, dotIndex) : withoutDollar;
3610
+ const prop = dotIndex >= 0 ? withoutDollar.slice(dotIndex + 1) : null;
3611
+ const value = formValues[fieldName];
3612
+ const state = fieldStates[fieldName];
3613
+ if (!prop) return value;
3614
+ if (prop === "label" && state) {
3615
+ return state.label || "";
3616
+ }
3617
+ if (prop === "labels" && state && Array.isArray(value)) {
3618
+ return value.map((v) => {
3619
+ const opt = state.options.find((o) => o.value === v);
3620
+ return opt?.label || v;
3621
+ }).join(", ");
3622
+ }
3623
+ if (state) {
3624
+ const selectedOpt = state.options.find((o) => o.value === value);
3625
+ if (selectedOpt && prop in selectedOpt) {
3626
+ return selectedOpt[prop];
3627
+ }
3628
+ }
3629
+ return "";
3630
+ }
3631
+ function resolveBody(obj, formValues, fieldStates) {
3632
+ if (typeof obj === "string") return resolveVariable(obj, formValues, fieldStates);
3633
+ if (Array.isArray(obj)) return obj.map((item) => resolveBody(item, formValues, fieldStates));
3634
+ if (obj !== null && typeof obj === "object") {
3635
+ const resolved = {};
3636
+ for (const [key, value] of Object.entries(obj)) {
3637
+ resolved[key] = resolveBody(value, formValues, fieldStates);
3638
+ }
3639
+ return resolved;
3640
+ }
3641
+ return obj;
3642
+ }
3643
+ function resolveParams(params, formValues, fieldStates) {
3644
+ const resolved = {};
3645
+ for (const [key, template] of Object.entries(params)) {
3646
+ resolved[key] = resolveVariable(template, formValues, fieldStates);
3647
+ }
3648
+ return resolved;
3649
+ }
3650
+ function resolveSummaryRows(rows, formValues, fieldStates) {
3651
+ return rows.map((row) => ({
3652
+ label: row.label,
3653
+ value: String(resolveVariable(row.value, formValues, fieldStates) ?? "")
3654
+ }));
3655
+ }
3656
+
3657
+ const FETCH_TIMEOUT_MS = 12e4;
3658
+ function fetchViaEventBus(eventBus, service, url, method, body) {
3659
+ const requestId = crypto.randomUUID();
3660
+ return new Promise((resolve, reject) => {
3661
+ const timeoutId = setTimeout(() => {
3662
+ unsubscribe();
3663
+ reject(new Error(`Timeout: no response for ${url} after ${FETCH_TIMEOUT_MS}ms`));
3664
+ }, FETCH_TIMEOUT_MS);
3665
+ const unsubscribe = eventBus.on(CHAT_EVENT.FETCH_RESPONSE, (response) => {
3666
+ if (response.requestId !== requestId) return;
3667
+ clearTimeout(timeoutId);
3668
+ unsubscribe();
3669
+ if (response.httpError) {
3670
+ reject(new Error(response.httpError));
3671
+ } else {
3672
+ resolve(response.data);
3673
+ }
3674
+ });
3675
+ eventBus.emit(CHAT_EVENT.FETCH_REQUEST, {
3676
+ requestId,
3677
+ service,
3678
+ url,
3679
+ method,
3680
+ ...body ? { body } : {}
3681
+ });
3682
+ });
3683
+ }
3684
+
3685
+ function formatTime$1(value, timezone) {
3686
+ try {
3687
+ const d = new Date(value);
3688
+ if (isNaN(d.getTime())) return value;
3689
+ return d.toLocaleTimeString([], {
3690
+ hour: "2-digit",
3691
+ minute: "2-digit",
3692
+ hour12: false,
3693
+ ...timezone ? { timeZone: timezone } : {}
3694
+ });
3695
+ } catch {
3696
+ return value;
3697
+ }
3698
+ }
3699
+ function formatDate$3(value, timezone) {
3700
+ try {
3701
+ const d = new Date(value);
3702
+ if (isNaN(d.getTime())) return value;
3703
+ return d.toLocaleDateString("sv-SE", {
3704
+ year: "numeric",
3705
+ month: "2-digit",
3706
+ day: "2-digit",
3707
+ ...timezone ? { timeZone: timezone } : {}
3708
+ });
3709
+ } catch {
3710
+ return value;
3711
+ }
3712
+ }
3713
+ async function mockFetch(url, params) {
3714
+ await new Promise((r) => setTimeout(r, 600 + Math.random() * 400));
3715
+ if (url.includes("companies")) {
3716
+ return [
3717
+ { id: "company-1", name: "Goluti" },
3718
+ { id: "company-2", name: "Barbeer" }
3719
+ ];
3720
+ }
3721
+ if (url.includes("locations")) {
3722
+ if (params.company_id === "company-1") {
3723
+ return [
3724
+ { id: "loc-1", name: "Sede Chico" },
3725
+ { id: "loc-2", name: "Sede Suba" }
3726
+ ];
3727
+ }
3728
+ return [{ id: "loc-3", name: "Sede Norte" }];
3729
+ }
3730
+ if (url.includes("services")) {
3731
+ return [
3732
+ { id: "svc-1", name: "Corte de cabello" },
3733
+ { id: "svc-2", name: "Manicure" },
3734
+ { id: "svc-3", name: "Tinte completo" }
3735
+ ];
3736
+ }
3737
+ if (url.includes("availability")) {
3738
+ return [
3739
+ {
3740
+ collaborator_id: "collab-1",
3741
+ user_location_rol_id: "ulr-1",
3742
+ name: "Leon",
3743
+ assignment_hours: [
3744
+ { start: "2026-03-02T14:00:00", end: "2026-03-02T14:20:00", start_time: "14:00", end_time: "14:20" },
3745
+ { start: "2026-03-02T14:30:00", end: "2026-03-02T14:50:00", start_time: "14:30", end_time: "14:50" }
3746
+ ]
3747
+ },
3748
+ {
3749
+ collaborator_id: "collab-2",
3750
+ user_location_rol_id: "ulr-2",
3751
+ name: "Carlos",
3752
+ assignment_hours: [
3753
+ { start: "2026-03-02T10:00:00", end: "2026-03-02T10:20:00", start_time: "10:00", end_time: "10:20" },
3754
+ { start: "2026-03-02T11:00:00", end: "2026-03-02T11:20:00", start_time: "11:00", end_time: "11:20" }
3755
+ ]
3756
+ }
3757
+ ];
3758
+ }
3759
+ return [];
3760
+ }
3761
+ function getDependencies(field) {
3762
+ if (!field.depends_on) return [];
3763
+ return Array.isArray(field.depends_on) ? field.depends_on : [field.depends_on];
3764
+ }
3765
+ function allDepsResolved(deps, formValues) {
3766
+ return deps.every((dep) => {
3767
+ const val = formValues[dep];
3768
+ if (Array.isArray(val)) return val.length > 0;
3769
+ return val !== "" && val !== null && val !== void 0;
3770
+ });
3771
+ }
3772
+ function useReactiveEndpoints({ fields, fieldStates, setFieldState, eventBus, timezone, formTitle }) {
3773
+ const loadingRef = useRef(/* @__PURE__ */ new Set());
3774
+ const loadEndpoint = useCallback(
3775
+ async (field, formValues) => {
3776
+ if (!field.endpoint || loadingRef.current.has(field.name)) return;
3777
+ const deps = getDependencies(field);
3778
+ if (!allDepsResolved(deps, formValues)) return;
3779
+ loadingRef.current.add(field.name);
3780
+ setFieldState(field.name, { loading: true, error: null });
3781
+ const startTime = Date.now();
3782
+ try {
3783
+ const resolvedBody = field.endpoint.body ? resolveBody(field.endpoint.body, formValues, fieldStates) : void 0;
3784
+ const params = field.endpoint.params ? resolveParams(field.endpoint.params, formValues, fieldStates) : {};
3785
+ const requestBody = resolvedBody ?? (Object.keys(params).length > 0 ? params : void 0);
3786
+ if (eventBus) {
3787
+ eventBus.emit(CHAT_EVENT.FORM_TRACE, {
3788
+ chatId: "",
3789
+ formTitle: formTitle || "",
3790
+ source: "reactive_form",
3791
+ phase: "request",
3792
+ service: field.endpoint.service,
3793
+ url: field.endpoint.url,
3794
+ method: field.endpoint.method,
3795
+ body: requestBody
3796
+ });
3797
+ }
3798
+ let rawData;
3799
+ if (eventBus) {
3800
+ rawData = await fetchViaEventBus(
3801
+ eventBus,
3802
+ field.endpoint.service,
3803
+ field.endpoint.url,
3804
+ field.endpoint.method,
3805
+ requestBody
3806
+ );
3807
+ } else {
3808
+ rawData = await mockFetch(field.endpoint.url, params);
3809
+ }
3810
+ let dataArray;
3811
+ let data = rawData;
3812
+ if (rawData && typeof rawData === "object" && "response" in rawData) {
3813
+ data = rawData.response;
3814
+ }
3815
+ if (field.endpoint.response_path && data && typeof data === "object" && !Array.isArray(data)) {
3816
+ const extracted = data[field.endpoint.response_path];
3817
+ dataArray = Array.isArray(extracted) ? extracted : [];
3818
+ } else {
3819
+ dataArray = Array.isArray(data) ? data : [];
3820
+ }
3821
+ if (eventBus && rawData && typeof rawData === "object") {
3822
+ const resp = rawData;
3823
+ if (resp.notification_type && String(resp.notification_type).toLowerCase() !== "success") {
3824
+ throw new Error(resp.message || "Error en la respuesta");
3825
+ }
3826
+ }
3827
+ const options = dataArray.map((item) => {
3828
+ const opt = {
3829
+ value: String(item[field.endpoint.value_field] || ""),
3830
+ label: String(item[field.endpoint.label_field] || "")
3831
+ };
3832
+ if (field.endpoint.extra_fields) {
3833
+ for (const ef of field.endpoint.extra_fields) {
3834
+ opt[ef] = item[ef];
3835
+ }
3836
+ }
3837
+ return opt;
3838
+ });
3839
+ setFieldState(field.name, { options, loading: false });
3840
+ if (eventBus) {
3841
+ eventBus.emit(CHAT_EVENT.FORM_TRACE, {
3842
+ chatId: "",
3843
+ formTitle: formTitle || "",
3844
+ source: "reactive_form",
3845
+ phase: "response",
3846
+ service: field.endpoint.service,
3847
+ url: field.endpoint.url,
3848
+ method: field.endpoint.method,
3849
+ status: 200,
3850
+ duration_ms: Date.now() - startTime,
3851
+ success: true,
3852
+ response: rawData
3853
+ });
3854
+ }
3855
+ } catch (err) {
3856
+ const errorMsg = err instanceof Error ? err.message : "Error al cargar opciones";
3857
+ setFieldState(field.name, { loading: false, error: errorMsg });
3858
+ if (eventBus) {
3859
+ eventBus.emit(CHAT_EVENT.FORM_TRACE, {
3860
+ chatId: "",
3861
+ formTitle: formTitle || "",
3862
+ source: "reactive_form",
3863
+ phase: "response",
3864
+ service: field.endpoint.service,
3865
+ url: field.endpoint.url,
3866
+ method: field.endpoint.method,
3867
+ status: 500,
3868
+ duration_ms: Date.now() - startTime,
3869
+ success: false,
3870
+ error: errorMsg
3871
+ });
3872
+ }
3873
+ } finally {
3874
+ loadingRef.current.delete(field.name);
3875
+ }
3876
+ },
3877
+ [fields, fieldStates, setFieldState, eventBus]
3878
+ );
3879
+ const resolveOptionsFrom = useCallback(
3880
+ (field, formValues) => {
3881
+ if (!field.options_from) return;
3882
+ const sourceState = fieldStates[field.options_from.source_field];
3883
+ const sourceValue = formValues[field.options_from.source_field];
3884
+ if (!sourceState || !sourceValue) return;
3885
+ const selectedItem = sourceState.options.find((o) => o.value === sourceValue);
3886
+ if (!selectedItem) return;
3887
+ const rawData = selectedItem[field.options_from.data_field];
3888
+ if (!Array.isArray(rawData)) return;
3889
+ const options = rawData.map((item) => {
3890
+ let val = field.options_from.value_template;
3891
+ let lbl = field.options_from.label_template;
3892
+ for (const [k, v] of Object.entries(item)) {
3893
+ const strVal = String(v);
3894
+ const timeStr = formatTime$1(strVal, timezone);
3895
+ const dateStr = formatDate$3(strVal, timezone);
3896
+ val = val.replace(`\${${k}|time}`, timeStr);
3897
+ val = val.replace(`\${${k}|date}`, dateStr);
3898
+ val = val.replace(`\${${k}_time}`, timeStr);
3899
+ val = val.replace(`\${${k}_date}`, dateStr);
3900
+ val = val.replace(`\${${k}}`, strVal);
3901
+ lbl = lbl.replace(`\${${k}|time}`, timeStr);
3902
+ lbl = lbl.replace(`\${${k}|date}`, dateStr);
3903
+ lbl = lbl.replace(`\${${k}_time}`, timeStr);
3904
+ lbl = lbl.replace(`\${${k}_date}`, dateStr);
3905
+ lbl = lbl.replace(`\${${k}}`, strVal);
3906
+ }
3907
+ return { value: val, label: lbl, ...item };
3908
+ });
3909
+ setFieldState(field.name, { options, loading: false });
3910
+ },
3911
+ [fieldStates, setFieldState]
3912
+ );
3913
+ return { loadEndpoint, resolveOptionsFrom, getDependencies, allDepsResolved, fetchViaEventBus: eventBus ? fetchViaEventBus.bind(null, eventBus) : void 0 };
3914
+ }
3915
+
3916
+ function createInitialFieldStates(fields) {
3917
+ const map = {};
3918
+ for (const f of fields) {
3919
+ map[f.name] = {
3920
+ value: f.type === "hidden" ? f.default_value ?? "" : f.type === "select_multiple" ? [] : "",
3921
+ label: "",
3922
+ options: f.options || [],
3923
+ loading: false,
3924
+ error: null
3925
+ };
3926
+ }
3927
+ return map;
3928
+ }
3929
+ function useReactiveForm(props) {
3930
+ const { fields, steps, submit, eventBus } = props;
3931
+ const { timezone } = useChatConfig();
3932
+ const [formStatus, setFormStatus] = useState("closed");
3933
+ const [currentStep, setCurrentStep] = useState(0);
3934
+ const [values, setValues] = useState(() => buildInitialValues(fields));
3935
+ const [errors, setErrors] = useState({});
3936
+ const [touched, setTouched] = useState({});
3937
+ const [fieldStates, setFieldStatesMap] = useState(
3938
+ () => createInitialFieldStates(fields)
3939
+ );
3940
+ const validationSchema = useMemo(() => buildYupSchema(fields), [fields]);
3941
+ const totalSteps = steps.length + 1;
3942
+ const setFieldState = useCallback((name, partial) => {
3943
+ setFieldStatesMap((prev) => ({
3944
+ ...prev,
3945
+ [name]: { ...prev[name], ...partial }
3946
+ }));
3947
+ }, []);
3948
+ const { loadEndpoint, resolveOptionsFrom, getDependencies, allDepsResolved } = useReactiveEndpoints({ fields, fieldStates, setFieldState, eventBus, timezone, formTitle: props.title });
3949
+ const handleTriggerClick = () => {
3950
+ if (formStatus === "completed") return;
3951
+ setFormStatus(formStatus === "open" ? "closed" : "open");
3952
+ };
3953
+ const setFieldValue = useCallback((name, value) => {
3954
+ setValues((prev) => ({ ...prev, [name]: value }));
3955
+ }, []);
3956
+ const handleFieldChange = useCallback(
3957
+ (fieldName, value, label, extraData) => {
3958
+ setFieldValue(fieldName, value);
3959
+ setFieldState(fieldName, { value, label, extraData });
3960
+ setErrors((prev) => {
3961
+ const next = { ...prev };
3962
+ delete next[fieldName];
3963
+ return next;
3964
+ });
3965
+ for (const f of fields) {
3966
+ const deps = getDependencies(f);
3967
+ if (deps.includes(fieldName)) {
3968
+ const resetVal = f.type === "select_multiple" ? [] : "";
3969
+ setFieldValue(f.name, resetVal);
3970
+ setFieldState(f.name, { value: resetVal, label: "", options: [], extraData: void 0 });
3971
+ }
3972
+ }
3973
+ setValues((currentValues) => {
3974
+ const nextValues = { ...currentValues, [fieldName]: value };
3975
+ for (const f of fields) {
3976
+ const deps = getDependencies(f);
3977
+ if (deps.includes(fieldName) && allDepsResolved(deps, nextValues)) {
3978
+ if (f.endpoint) {
3979
+ loadEndpoint(f, nextValues);
3980
+ } else if (f.options_from) {
3981
+ setTimeout(() => resolveOptionsFrom(f, nextValues), 0);
3982
+ }
3983
+ }
3984
+ }
3985
+ return nextValues;
3986
+ });
3987
+ },
3988
+ [fields, getDependencies, allDepsResolved, loadEndpoint, resolveOptionsFrom, setFieldState, setFieldValue]
3989
+ );
3990
+ useEffect(() => {
3991
+ if (formStatus !== "open") return;
3992
+ const initialValues = buildInitialValues(fields);
3993
+ for (const f of fields) {
3994
+ if (!f.endpoint || fieldStates[f.name]?.options.length > 0) continue;
3995
+ const deps = getDependencies(f);
3996
+ if (deps.length === 0 || allDepsResolved(deps, initialValues)) {
3997
+ loadEndpoint(f, initialValues);
3998
+ }
3999
+ }
4000
+ }, [formStatus]);
4001
+ useEffect(() => {
4002
+ if (formStatus !== "open" || currentStep >= steps.length) return;
4003
+ const stepFieldNames = steps[currentStep].fields;
4004
+ setValues((currentValues) => {
4005
+ for (const f of fields) {
4006
+ if (!stepFieldNames.includes(f.name)) continue;
4007
+ if (!f.endpoint && !f.options_from) continue;
4008
+ if (fieldStates[f.name]?.options.length > 0) continue;
4009
+ if (fieldStates[f.name]?.loading) continue;
4010
+ const deps = getDependencies(f);
4011
+ if (allDepsResolved(deps, currentValues)) {
4012
+ if (f.endpoint) {
4013
+ loadEndpoint(f, currentValues);
4014
+ } else if (f.options_from) {
4015
+ resolveOptionsFrom(f, currentValues);
4016
+ }
4017
+ }
4018
+ }
4019
+ return currentValues;
4020
+ });
4021
+ }, [currentStep, formStatus]);
4022
+ const validateFields = async (fieldNames) => {
4023
+ const fieldErrors = {};
4024
+ try {
4025
+ await validationSchema.validate(values, { abortEarly: false });
4026
+ } catch (err) {
4027
+ if (err && typeof err === "object" && "inner" in err) {
4028
+ const yupErr = err;
4029
+ for (const e of yupErr.inner) {
4030
+ if (e.path && fieldNames.includes(e.path)) {
4031
+ fieldErrors[e.path] = e.message;
4032
+ }
4033
+ }
4034
+ }
4035
+ }
4036
+ return fieldErrors;
4037
+ };
4038
+ const validateStep = async (stepIndex) => {
4039
+ if (stepIndex >= steps.length) return true;
4040
+ const stepFieldNames = steps[stepIndex].fields;
4041
+ const stepErrors = await validateFields(stepFieldNames);
4042
+ setErrors((prev) => ({ ...prev, ...stepErrors }));
4043
+ const touchMap = {};
4044
+ for (const name of stepFieldNames) touchMap[name] = true;
4045
+ setTouched((prev) => ({ ...prev, ...touchMap }));
4046
+ return Object.keys(stepErrors).length === 0;
4047
+ };
4048
+ const handleNext = async () => {
4049
+ const valid = await validateStep(currentStep);
4050
+ if (valid) setCurrentStep((s) => s + 1);
4051
+ };
4052
+ const handleBack = () => setCurrentStep((s) => s - 1);
4053
+ const [submitMessage, setSubmitMessage] = useState("");
4054
+ const handleSubmit = async () => {
4055
+ const resolvedPayload = resolveBody(submit.payload_map, values, fieldStates);
4056
+ if (eventBus) {
4057
+ try {
4058
+ const data = await fetchViaEventBus(
4059
+ eventBus,
4060
+ submit.service,
4061
+ submit.url,
4062
+ submit.method,
4063
+ resolvedPayload
4064
+ );
4065
+ const resp = data;
4066
+ const notificationType = String(resp?.notification_type ?? "SUCCESS").toUpperCase();
4067
+ const message = String(resp?.message ?? "");
4068
+ const formLabels = {};
4069
+ for (const [name, state] of Object.entries(fieldStates)) {
4070
+ if (state.label) formLabels[name] = state.label;
4071
+ }
4072
+ eventBus.emit(CHAT_EVENT.FORM_SUBMIT, {
4073
+ formType: "reactive_form",
4074
+ submitUrl: submit.url,
4075
+ result: data,
4076
+ formValues: values,
4077
+ formLabels
4078
+ });
4079
+ if (notificationType === "SUCCESS") {
4080
+ setSubmitMessage(message || "Completado");
4081
+ setFormStatus("completed");
4082
+ } else if (notificationType === "WARNING") {
4083
+ setSubmitMessage(message || "Advertencia");
4084
+ setFormStatus("warning");
4085
+ } else {
4086
+ setSubmitMessage(message || "Error al procesar");
4087
+ setFormStatus("error");
4088
+ }
4089
+ } catch (err) {
4090
+ const message = err instanceof Error ? err.message : "Error al enviar formulario";
4091
+ setSubmitMessage(message);
4092
+ setFormStatus("error");
4093
+ }
4094
+ } else {
4095
+ console.log("[ReactiveForm] Submit:", values);
4096
+ console.log("[ReactiveForm] Payload map:", resolvedPayload);
4097
+ setFormStatus("completed");
4098
+ }
4099
+ };
4100
+ const resolveRows = (rows) => resolveSummaryRows(rows, values, fieldStates);
4101
+ return {
4102
+ formStatus,
4103
+ setFormStatus,
4104
+ submitMessage,
4105
+ currentStep,
4106
+ setCurrentStep,
4107
+ values,
4108
+ errors,
4109
+ touched,
4110
+ fieldStates,
4111
+ validationSchema,
4112
+ totalSteps,
4113
+ handleTriggerClick,
4114
+ setFieldValue,
4115
+ handleFieldChange,
4116
+ validateFields,
4117
+ validateStep,
4118
+ handleNext,
4119
+ handleBack,
4120
+ handleSubmit,
4121
+ getDependencies,
4122
+ allDepsResolved,
4123
+ resolveSummaryRows: resolveRows
4124
+ };
4125
+ }
4126
+
4127
+ const MOBILE_BREAKPOINT = 640;
4128
+ const useIsMobile$1 = () => {
4129
+ const [isMobile, setIsMobile] = useState(
4130
+ typeof window !== "undefined" ? window.innerWidth < MOBILE_BREAKPOINT : false
4131
+ );
4132
+ useEffect(() => {
4133
+ const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
4134
+ const handler = (e) => setIsMobile(e.matches);
4135
+ mq.addEventListener("change", handler);
4136
+ return () => mq.removeEventListener("change", handler);
4137
+ }, []);
4138
+ return isMobile;
4139
+ };
4140
+ const ReactiveForm = ({ component, eventBus }) => {
4141
+ const props = component.props;
4142
+ const isMobile = useIsMobile$1();
4143
+ const form = useReactiveForm({ ...props, eventBus });
4144
+ if (component.answered && form.formStatus !== "completed" && form.formStatus !== "warning" && form.formStatus !== "error") {
4145
+ form.setFormStatus("completed");
4146
+ }
4147
+ return /* @__PURE__ */ jsx(
4148
+ ReactiveFormView,
4149
+ {
4150
+ ...props,
4151
+ form,
4152
+ drawerPlacement: isMobile ? "bottom" : "right"
4153
+ }
4154
+ );
4155
+ };
4156
+
4157
+ function useStoreState(store, key) {
4158
+ const [value, setValue] = useState(() => store.get(key));
4159
+ useEffect(() => {
4160
+ return store.subscribe(key, setValue);
4161
+ }, [store, key]);
4162
+ return value;
4163
+ }
4164
+
4165
+ function createStore(initial) {
4166
+ const state = { ...initial };
4167
+ const listeners = {};
4168
+ const notify = (key, value) => {
4169
+ const keyStr = String(key);
4170
+ listeners[keyStr]?.forEach((l) => l(value));
4171
+ };
4172
+ const subscribe = (key, listener) => {
4173
+ const keyStr = String(key);
4174
+ if (!listeners[keyStr]) listeners[keyStr] = /* @__PURE__ */ new Set();
4175
+ listeners[keyStr].add(listener);
4176
+ listener(state[key]);
4177
+ return () => {
4178
+ listeners[keyStr].delete(listener);
4179
+ };
4180
+ };
4181
+ const set = (key, value) => {
4182
+ state[key] = value;
4183
+ notify(key, value);
4184
+ };
4185
+ const get = (key) => state[key];
4186
+ return { set, get, subscribe };
4187
+ }
4188
+
4189
+ const CAROUSEL_STORE_KEYS = {
4190
+ ITEMS: "items",
4191
+ ORIGINAL_ITEMS: "originalItems",
4192
+ SEARCH_QUERY: "searchQuery",
4193
+ SEARCH_STATUS: "searchStatus",
4194
+ SELECTED_IDS: "selectedIds",
4195
+ CURRENT_PAGE: "currentPage",
4196
+ HAS_MORE: "hasMore"
4197
+ };
4198
+
4199
+ function createCarouselStore(initialItems) {
4200
+ return createStore({
4201
+ [CAROUSEL_STORE_KEYS.ITEMS]: initialItems,
4202
+ [CAROUSEL_STORE_KEYS.ORIGINAL_ITEMS]: initialItems,
4203
+ [CAROUSEL_STORE_KEYS.SEARCH_QUERY]: "",
4204
+ [CAROUSEL_STORE_KEYS.SEARCH_STATUS]: "idle",
4205
+ [CAROUSEL_STORE_KEYS.SELECTED_IDS]: [],
4206
+ [CAROUSEL_STORE_KEYS.CURRENT_PAGE]: 0,
4207
+ [CAROUSEL_STORE_KEYS.HAS_MORE]: false
4208
+ });
4209
+ }
4210
+
4211
+ function createCarouselActions(store) {
4212
+ return {
4213
+ items: {
4214
+ set: (items) => store.set(CAROUSEL_STORE_KEYS.ITEMS, items),
4215
+ remove: (id) => {
4216
+ const current = store.get(CAROUSEL_STORE_KEYS.ITEMS);
4217
+ if (current.length <= 1) return;
4218
+ store.set(CAROUSEL_STORE_KEYS.ITEMS, current.filter((i) => i.id !== id));
4219
+ },
4220
+ get: () => store.get(CAROUSEL_STORE_KEYS.ITEMS)
4221
+ },
4222
+ selection: {
4223
+ toggle: (id) => {
4224
+ const current = store.get(CAROUSEL_STORE_KEYS.SELECTED_IDS);
4225
+ const next = current.includes(id) ? current.filter((i) => i !== id) : [...current, id];
4226
+ store.set(CAROUSEL_STORE_KEYS.SELECTED_IDS, next);
4227
+ },
4228
+ clear: () => store.set(CAROUSEL_STORE_KEYS.SELECTED_IDS, []),
4229
+ get: () => store.get(CAROUSEL_STORE_KEYS.SELECTED_IDS)
4230
+ },
4231
+ search: {
4232
+ setQuery: (query) => store.set(CAROUSEL_STORE_KEYS.SEARCH_QUERY, query),
4233
+ setStatus: (status) => store.set(CAROUSEL_STORE_KEYS.SEARCH_STATUS, status),
4234
+ getQuery: () => store.get(CAROUSEL_STORE_KEYS.SEARCH_QUERY)
4235
+ },
4236
+ pagination: {
4237
+ setPage: (page) => store.set(CAROUSEL_STORE_KEYS.CURRENT_PAGE, page),
4238
+ setHasMore: (hasMore) => store.set(CAROUSEL_STORE_KEYS.HAS_MORE, hasMore),
4239
+ getPage: () => store.get(CAROUSEL_STORE_KEYS.CURRENT_PAGE)
4240
+ },
4241
+ getOriginalItems: () => store.get(CAROUSEL_STORE_KEYS.ORIGINAL_ITEMS)
4242
+ };
4243
+ }
4244
+
4245
+ const SIZE_PX = { small: 80, medium: 120, large: 180 };
4246
+ const GAP_PX = 8;
4247
+ function calcPageLimit(size, containerWidth) {
4248
+ const cardWidth = SIZE_PX[size];
4249
+ return Math.max(1, Math.floor(containerWidth / (cardWidth + GAP_PX)));
4250
+ }
4251
+ function resolveSize(size, itemCount) {
4252
+ if (size && size !== "auto") return size;
4253
+ if (itemCount <= 3) return "large";
4254
+ if (itemCount <= 6) return "medium";
4255
+ return "small";
4256
+ }
4257
+ function mapResponseToItems(data, endpoint) {
4258
+ let unwrapped = data;
4259
+ if (unwrapped && typeof unwrapped === "object" && "response" in unwrapped) {
4260
+ unwrapped = unwrapped.response;
4261
+ }
4262
+ if (endpoint.response_path && unwrapped && typeof unwrapped === "object" && !Array.isArray(unwrapped)) {
4263
+ unwrapped = unwrapped[endpoint.response_path];
4264
+ }
4265
+ const arr = Array.isArray(unwrapped) ? unwrapped : [];
4266
+ return arr.map((item) => {
4267
+ const metadata = {};
4268
+ if (endpoint.extra_fields) {
4269
+ for (const field of endpoint.extra_fields) {
4270
+ metadata[field] = item[field];
4271
+ }
4272
+ }
4273
+ return {
4274
+ id: String(item[endpoint.id_field] ?? ""),
4275
+ type: endpoint.item_type,
4276
+ title: endpoint.title_field ? String(item[endpoint.title_field] ?? "") : void 0,
4277
+ description: endpoint.description_field ? String(item[endpoint.description_field] ?? "") : void 0,
4278
+ src: endpoint.src_field ? String(item[endpoint.src_field] ?? "") : void 0,
4279
+ file_type: endpoint.file_type_field ? String(item[endpoint.file_type_field] ?? "") : void 0,
4280
+ status: "ready",
4281
+ metadata: Object.keys(metadata).length > 0 ? metadata : void 0
4282
+ };
4283
+ });
4284
+ }
4285
+
4286
+ const MOCK_NAMES = [
4287
+ "Alpha",
4288
+ "Beta",
4289
+ "Gamma",
4290
+ "Delta",
4291
+ "Epsilon",
4292
+ "Zeta",
4293
+ "Eta",
4294
+ "Theta",
4295
+ "Iota",
4296
+ "Kappa",
4297
+ "Lambda",
4298
+ "Mu",
4299
+ "Nu",
4300
+ "Xi",
4301
+ "Omicron",
4302
+ "Pi",
4303
+ "Rho",
4304
+ "Sigma",
4305
+ "Tau",
4306
+ "Upsilon",
4307
+ "Phi",
4308
+ "Chi",
4309
+ "Psi",
4310
+ "Omega",
4311
+ "Altair",
4312
+ "Vega",
4313
+ "Sirius",
4314
+ "Rigel",
4315
+ "Polaris",
4316
+ "Antares"
4317
+ ];
4318
+ const MOCK_ITEMS = MOCK_NAMES.map((name, i) => ({
4319
+ id: String(i + 1),
4320
+ name: `Empresa ${name}`,
4321
+ address: `Calle ${i + 1} #${(i + 1) * 10}-${(i + 1) * 5}`,
4322
+ logo_url: `https://picsum.photos/seed/${name.toLowerCase()}/200`
4323
+ }));
4324
+ async function mockSearchFetch(query, skip, limit) {
4325
+ await new Promise((r) => setTimeout(r, 400 + Math.random() * 300));
4326
+ let filtered = MOCK_ITEMS;
4327
+ if (query) {
4328
+ filtered = MOCK_ITEMS.filter((i) => i.name.toLowerCase().includes(query.toLowerCase()));
4329
+ }
4330
+ return filtered.slice(skip, skip + limit);
4331
+ }
4332
+ function useCarouselSearch({ actions, endpoint, eventBus, pageLimit }) {
4333
+ const loadingRef = useRef(false);
4334
+ const search = useCallback(
4335
+ async (query, page = 0) => {
4336
+ if (loadingRef.current) return;
4337
+ loadingRef.current = true;
4338
+ actions.search.setQuery(query);
4339
+ if (page === 0) {
4340
+ actions.search.setStatus("loading");
4341
+ }
4342
+ const limit = endpoint?.limit ?? pageLimit;
4343
+ const skip = page * limit;
4344
+ const startTime = Date.now();
4345
+ try {
4346
+ let rawData;
4347
+ if (eventBus && endpoint) {
4348
+ const baseBody = endpoint.body ?? {};
4349
+ const cleanBody = {};
4350
+ for (const [k, v] of Object.entries(baseBody)) {
4351
+ if (typeof v === "string" && v.includes("$query")) continue;
4352
+ cleanBody[k] = v;
4353
+ }
4354
+ const body = {
4355
+ ...cleanBody,
4356
+ skip,
4357
+ limit
4358
+ };
4359
+ if (query && endpoint.query_param) {
4360
+ body.filters = [
4361
+ ...Array.isArray(body.filters) ? body.filters : [],
4362
+ { field: endpoint.query_param, condition: "like", value: query }
4363
+ ];
4364
+ }
4365
+ eventBus.emit(CHAT_EVENT.FORM_TRACE, {
4366
+ chatId: "",
4367
+ formTitle: "carousel",
4368
+ source: "carousel",
4369
+ phase: "request",
4370
+ service: endpoint.service,
4371
+ url: endpoint.url,
4372
+ method: endpoint.method,
4373
+ body
4374
+ });
4375
+ rawData = await fetchViaEventBus(
4376
+ eventBus,
4377
+ endpoint.service,
4378
+ endpoint.url,
4379
+ endpoint.method,
4380
+ body
4381
+ );
4382
+ eventBus.emit(CHAT_EVENT.FORM_TRACE, {
4383
+ chatId: "",
4384
+ formTitle: "carousel",
4385
+ source: "carousel",
4386
+ phase: "response",
4387
+ service: endpoint.service,
4388
+ url: endpoint.url,
4389
+ method: endpoint.method,
4390
+ status: 200,
4391
+ duration_ms: Date.now() - startTime,
4392
+ success: true,
4393
+ response: rawData
4394
+ });
4395
+ } else {
4396
+ rawData = await mockSearchFetch(query, skip, limit);
4397
+ }
4398
+ let newItems;
4399
+ if (endpoint) {
4400
+ newItems = mapResponseToItems(rawData, endpoint);
4401
+ } else {
4402
+ const arr = Array.isArray(rawData) ? rawData : [];
4403
+ newItems = arr.map((item) => ({
4404
+ id: String(item.id ?? ""),
4405
+ type: "image",
4406
+ title: String(item.name ?? ""),
4407
+ description: String(item.address ?? ""),
4408
+ src: String(item.logo_url ?? ""),
4409
+ status: "ready"
4410
+ }));
4411
+ }
4412
+ actions.items.set(newItems);
4413
+ actions.pagination.setPage(page);
4414
+ actions.pagination.setHasMore(newItems.length === limit);
4415
+ actions.search.setStatus("idle");
4416
+ } catch (err) {
4417
+ actions.search.setStatus("error");
4418
+ if (eventBus && endpoint) {
4419
+ eventBus.emit(CHAT_EVENT.FORM_TRACE, {
4420
+ chatId: "",
4421
+ formTitle: "carousel",
4422
+ source: "carousel",
4423
+ phase: "response",
4424
+ service: endpoint.service,
4425
+ url: endpoint.url,
4426
+ method: endpoint.method,
4427
+ status: 500,
4428
+ duration_ms: Date.now() - startTime,
4429
+ success: false,
4430
+ error: err instanceof Error ? err.message : "Error en busqueda"
4431
+ });
4432
+ }
4433
+ } finally {
4434
+ loadingRef.current = false;
4435
+ }
4436
+ },
4437
+ [actions, endpoint, eventBus, pageLimit]
4438
+ );
4439
+ const loadNext = useCallback(() => {
4440
+ const currentPage = actions.pagination.getPage();
4441
+ const query = actions.search.getQuery();
4442
+ search(query, currentPage + 1);
4443
+ }, [actions, search]);
4444
+ const loadPrev = useCallback(() => {
4445
+ const currentPage = actions.pagination.getPage();
4446
+ if (currentPage <= 0) return;
4447
+ const query = actions.search.getQuery();
4448
+ search(query, currentPage - 1);
4449
+ }, [actions, search]);
4450
+ return { search, loadNext, loadPrev };
4451
+ }
4452
+
4453
+ const FILE_ICONS = {
4454
+ pdf: "\u{1F4C4}",
4455
+ doc: "\u{1F4DD}",
4456
+ docx: "\u{1F4DD}",
4457
+ xls: "\u{1F4CA}",
4458
+ xlsx: "\u{1F4CA}",
4459
+ ppt: "\u{1F4CE}",
4460
+ pptx: "\u{1F4CE}",
4461
+ zip: "\u{1F4E6}",
4462
+ rar: "\u{1F4E6}",
4463
+ jpg: "\u{1F5BC}\uFE0F",
4464
+ jpeg: "\u{1F5BC}\uFE0F",
4465
+ png: "\u{1F5BC}\uFE0F",
4466
+ gif: "\u{1F5BC}\uFE0F",
4467
+ webp: "\u{1F5BC}\uFE0F",
4468
+ mp4: "\u{1F3AC}",
4469
+ mov: "\u{1F3AC}",
4470
+ avi: "\u{1F3AC}",
4471
+ mp3: "\u{1F3B5}",
4472
+ wav: "\u{1F3B5}"
4473
+ };
4474
+ const CarouselCard = ({
4475
+ item,
4476
+ size,
4477
+ selectionMode,
4478
+ isSelected,
4479
+ disabled,
4480
+ onSelect,
4481
+ onRemove,
4482
+ onPreview
4483
+ }) => {
4484
+ const isSelectable = selectionMode !== "none" && !disabled;
4485
+ const hasPreview = selectionMode === "none" && !!onPreview && item.src && (item.type === "image" || item.type === "file");
4486
+ const isClickable = isSelectable || hasPreview;
4487
+ const handleClick = () => {
4488
+ if (isSelectable) {
4489
+ if (selectionMode === "removable") return;
4490
+ onSelect(item);
4491
+ return;
4492
+ }
4493
+ if (hasPreview) {
4494
+ onPreview(item);
4495
+ }
4496
+ };
4497
+ const handleRemove = (e) => {
4498
+ e.stopPropagation();
4499
+ if (disabled) return;
4500
+ onRemove(item);
4501
+ };
4502
+ if (item.status === "loading") {
4503
+ return /* @__PURE__ */ jsx("div", { className: `px-chat-carousel-card px-chat-carousel-card--${size} px-chat-carousel-card--loading`, children: /* @__PURE__ */ jsx("div", { className: "px-chat-carousel-card__skeleton" }) });
4504
+ }
4505
+ return /* @__PURE__ */ jsxs(
4506
+ "div",
4507
+ {
4508
+ className: [
4509
+ "px-chat-carousel-card",
4510
+ `px-chat-carousel-card--${size}`,
4511
+ `px-chat-carousel-card--${item.type}`,
4512
+ isSelected ? "px-chat-carousel-card--selected" : "",
4513
+ isClickable ? "px-chat-carousel-card--clickable" : "",
4514
+ disabled ? "px-chat-carousel-card--disabled" : ""
4515
+ ].filter(Boolean).join(" "),
4516
+ onClick: handleClick,
4517
+ role: isClickable ? "button" : void 0,
4518
+ tabIndex: isClickable ? 0 : void 0,
4519
+ onKeyDown: isClickable ? (e) => {
4520
+ if (e.key === "Enter" || e.key === " ") handleClick();
4521
+ } : void 0,
4522
+ children: [
4523
+ selectionMode === "removable" && !disabled && /* @__PURE__ */ jsx(
4524
+ "button",
4525
+ {
4526
+ className: "px-chat-carousel-card__remove",
4527
+ onClick: handleRemove,
4528
+ "aria-label": "Eliminar",
4529
+ type: "button",
4530
+ children: "\xD7"
4531
+ }
4532
+ ),
4533
+ isSelected && selectionMode !== "removable" && /* @__PURE__ */ jsx("div", { className: "px-chat-carousel-card__check", children: "\u2713" }),
4534
+ item.type === "image" && /* @__PURE__ */ jsx(
4535
+ "img",
4536
+ {
4537
+ className: "px-chat-carousel-card__image",
4538
+ src: item.src,
4539
+ alt: item.title || "",
4540
+ loading: "lazy"
4541
+ }
4542
+ ),
4543
+ item.type === "file" && /* @__PURE__ */ jsx("div", { className: "px-chat-carousel-card__file-icon", children: FILE_ICONS[item.file_type?.toLowerCase() ?? ""] || "\u{1F4C1}" }),
4544
+ item.type === "text" && !item.title && !item.description && /* @__PURE__ */ jsx("div", { className: "px-chat-carousel-card__file-icon", children: "\u{1F4CB}" }),
4545
+ (item.title || item.description) && /* @__PURE__ */ jsxs("div", { className: "px-chat-carousel-card__info", children: [
4546
+ item.title && /* @__PURE__ */ jsx("div", { className: "px-chat-carousel-card__title", children: item.title }),
4547
+ item.description && /* @__PURE__ */ jsx("div", { className: "px-chat-carousel-card__description", children: item.description })
4548
+ ] })
4549
+ ]
4550
+ }
4551
+ );
4552
+ };
4553
+
4554
+ const CarouselTrack = ({
4555
+ currentPage,
4556
+ hasMore,
4557
+ onPrev,
4558
+ onNext,
4559
+ children
4560
+ }) => {
4561
+ const trackRef = useRef(null);
4562
+ useEffect(() => {
4563
+ if (trackRef.current) {
4564
+ trackRef.current.scrollLeft = 0;
4565
+ }
4566
+ }, [currentPage]);
4567
+ const showPrev = currentPage > 0;
4568
+ const showNext = hasMore;
4569
+ return /* @__PURE__ */ jsxs("div", { className: "px-chat-carousel-track-wrapper", children: [
4570
+ showPrev && /* @__PURE__ */ jsx(
4571
+ "button",
4572
+ {
4573
+ className: "px-chat-carousel-track__nav",
4574
+ onClick: onPrev,
4575
+ type: "button",
4576
+ "aria-label": "Anterior",
4577
+ children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "15 18 9 12 15 6" }) })
4578
+ }
4579
+ ),
4580
+ /* @__PURE__ */ jsx("div", { className: "px-chat-carousel-track", ref: trackRef, children }),
4581
+ showNext && /* @__PURE__ */ jsx(
4582
+ "button",
4583
+ {
4584
+ className: "px-chat-carousel-track__nav",
4585
+ onClick: onNext,
4586
+ type: "button",
4587
+ "aria-label": "Siguiente",
4588
+ children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" }) })
4589
+ }
4590
+ )
4591
+ ] });
4592
+ };
4593
+
4594
+ const DEBOUNCE_MS = 300;
4595
+ const CarouselSearch = ({ onSearch, loading }) => {
4596
+ const [value, setValue] = useState("");
4597
+ const timerRef = useRef(void 0);
4598
+ const onSearchRef = useRef(onSearch);
4599
+ onSearchRef.current = onSearch;
4600
+ useEffect(() => {
4601
+ clearTimeout(timerRef.current);
4602
+ timerRef.current = setTimeout(() => {
4603
+ onSearchRef.current(value);
4604
+ }, DEBOUNCE_MS);
4605
+ return () => clearTimeout(timerRef.current);
4606
+ }, [value]);
4607
+ return /* @__PURE__ */ jsxs("div", { className: "px-chat-carousel-search", children: [
4608
+ /* @__PURE__ */ jsx(
4609
+ "input",
4610
+ {
4611
+ className: "px-chat-carousel-search__input",
4612
+ type: "text",
4613
+ placeholder: "Buscar...",
4614
+ value,
4615
+ onChange: (e) => setValue(e.target.value)
4616
+ }
4617
+ ),
4618
+ loading && /* @__PURE__ */ jsx("span", { className: "px-chat-carousel-search__spinner" }),
4619
+ value && !loading && /* @__PURE__ */ jsx(
4620
+ "button",
4621
+ {
4622
+ className: "px-chat-carousel-search__clear",
4623
+ onClick: () => setValue(""),
4624
+ type: "button",
4625
+ "aria-label": "Limpiar",
4626
+ children: "\xD7"
4627
+ }
4628
+ )
4629
+ ] });
4630
+ };
4631
+
4632
+ const CarouselConfirm = ({
4633
+ label,
4634
+ count,
4635
+ disabled,
4636
+ onClick
4637
+ }) => {
4638
+ return /* @__PURE__ */ jsx("div", { className: "px-chat-carousel-confirm", children: /* @__PURE__ */ jsxs(
4639
+ "button",
4640
+ {
4641
+ className: "px-chat-carousel-confirm__button",
4642
+ disabled,
4643
+ onClick,
4644
+ type: "button",
4645
+ children: [
4646
+ label,
4647
+ " ",
4648
+ count > 0 && /* @__PURE__ */ jsxs("span", { className: "px-chat-carousel-confirm__count", children: [
4649
+ "(",
4650
+ count,
4651
+ ")"
4652
+ ] })
4653
+ ]
4654
+ }
4655
+ ) });
4656
+ };
4657
+
4658
+ const CarouselDisplay = ({
4659
+ component,
4660
+ eventBus,
4661
+ assistantMessageId = ""
4662
+ }) => {
4663
+ const props = component.props;
4664
+ const {
4665
+ items: initialItems = [],
4666
+ size: sizeProp,
4667
+ selection_mode: selectionMode = "none",
4668
+ confirm_label: confirmLabel = "Confirmar",
4669
+ searchable = false,
4670
+ search_endpoint: searchEndpoint,
4671
+ field_name: fieldName = ""
4672
+ } = props;
4673
+ const isAnswered = component.answered === true;
4674
+ const disabled = isAnswered && selectionMode !== "none";
4675
+ const { store, actions } = useMemo(() => {
4676
+ const s = createCarouselStore(initialItems);
4677
+ if (searchable && initialItems.length === 0) {
4678
+ s.set(CAROUSEL_STORE_KEYS.SEARCH_STATUS, "loading");
4679
+ }
4680
+ return { store: s, actions: createCarouselActions(s) };
4681
+ }, []);
4682
+ const items = useStoreState(store, CAROUSEL_STORE_KEYS.ITEMS);
4683
+ const selectedIds = useStoreState(store, CAROUSEL_STORE_KEYS.SELECTED_IDS);
4684
+ const searchStatus = useStoreState(store, CAROUSEL_STORE_KEYS.SEARCH_STATUS);
4685
+ const hasMore = useStoreState(store, CAROUSEL_STORE_KEYS.HAS_MORE);
4686
+ const currentPage = useStoreState(store, CAROUSEL_STORE_KEYS.CURRENT_PAGE);
4687
+ const containerRef = useRef(null);
4688
+ const resolvedSize = resolveSize(sizeProp, items.length);
4689
+ const pageLimit = useMemo(() => {
4690
+ const width = containerRef.current?.clientWidth ?? window.innerWidth;
4691
+ return calcPageLimit(resolvedSize, width);
4692
+ }, [resolvedSize]);
4693
+ const { emitInteraction, isConfirmed } = useComponentInteraction({
4694
+ eventBus,
4695
+ fieldName,
4696
+ componentType: "carousel",
4697
+ assistantMessageId
4698
+ });
4699
+ const { search, loadNext, loadPrev } = useCarouselSearch({
4700
+ actions,
4701
+ endpoint: searchEndpoint,
4702
+ eventBus,
4703
+ pageLimit
4704
+ });
4705
+ useEffect(() => {
4706
+ if (searchable && initialItems.length === 0) {
4707
+ search("", 0);
4708
+ }
4709
+ }, []);
4710
+ const handleSelect = useCallback(
4711
+ (item) => {
4712
+ if (disabled || isConfirmed) return;
4713
+ if (selectionMode === "single") {
4714
+ actions.selection.clear();
4715
+ actions.selection.toggle(item.id);
4716
+ emitInteraction(
4717
+ [{ value: item.id, label: item.title || item.id }],
4718
+ item.title || item.id
4719
+ );
4720
+ return;
4721
+ }
4722
+ if (selectionMode === "multiple") {
4723
+ actions.selection.toggle(item.id);
4724
+ }
4725
+ },
4726
+ [selectionMode, disabled, isConfirmed, actions, emitInteraction]
4727
+ );
4728
+ const handleRemove = useCallback(
4729
+ (item) => {
4730
+ if (disabled || isConfirmed) return;
4731
+ actions.items.remove(item.id);
4732
+ },
4733
+ [disabled, isConfirmed, actions]
4734
+ );
4735
+ const handleConfirm = useCallback(() => {
4736
+ if (disabled || isConfirmed) return;
4737
+ if (selectionMode === "multiple") {
4738
+ const selected = items.filter((i) => selectedIds.includes(i.id));
4739
+ const value = selected.map((i) => ({ value: i.id, label: i.title || i.id }));
4740
+ const label = selected.map((i) => i.title || i.id).join(", ");
4741
+ emitInteraction(value, label);
4742
+ }
4743
+ if (selectionMode === "removable") {
4744
+ const value = items.map((i) => ({ value: i.id, label: i.title || i.id }));
4745
+ const label = items.map((i) => i.title || i.id).join(", ");
4746
+ emitInteraction(value, label);
4747
+ }
4748
+ }, [selectionMode, disabled, isConfirmed, items, selectedIds, emitInteraction]);
4749
+ const confirmDisabled = useMemo(() => {
4750
+ if (selectionMode === "multiple") return selectedIds.length === 0;
4751
+ if (selectionMode === "removable") {
4752
+ const originalLen = actions.getOriginalItems().length;
4753
+ return items.length === originalLen;
4754
+ }
4755
+ return true;
4756
+ }, [selectionMode, selectedIds, items, actions]);
4757
+ const showConfirm = (selectionMode === "multiple" || selectionMode === "removable") && !disabled && !isConfirmed;
4758
+ if (selectionMode === "single" && (isConfirmed || isAnswered)) {
4759
+ return null;
4760
+ }
4761
+ return /* @__PURE__ */ jsxs("div", { className: "px-chat-carousel", ref: containerRef, children: [
4762
+ searchable && /* @__PURE__ */ jsx(
4763
+ CarouselSearch,
4764
+ {
4765
+ onSearch: (q) => search(q, 0),
4766
+ loading: searchStatus === "loading"
4767
+ }
4768
+ ),
4769
+ /* @__PURE__ */ jsx(
4770
+ CarouselTrack,
4771
+ {
4772
+ currentPage,
4773
+ hasMore,
4774
+ onPrev: loadPrev,
4775
+ onNext: loadNext,
4776
+ children: items.map((item) => /* @__PURE__ */ jsx(
4777
+ CarouselCard,
4778
+ {
4779
+ item,
4780
+ size: resolvedSize,
4781
+ selectionMode,
4782
+ isSelected: selectedIds.includes(item.id),
4783
+ disabled: disabled || isConfirmed,
4784
+ onSelect: handleSelect,
4785
+ onRemove: handleRemove
4786
+ },
4787
+ item.id
4788
+ ))
4789
+ }
4790
+ ),
4791
+ showConfirm && /* @__PURE__ */ jsx(
4792
+ CarouselConfirm,
4793
+ {
4794
+ label: confirmLabel,
4795
+ count: selectionMode === "multiple" ? selectedIds.length : items.length,
4796
+ disabled: confirmDisabled,
4797
+ onClick: handleConfirm
4798
+ }
4799
+ ),
4800
+ items.length === 0 && searchStatus !== "loading" && /* @__PURE__ */ jsx("div", { className: "px-chat-carousel__empty", children: "Sin resultados" })
4801
+ ] });
4802
+ };
4803
+
4804
+ const COMPONENT_MAP = {
4805
+ select: SelectWithConfirm,
4806
+ select_multiple: SelectMultipleWithConfirm,
4807
+ confirm: ConfirmButton,
4808
+ date_input: DateInputWithConfirm,
4809
+ time_input: TimeInputWithConfirm,
4810
+ input: InputWithConfirm,
4811
+ card: CardDisplay,
4812
+ badge: BadgeDisplay,
4813
+ reactive_form: ReactiveForm,
4814
+ carousel: CarouselDisplay
4815
+ };
4816
+ function renderComponent(props) {
4817
+ const { component } = props;
4818
+ if (component.answered && !DISPLAY_COMPONENTS.has(component.type)) {
4819
+ return null;
4820
+ }
4821
+ const Component = COMPONENT_MAP[component.type];
4822
+ if (!Component) return null;
4823
+ return /* @__PURE__ */ jsx(Component, { ...props });
4824
+ }
4825
+
4826
+ const StructuredContent = ({
4827
+ content,
4828
+ eventBus,
4829
+ assistantMessageId,
4830
+ className = ""
4831
+ }) => {
4832
+ const structured = parseContent(content);
4833
+ const markdownContent = structured ? structured.message : content;
4834
+ const rawComponent = structured?.component || null;
4835
+ const components = rawComponent ? Array.isArray(rawComponent) ? rawComponent : [rawComponent] : [];
4836
+ const hasVisibleComponents = components.some((comp) => !comp.answered || DISPLAY_COMPONENTS.has(comp.type));
4837
+ return /* @__PURE__ */ jsxs("div", { className: `${COMPONENT_PREFIX$1}structured-content ${className}`, children: [
4838
+ markdownContent && /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX$1}assistant-message__markdown${hasVisibleComponents ? ` ${COMPONENT_PREFIX$1}assistant-message__markdown--with-component` : ``}`, children: /* @__PURE__ */ jsx(
4839
+ ReactMarkdown,
4840
+ {
4841
+ components: {
4842
+ a: ({ href, children }) => /* @__PURE__ */ jsx(
4843
+ Link,
4844
+ {
4845
+ href: href || "#",
4846
+ variant: "primary",
4847
+ size: "medium",
4848
+ weight: "bold",
4849
+ underline: false,
4850
+ children
4851
+ }
4852
+ )
4853
+ },
4854
+ children: markdownContent
4855
+ }
4856
+ ) }),
4857
+ components.length > 0 && /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX$1}structured-content__component`, children: components.map((comp, index) => /* @__PURE__ */ jsx(React.Fragment, { children: renderComponent({ component: comp, eventBus, assistantMessageId }) }, `${comp.type}-${index}`)) })
4858
+ ] });
4859
+ };
4860
+
4861
+ const getAttachmentType = (file) => {
4862
+ const mimeType = file.type.toLowerCase();
4863
+ if (mimeType.startsWith(MIME_PREFIXES.AUDIO)) {
4864
+ return AttachmentType.AUDIO;
4865
+ }
4866
+ if (mimeType.startsWith(MIME_PREFIXES.VIDEO)) {
4867
+ return AttachmentType.VIDEO;
4868
+ }
4869
+ if (mimeType.startsWith(MIME_PREFIXES.IMAGE)) {
4870
+ return AttachmentType.IMAGE;
4871
+ }
4872
+ if (mimeType === MIME_TYPES.PDF) {
4873
+ return AttachmentType.PDF;
4874
+ }
4875
+ if (mimeType.includes(MIME_KEYWORDS.DOCUMENT) || mimeType.includes(MIME_KEYWORDS.WORD) || mimeType.includes(MIME_KEYWORDS.EXCEL) || mimeType.includes(MIME_KEYWORDS.POWERPOINT) || mimeType.startsWith(MIME_PREFIXES.TEXT)) {
4876
+ return AttachmentType.DOCUMENT;
4877
+ }
4878
+ return AttachmentType.OTHER;
4879
+ };
4880
+ const filterFilesByType = (files, type) => {
4881
+ const types = Array.isArray(type) ? type : [type];
4882
+ return files.filter((file) => {
4883
+ const fileType = getAttachmentType(file);
4884
+ return types.includes(fileType);
4885
+ });
4886
+ };
4887
+ const getFileUrl = (file) => {
4888
+ if (file.url) {
4889
+ return file.url;
4890
+ }
4891
+ return URL.createObjectURL(file);
4892
+ };
4893
+ const getAudioFiles = (files) => {
4894
+ return filterFilesByType(files, [AttachmentType.AUDIO]);
4895
+ };
4896
+ const getNonAudioFiles = (files) => {
4897
+ return filterFilesByType(files, [
4898
+ AttachmentType.IMAGE,
4899
+ AttachmentType.PDF,
4900
+ AttachmentType.DOCUMENT,
4901
+ AttachmentType.OTHER
4902
+ ]);
4903
+ };
4904
+
4905
+ function deepMerge(target, source) {
3099
4906
  if (typeof target !== "object" || target === null) {
3100
4907
  return source;
3101
4908
  }
@@ -3200,20 +5007,244 @@ const AssistantMessage = ({
3200
5007
  ] }) });
3201
5008
  };
3202
5009
 
3203
- const messages = {
5010
+ const initialState$1 = {
5011
+ // ChatInput (molécula) - Estados del input de chat
5012
+ chatInput: {
5013
+ buttonSend: {
5014
+ disabled: true,
5015
+ // Disabled hasta que haya contenido
5016
+ visible: false
5017
+ // Inicialmente oculto
5018
+ },
5019
+ buttonMicrophone: {
5020
+ disabled: false,
5021
+ visible: true
5022
+ // Inicialmente visible (botón de audio por defecto)
5023
+ },
5024
+ buttonAttachment: {
5025
+ disabled: false
5026
+ },
5027
+ hasText: false,
5028
+ hasAttachments: false
5029
+ },
5030
+ // AssistantThinkingIndicator (molécula) - Estado del indicador
5031
+ assistantThinkingIndicator: {
5032
+ visible: false,
5033
+ agentName: void 0,
5034
+ agentLabel: void 0,
5035
+ toolName: void 0
5036
+ },
5037
+ // ScrollButton (átomo) - Estado del botón de scroll
5038
+ scrollButton: {
5039
+ visible: false
5040
+ },
5041
+ // VirtualKeyboard - Estado del teclado virtual
5042
+ virtualKeyboard: {
5043
+ isOpen: false
5044
+ },
5045
+ // Textarea - Estado del textarea del chat
5046
+ textarea: {
5047
+ isFocused: false,
5048
+ isEmpty: true,
5049
+ shouldPreventKeyboard: false,
5050
+ shouldFocus: false,
5051
+ shouldBlur: false
5052
+ },
5053
+ // Scroll to top trigger
5054
+ scrollToTop: {
5055
+ pending: false
5056
+ }
5057
+ };
5058
+ const chatStore = createStore(initialState$1);
5059
+ const setChatStore = createStoreMerger(chatStore);
5060
+ const subscribeChatProperty = createDeepPropertySubscriber(chatStore);
5061
+
5062
+ const CHAT_STORE_KEYS = {
5063
+ // ChatInput relacionado
5064
+ CHAT_INPUT: "chatInput",
5065
+ // AssistantThinkingIndicator relacionado
5066
+ ASSISTANT_THINKING_INDICATOR: "assistantThinkingIndicator",
5067
+ // ScrollButton relacionado
5068
+ SCROLL_BUTTON: "scrollButton",
5069
+ // VirtualKeyboard relacionado
5070
+ VIRTUAL_KEYBOARD: "virtualKeyboard",
5071
+ // Textarea relacionado
5072
+ TEXTAREA: "textarea",
5073
+ // Scroll to top trigger
5074
+ SCROLL_TO_TOP: "scrollToTop"
5075
+ };
5076
+
5077
+ const textareaActions = {
5078
+ focus: () => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true }),
5079
+ blur: () => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldBlur: true }),
5080
+ setFocused: (isFocused) => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { isFocused }),
5081
+ setEmpty: (isEmpty) => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { isEmpty }),
5082
+ setShouldPreventKeyboard: (shouldPrevent) => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldPreventKeyboard: shouldPrevent }),
5083
+ resetTriggers: () => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: false, shouldBlur: false }),
5084
+ maintainFocusAfterSend: () => {
5085
+ setTimeout(() => {
5086
+ setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
5087
+ }, 10);
5088
+ setTimeout(() => {
5089
+ setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
5090
+ }, 50);
5091
+ },
5092
+ preserveFocusWithKeyboard: () => {
5093
+ setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
5094
+ setTimeout(() => {
5095
+ setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
5096
+ }, 10);
5097
+ setTimeout(() => {
5098
+ setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
5099
+ }, 50);
5100
+ }
5101
+ };
5102
+ const keyboardActions = {
5103
+ setOpen: (isOpen) => setChatStore(CHAT_STORE_KEYS.VIRTUAL_KEYBOARD, { isOpen }),
5104
+ open: () => setChatStore(CHAT_STORE_KEYS.VIRTUAL_KEYBOARD, { isOpen: true }),
5105
+ close: () => setChatStore(CHAT_STORE_KEYS.VIRTUAL_KEYBOARD, { isOpen: false })
5106
+ };
5107
+ const chatInputActions = {
5108
+ setSendDisabled: (disabled) => {
5109
+ const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
5110
+ setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
5111
+ buttonSend: {
5112
+ disabled,
5113
+ visible: currentState.buttonSend.visible
5114
+ }
5115
+ });
5116
+ },
5117
+ setMicDisabled: (disabled) => {
5118
+ const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
5119
+ setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
5120
+ buttonMicrophone: {
5121
+ disabled,
5122
+ visible: currentState.buttonMicrophone.visible
5123
+ }
5124
+ });
5125
+ },
5126
+ setAttachDisabled: (disabled) => setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, { buttonAttachment: { disabled } }),
5127
+ setSendVisible: (visible) => {
5128
+ const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
5129
+ setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
5130
+ buttonSend: {
5131
+ visible,
5132
+ disabled: currentState.buttonSend.disabled
5133
+ }
5134
+ });
5135
+ },
5136
+ setMicVisible: (visible) => {
5137
+ const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
5138
+ setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
5139
+ buttonMicrophone: {
5140
+ visible,
5141
+ disabled: currentState.buttonMicrophone.disabled
5142
+ }
5143
+ });
5144
+ },
5145
+ setHasText: (hasText) => setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, { hasText }),
5146
+ setHasAttachments: (hasAttachments) => setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, { hasAttachments }),
5147
+ updateButtonVisibility: (hasText, hasAttachments) => {
5148
+ const shouldShowSend = hasText || hasAttachments;
5149
+ const shouldShowMic = !hasText && !hasAttachments;
5150
+ const isThinking = chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).visible;
5151
+ const hasContent = hasText || hasAttachments;
5152
+ const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
5153
+ setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
5154
+ hasText,
5155
+ hasAttachments,
5156
+ buttonSend: {
5157
+ visible: shouldShowSend,
5158
+ disabled: isThinking || !hasContent
5159
+ },
5160
+ buttonMicrophone: {
5161
+ visible: shouldShowMic,
5162
+ disabled: currentState.buttonMicrophone.disabled
5163
+ }
5164
+ });
5165
+ }
5166
+ };
5167
+ const thinkingActions = {
5168
+ setVisible: (visible) => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { visible }),
5169
+ show: () => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { visible: true }),
5170
+ hide: () => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, {
5171
+ visible: false,
5172
+ agentName: void 0,
5173
+ agentLabel: void 0,
5174
+ toolName: void 0
5175
+ }),
5176
+ setThinking: (isThinking) => {
5177
+ setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { visible: isThinking });
5178
+ },
5179
+ setAgentName: (agentName) => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { agentName }),
5180
+ setAgentLabel: (agentLabel) => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { agentLabel }),
5181
+ setToolName: (toolName) => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { toolName })
5182
+ };
5183
+ const scrollButtonActions = {
5184
+ setVisible: (visible) => setChatStore(CHAT_STORE_KEYS.SCROLL_BUTTON, { visible }),
5185
+ show: () => setChatStore(CHAT_STORE_KEYS.SCROLL_BUTTON, { visible: true }),
5186
+ hide: () => setChatStore(CHAT_STORE_KEYS.SCROLL_BUTTON, { visible: false })
5187
+ };
5188
+ const scrollToTopActions = {
5189
+ activate: () => setChatStore(CHAT_STORE_KEYS.SCROLL_TO_TOP, { pending: true }),
5190
+ reset: () => setChatStore(CHAT_STORE_KEYS.SCROLL_TO_TOP, { pending: false })
5191
+ };
5192
+ const combinedActions = {
5193
+ prepareFileButtonClick: (isEmpty, isKeyboardOpen) => {
5194
+ if (!isKeyboardOpen && isEmpty) {
5195
+ textareaActions.setShouldPreventKeyboard(true);
5196
+ textareaActions.blur();
5197
+ }
5198
+ },
5199
+ initializeChat: () => {
5200
+ textareaActions.setEmpty(true);
5201
+ textareaActions.setFocused(false);
5202
+ keyboardActions.close();
5203
+ thinkingActions.hide();
5204
+ scrollButtonActions.hide();
5205
+ chatInputActions.updateButtonVisibility(false, false);
5206
+ },
5207
+ handleMessageSend: () => {
5208
+ textareaActions.maintainFocusAfterSend();
5209
+ }
5210
+ };
5211
+
5212
+ const fallbackMessages = {
3204
5213
  short: ["Revisando...", "Procesando...", "Analizando..."],
3205
5214
  medium: ["Analizando tu consulta...", "Estoy viendo c\xF3mo resolverlo...", "Buscando la mejor manera de ayudarte..."],
3206
5215
  long: ["Sigo con esto. Un momento m\xE1s.", "Estoy en eso, ya te respondo.", "Ya casi lo tengo."],
3207
5216
  veryLong: ["Esto est\xE1 tardando mas de lo habitual.", "Esto lleva un poco m\xE1s de tiempo.", "Lleva un poco m\xE1s de lo normal."]
3208
5217
  };
3209
5218
  const getRandomMessage = (category) => {
3210
- const categoryMessages = messages[category];
5219
+ const categoryMessages = fallbackMessages[category];
3211
5220
  return categoryMessages[Math.floor(Math.random() * categoryMessages.length)];
3212
5221
  };
3213
5222
  const AssistantThinkingIndicator = () => {
3214
5223
  const { showRoleLabels } = useChatConfig();
3215
- const [displayedMessage, setDisplayedMessage] = useState(getRandomMessage("short"));
5224
+ const [fallbackMessage, setFallbackMessage] = useState(getRandomMessage("short"));
3216
5225
  const [elapsedSeconds, setElapsedSeconds] = useState(0);
5226
+ const [agentLabel, setAgentLabel] = useState(
5227
+ chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).agentLabel
5228
+ );
5229
+ const [toolName, setToolName] = useState(
5230
+ chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).toolName
5231
+ );
5232
+ useEffect(() => {
5233
+ const unsubLabel = subscribeChatProperty(
5234
+ CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR,
5235
+ "agentLabel",
5236
+ setAgentLabel
5237
+ );
5238
+ const unsubTool = subscribeChatProperty(
5239
+ CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR,
5240
+ "toolName",
5241
+ setToolName
5242
+ );
5243
+ return () => {
5244
+ unsubLabel();
5245
+ unsubTool();
5246
+ };
5247
+ }, []);
3217
5248
  useEffect(() => {
3218
5249
  const timer = setInterval(() => {
3219
5250
  setElapsedSeconds((prev) => prev + 1);
@@ -3222,13 +5253,14 @@ const AssistantThinkingIndicator = () => {
3222
5253
  }, []);
3223
5254
  useEffect(() => {
3224
5255
  if (elapsedSeconds === 6) {
3225
- setDisplayedMessage(getRandomMessage("medium"));
5256
+ setFallbackMessage(getRandomMessage("medium"));
3226
5257
  } else if (elapsedSeconds === 13) {
3227
- setDisplayedMessage(getRandomMessage("long"));
5258
+ setFallbackMessage(getRandomMessage("long"));
3228
5259
  } else if (elapsedSeconds === 21) {
3229
- setDisplayedMessage(getRandomMessage("veryLong"));
5260
+ setFallbackMessage(getRandomMessage("veryLong"));
3230
5261
  }
3231
5262
  }, [elapsedSeconds]);
5263
+ const displayedMessage = agentLabel ? toolName ? `${agentLabel} \u2014 ${toolName}` : `${agentLabel}...` : fallbackMessage;
3232
5264
  return /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX$1}assistant-thinking-indicator`, children: /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX$1}assistant-thinking-indicator__content`, children: /* @__PURE__ */ jsxs("div", { className: `${COMPONENT_PREFIX$1}assistant-thinking-indicator__bubble`, children: [
3233
5265
  showRoleLabels && /* @__PURE__ */ jsx(Text, { variant: "caption", color: "secondary", className: `${COMPONENT_PREFIX$1}assistant-thinking-indicator__role`, children: "Assistant" }),
3234
5266
  /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX$1}assistant-thinking-indicator__text-container`, children: /* @__PURE__ */ jsx(Text, { variant: "body", color: "primary", className: `${COMPONENT_PREFIX$1}assistant-thinking-indicator__wave-text`, children: displayedMessage.split("").map((char, index) => /* @__PURE__ */ jsx(
@@ -3671,203 +5703,6 @@ const FullscreenViewer = ({
3671
5703
  );
3672
5704
  };
3673
5705
 
3674
- const initialState$1 = {
3675
- // ChatInput (molécula) - Estados del input de chat
3676
- chatInput: {
3677
- buttonSend: {
3678
- disabled: true,
3679
- // Disabled hasta que haya contenido
3680
- visible: false
3681
- // Inicialmente oculto
3682
- },
3683
- buttonMicrophone: {
3684
- disabled: false,
3685
- visible: true
3686
- // Inicialmente visible (botón de audio por defecto)
3687
- },
3688
- buttonAttachment: {
3689
- disabled: false
3690
- },
3691
- hasText: false,
3692
- hasAttachments: false
3693
- },
3694
- // AssistantThinkingIndicator (molécula) - Estado del indicador
3695
- assistantThinkingIndicator: {
3696
- visible: false
3697
- },
3698
- // ScrollButton (átomo) - Estado del botón de scroll
3699
- scrollButton: {
3700
- visible: false
3701
- },
3702
- // VirtualKeyboard - Estado del teclado virtual
3703
- virtualKeyboard: {
3704
- isOpen: false
3705
- },
3706
- // Textarea - Estado del textarea del chat
3707
- textarea: {
3708
- isFocused: false,
3709
- isEmpty: true,
3710
- shouldPreventKeyboard: false,
3711
- shouldFocus: false,
3712
- shouldBlur: false
3713
- },
3714
- // Scroll to top trigger
3715
- scrollToTop: {
3716
- pending: false
3717
- }
3718
- };
3719
- const chatStore = createStore(initialState$1);
3720
- const setChatStore = createStoreMerger(chatStore);
3721
- const subscribeChatProperty = createDeepPropertySubscriber(chatStore);
3722
-
3723
- const CHAT_STORE_KEYS = {
3724
- // ChatInput relacionado
3725
- CHAT_INPUT: "chatInput",
3726
- // AssistantThinkingIndicator relacionado
3727
- ASSISTANT_THINKING_INDICATOR: "assistantThinkingIndicator",
3728
- // ScrollButton relacionado
3729
- SCROLL_BUTTON: "scrollButton",
3730
- // VirtualKeyboard relacionado
3731
- VIRTUAL_KEYBOARD: "virtualKeyboard",
3732
- // Textarea relacionado
3733
- TEXTAREA: "textarea",
3734
- // Scroll to top trigger
3735
- SCROLL_TO_TOP: "scrollToTop"
3736
- };
3737
-
3738
- const textareaActions = {
3739
- focus: () => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true }),
3740
- blur: () => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldBlur: true }),
3741
- setFocused: (isFocused) => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { isFocused }),
3742
- setEmpty: (isEmpty) => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { isEmpty }),
3743
- setShouldPreventKeyboard: (shouldPrevent) => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldPreventKeyboard: shouldPrevent }),
3744
- resetTriggers: () => setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: false, shouldBlur: false }),
3745
- maintainFocusAfterSend: () => {
3746
- setTimeout(() => {
3747
- setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
3748
- }, 10);
3749
- setTimeout(() => {
3750
- setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
3751
- }, 50);
3752
- },
3753
- preserveFocusWithKeyboard: () => {
3754
- setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
3755
- setTimeout(() => {
3756
- setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
3757
- }, 10);
3758
- setTimeout(() => {
3759
- setChatStore(CHAT_STORE_KEYS.TEXTAREA, { shouldFocus: true });
3760
- }, 50);
3761
- }
3762
- };
3763
- const keyboardActions = {
3764
- setOpen: (isOpen) => setChatStore(CHAT_STORE_KEYS.VIRTUAL_KEYBOARD, { isOpen }),
3765
- open: () => setChatStore(CHAT_STORE_KEYS.VIRTUAL_KEYBOARD, { isOpen: true }),
3766
- close: () => setChatStore(CHAT_STORE_KEYS.VIRTUAL_KEYBOARD, { isOpen: false })
3767
- };
3768
- const chatInputActions = {
3769
- setSendDisabled: (disabled) => {
3770
- const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
3771
- setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
3772
- buttonSend: {
3773
- disabled,
3774
- visible: currentState.buttonSend.visible
3775
- }
3776
- });
3777
- },
3778
- setMicDisabled: (disabled) => {
3779
- const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
3780
- setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
3781
- buttonMicrophone: {
3782
- disabled,
3783
- visible: currentState.buttonMicrophone.visible
3784
- }
3785
- });
3786
- },
3787
- setAttachDisabled: (disabled) => setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, { buttonAttachment: { disabled } }),
3788
- setSendVisible: (visible) => {
3789
- const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
3790
- setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
3791
- buttonSend: {
3792
- visible,
3793
- disabled: currentState.buttonSend.disabled
3794
- }
3795
- });
3796
- },
3797
- setMicVisible: (visible) => {
3798
- const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
3799
- setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
3800
- buttonMicrophone: {
3801
- visible,
3802
- disabled: currentState.buttonMicrophone.disabled
3803
- }
3804
- });
3805
- },
3806
- setHasText: (hasText) => setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, { hasText }),
3807
- setHasAttachments: (hasAttachments) => setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, { hasAttachments }),
3808
- updateButtonVisibility: (hasText, hasAttachments) => {
3809
- const shouldShowSend = hasText || hasAttachments;
3810
- const shouldShowMic = !hasText && !hasAttachments;
3811
- const isThinking = chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).visible;
3812
- const hasContent = hasText || hasAttachments;
3813
- const currentState = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
3814
- setChatStore(CHAT_STORE_KEYS.CHAT_INPUT, {
3815
- hasText,
3816
- hasAttachments,
3817
- buttonSend: {
3818
- visible: shouldShowSend,
3819
- disabled: isThinking || !hasContent
3820
- },
3821
- buttonMicrophone: {
3822
- visible: shouldShowMic,
3823
- disabled: currentState.buttonMicrophone.disabled
3824
- }
3825
- });
3826
- }
3827
- };
3828
- const thinkingActions = {
3829
- setVisible: (visible) => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { visible }),
3830
- show: () => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { visible: true }),
3831
- hide: () => setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { visible: false }),
3832
- setThinking: (isThinking) => {
3833
- setChatStore(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR, { visible: isThinking });
3834
- if (isThinking) {
3835
- chatInputActions.setSendDisabled(true);
3836
- } else {
3837
- const currentInput = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
3838
- chatInputActions.updateButtonVisibility(currentInput.hasText, currentInput.hasAttachments);
3839
- }
3840
- }
3841
- };
3842
- const scrollButtonActions = {
3843
- setVisible: (visible) => setChatStore(CHAT_STORE_KEYS.SCROLL_BUTTON, { visible }),
3844
- show: () => setChatStore(CHAT_STORE_KEYS.SCROLL_BUTTON, { visible: true }),
3845
- hide: () => setChatStore(CHAT_STORE_KEYS.SCROLL_BUTTON, { visible: false })
3846
- };
3847
- const scrollToTopActions = {
3848
- activate: () => setChatStore(CHAT_STORE_KEYS.SCROLL_TO_TOP, { pending: true }),
3849
- reset: () => setChatStore(CHAT_STORE_KEYS.SCROLL_TO_TOP, { pending: false })
3850
- };
3851
- const combinedActions = {
3852
- prepareFileButtonClick: (isEmpty, isKeyboardOpen) => {
3853
- if (!isKeyboardOpen && isEmpty) {
3854
- textareaActions.setShouldPreventKeyboard(true);
3855
- textareaActions.blur();
3856
- }
3857
- },
3858
- initializeChat: () => {
3859
- textareaActions.setEmpty(true);
3860
- textareaActions.setFocused(false);
3861
- keyboardActions.close();
3862
- thinkingActions.hide();
3863
- scrollButtonActions.hide();
3864
- chatInputActions.updateButtonVisibility(false, false);
3865
- },
3866
- handleMessageSend: () => {
3867
- textareaActions.maintainFocusAfterSend();
3868
- }
3869
- };
3870
-
3871
5706
  const ChatInput = forwardRef(({
3872
5707
  value,
3873
5708
  onChange,
@@ -4792,6 +6627,15 @@ const useChatStore = () => {
4792
6627
  const [showThinking, setShowThinking] = useState(
4793
6628
  chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).visible
4794
6629
  );
6630
+ const [agentName, setAgentName] = useState(
6631
+ chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).agentName
6632
+ );
6633
+ const [agentLabel, setAgentLabel] = useState(
6634
+ chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).agentLabel
6635
+ );
6636
+ const [toolName, setToolName] = useState(
6637
+ chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).toolName
6638
+ );
4795
6639
  const [scrollButtonState, setScrollButtonState] = useState(
4796
6640
  chatStore.get(CHAT_STORE_KEYS.SCROLL_BUTTON)
4797
6641
  );
@@ -4804,6 +6648,21 @@ const useChatStore = () => {
4804
6648
  "visible",
4805
6649
  setShowThinking
4806
6650
  );
6651
+ const unsubAgentName = subscribeChatProperty(
6652
+ CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR,
6653
+ "agentName",
6654
+ setAgentName
6655
+ );
6656
+ const unsubAgentLabel = subscribeChatProperty(
6657
+ CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR,
6658
+ "agentLabel",
6659
+ setAgentLabel
6660
+ );
6661
+ const unsubToolName = subscribeChatProperty(
6662
+ CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR,
6663
+ "toolName",
6664
+ setToolName
6665
+ );
4807
6666
  const unsubScrollButton = subscribeChatProperty(
4808
6667
  CHAT_STORE_KEYS.SCROLL_BUTTON,
4809
6668
  "",
@@ -4816,12 +6675,18 @@ const useChatStore = () => {
4816
6675
  );
4817
6676
  return () => {
4818
6677
  unsubThinking();
6678
+ unsubAgentName();
6679
+ unsubAgentLabel();
6680
+ unsubToolName();
4819
6681
  unsubScrollButton();
4820
6682
  unsubScrollToTop();
4821
6683
  };
4822
6684
  }, []);
4823
6685
  return {
4824
6686
  showThinking,
6687
+ agentName,
6688
+ agentLabel,
6689
+ toolName,
4825
6690
  scrollButtonState,
4826
6691
  scrollToTopPending
4827
6692
  };
@@ -4849,9 +6714,9 @@ const useChatHandlers = ({
4849
6714
  clearAttachments,
4850
6715
  scrollToLastUserMessage
4851
6716
  }) => {
4852
- const isThinking = () => chatStore.get(CHAT_STORE_KEYS.ASSISTANT_THINKING_INDICATOR).visible;
6717
+ const isInputDisabled = () => chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT).buttonSend.disabled;
4853
6718
  const handleSendWithFiles = (content, files) => {
4854
- if (isThinking()) return;
6719
+ if (isInputDisabled()) return;
4855
6720
  if (!content.trim() && (!files || files.length === 0)) return;
4856
6721
  combinedActions.handleMessageSend();
4857
6722
  onSend(content, files);
@@ -4862,7 +6727,7 @@ const useChatHandlers = ({
4862
6727
  const handleInputKeyDown = (e, inputValue, attachments) => {
4863
6728
  if (e.key === "Enter" && !e.shiftKey) {
4864
6729
  e.preventDefault();
4865
- if (isThinking()) return;
6730
+ if (isInputDisabled()) return;
4866
6731
  handleSendWithFiles(inputValue, attachments);
4867
6732
  }
4868
6733
  };
@@ -5199,12 +7064,21 @@ const Chat = ({
5199
7064
  const unsubComponent = eventBus.on(CHAT_EVENT.COMPONENT_INTERACTION, () => {
5200
7065
  scrollToTopActions.activate();
5201
7066
  });
7067
+ const unsubInputDisabled = eventBus.on(CHAT_EVENT.INPUT_DISABLED, ({ disabled }) => {
7068
+ if (disabled) {
7069
+ chatInputActions.setSendDisabled(true);
7070
+ } else {
7071
+ const { hasText, hasAttachments } = chatStore.get(CHAT_STORE_KEYS.CHAT_INPUT);
7072
+ chatInputActions.updateButtonVisibility(hasText, hasAttachments);
7073
+ }
7074
+ });
5202
7075
  return () => {
5203
7076
  unsubMessages();
5204
7077
  unsubHeader();
5205
7078
  unsubPlaceholder();
5206
7079
  unsubThinking();
5207
7080
  unsubComponent();
7081
+ unsubInputDisabled();
5208
7082
  };
5209
7083
  }, [eventBus]);
5210
7084
  const handleSend = (content, files) => {
@@ -5289,33 +7163,37 @@ const Chat = ({
5289
7163
  ref: messagesContainerRef,
5290
7164
  onClick: handleMainClick,
5291
7165
  children: [
5292
- messageGroups.map((group, groupIndex) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
5293
- /* @__PURE__ */ jsx(DateDivider, { date: group.date }),
5294
- group.messages.map((msg, msgIndex) => {
5295
- const key = msg.id ?? `${groupIndex}-${msgIndex}`;
5296
- return msg.role === "user" ? /* @__PURE__ */ jsx(
5297
- UserMessage,
5298
- {
5299
- content: msg.content,
5300
- timestamp: msg.timestamp,
5301
- status: msg.status,
5302
- onRetry: msg.status === "failed" ? () => handleRetry(msg) : void 0,
5303
- files: msg.files
5304
- },
5305
- key
5306
- ) : /* @__PURE__ */ jsx(
5307
- AssistantMessage,
5308
- {
5309
- content: msg.content,
5310
- timestamp: msg.timestamp,
5311
- files: msg.files,
5312
- eventBus,
5313
- messageId: msg.id
5314
- },
5315
- key
5316
- );
5317
- })
5318
- ] }, `${group.date.getTime()}-${groupIndex}`)),
7166
+ messageGroups.map((group, groupIndex) => {
7167
+ const isToday = group.date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
7168
+ const showDivider = !(messageGroups.length === 1 && isToday);
7169
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
7170
+ showDivider && /* @__PURE__ */ jsx(DateDivider, { date: group.date }),
7171
+ group.messages.map((msg, msgIndex) => {
7172
+ const key = msg.id ?? `${groupIndex}-${msgIndex}`;
7173
+ return msg.role === "user" ? /* @__PURE__ */ jsx(
7174
+ UserMessage,
7175
+ {
7176
+ content: msg.content,
7177
+ timestamp: msg.timestamp,
7178
+ status: msg.status,
7179
+ onRetry: msg.status === "failed" ? () => handleRetry(msg) : void 0,
7180
+ files: msg.files
7181
+ },
7182
+ key
7183
+ ) : /* @__PURE__ */ jsx(
7184
+ AssistantMessage,
7185
+ {
7186
+ content: msg.content,
7187
+ timestamp: msg.timestamp,
7188
+ files: msg.files,
7189
+ eventBus,
7190
+ messageId: msg.id
7191
+ },
7192
+ key
7193
+ );
7194
+ })
7195
+ ] }, `${group.date.getTime()}-${groupIndex}`);
7196
+ }),
5319
7197
  showThinking && /* @__PURE__ */ jsx(AssistantThinkingIndicator, {}),
5320
7198
  /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
5321
7199
  ]