pixelon 0.3.77 → 0.3.78

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 (24) hide show
  1. package/dist/components/atoms/lumi/FieldValue/FieldValue.d.ts +15 -0
  2. package/dist/components/atoms/lumi/FieldValue/index.d.ts +2 -0
  3. package/dist/components/atoms/lumi/FieldValue/types.d.ts +10 -0
  4. package/dist/components/molecules/chat/StructuredContent/components/ReactiveCrud/ChatLinkCell.d.ts +20 -0
  5. package/dist/components/molecules/chat/StructuredContent/components/ReactiveCrud/optionsLoader.d.ts +2 -1
  6. package/dist/components/molecules/chat/StructuredContent/components/ReactiveCrud/types.d.ts +6 -0
  7. package/dist/components/molecules/lumi/Drawer/Drawer.d.ts +8 -0
  8. package/dist/components/molecules/lumi/RecordCard/RecordCard.d.ts +14 -0
  9. package/dist/components/molecules/lumi/RecordCard/index.d.ts +2 -0
  10. package/dist/components/molecules/lumi/RecordCard/types.d.ts +16 -0
  11. package/dist/components/molecules/lumi/ScrollToEnd/ScrollToEnd.d.ts +21 -0
  12. package/dist/components/molecules/lumi/ScrollToEnd/index.d.ts +2 -0
  13. package/dist/components/templates/lumi/Crud/CardList.d.ts +34 -0
  14. package/dist/components/templates/lumi/Crud/Crud.d.ts +1 -1
  15. package/dist/components/templates/lumi/Crud/ScrollToEnd.d.ts +18 -0
  16. package/dist/components/templates/lumi/Crud/helpers/fieldValue.d.ts +12 -0
  17. package/dist/components/templates/lumi/Crud/types.d.ts +25 -0
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.esm.js +545 -276
  20. package/dist/index.js +546 -275
  21. package/dist/styles.css +1 -1
  22. package/dist/styles.css.map +1 -1
  23. package/package.json +1 -1
  24. package/src/styles/index.scss +4 -0
package/dist/index.esm.js CHANGED
@@ -3987,13 +3987,13 @@ function resolveVariable(template, formValues, fieldStates) {
3987
3987
  }
3988
3988
  return "";
3989
3989
  }
3990
- function resolveBody(obj, formValues, fieldStates) {
3990
+ function resolveBody$1(obj, formValues, fieldStates) {
3991
3991
  if (typeof obj === "string") return resolveVariable(obj, formValues, fieldStates);
3992
- if (Array.isArray(obj)) return obj.map((item) => resolveBody(item, formValues, fieldStates));
3992
+ if (Array.isArray(obj)) return obj.map((item) => resolveBody$1(item, formValues, fieldStates));
3993
3993
  if (obj !== null && typeof obj === "object") {
3994
3994
  const resolved = {};
3995
3995
  for (const [key, value] of Object.entries(obj)) {
3996
- resolved[key] = resolveBody(value, formValues, fieldStates);
3996
+ resolved[key] = resolveBody$1(value, formValues, fieldStates);
3997
3997
  }
3998
3998
  return resolved;
3999
3999
  }
@@ -4043,7 +4043,7 @@ const CostSummaryField = ({
4043
4043
  return;
4044
4044
  }
4045
4045
  fetchedRef.current = true;
4046
- const body = resolveBody(field.endpoint.body || {}, values, fieldStates);
4046
+ const body = resolveBody$1(field.endpoint.body || {}, values, fieldStates);
4047
4047
  setLoading(true);
4048
4048
  setError("");
4049
4049
  fetchViaEventBus(eventBus, field.endpoint.service, field.endpoint.url, field.endpoint.method, body).then((data) => {
@@ -4497,7 +4497,7 @@ function useReactiveEndpoints({ fields, fieldStates, setFieldState, eventBus, ti
4497
4497
  setFieldState(field.name, { loading: true, error: null });
4498
4498
  const startTime = Date.now();
4499
4499
  try {
4500
- const resolvedBody = field.endpoint.body ? resolveBody(field.endpoint.body, formValues, fieldStates) : void 0;
4500
+ const resolvedBody = field.endpoint.body ? resolveBody$1(field.endpoint.body, formValues, fieldStates) : void 0;
4501
4501
  const params = field.endpoint.params ? resolveParams(field.endpoint.params, formValues, fieldStates) : {};
4502
4502
  const requestBody = resolvedBody ?? (Object.keys(params).length > 0 ? params : void 0);
4503
4503
  if (eventBus) {
@@ -4772,7 +4772,7 @@ function useReactiveForm(props) {
4772
4772
  const handleSubmit = async () => {
4773
4773
  if (isSubmitting) return;
4774
4774
  setIsSubmitting(true);
4775
- const resolvedPayload = resolveBody(submit.payload_map, values, fieldStates);
4775
+ const resolvedPayload = resolveBody$1(submit.payload_map, values, fieldStates);
4776
4776
  if (eventBus) {
4777
4777
  try {
4778
4778
  const data = await fetchViaEventBus(
@@ -10865,6 +10865,7 @@ const Drawer = ({
10865
10865
  size = DRAWER_SIZES.RESPONSIVE,
10866
10866
  fixedSize = 400,
10867
10867
  responsivePercentage = 80,
10868
+ mobileSheet = false,
10868
10869
  title,
10869
10870
  headerExtra,
10870
10871
  showCloseButton = true,
@@ -10947,11 +10948,13 @@ const Drawer = ({
10947
10948
  `${COMPONENT_PREFIX}drawer--${size}`,
10948
10949
  isOpen && `${COMPONENT_PREFIX}drawer--open`,
10949
10950
  isMobile && `${COMPONENT_PREFIX}drawer--mobile`,
10951
+ mobileSheet && `${COMPONENT_PREFIX}drawer--sheet`,
10950
10952
  className
10951
10953
  ].filter(Boolean).join(" ");
10952
10954
  const overlayClasses = [
10953
10955
  `${COMPONENT_PREFIX}drawer-overlay`,
10954
- isOpen && showOverlay && `${COMPONENT_PREFIX}drawer-overlay--visible`
10956
+ isOpen && showOverlay && `${COMPONENT_PREFIX}drawer-overlay--visible`,
10957
+ mobileSheet && `${COMPONENT_PREFIX}drawer-overlay--sheet`
10955
10958
  ].filter(Boolean).join(" ");
10956
10959
  const getDrawerStyles = () => {
10957
10960
  if (isMobile) {
@@ -13058,36 +13061,45 @@ const Badge = ({
13058
13061
  };
13059
13062
  Badge.displayName = "LumiBadge";
13060
13063
 
13064
+ function fieldOptions(field) {
13065
+ return field.uiProps?.options;
13066
+ }
13067
+ function renderFieldValue(field, row) {
13068
+ const value = row[field.key];
13069
+ const options = fieldOptions(field);
13070
+ const opt = options?.find((o) => String(o.value) === String(value));
13071
+ if (field.moleculeType === "BADGE") {
13072
+ if (value == null || value === "") return null;
13073
+ return createElement(Badge, { color: opt?.color, children: opt?.label ?? String(value) });
13074
+ }
13075
+ if (field.moleculeType === "INPUT_CURRENCY") {
13076
+ if (value == null || value === "") return null;
13077
+ const cp = field.uiProps ?? {};
13078
+ return createElement(CurrencyDisplay, {
13079
+ value,
13080
+ showCode: cp.showCode ?? true,
13081
+ showSymbol: cp.showSymbol ?? true,
13082
+ currency: cp.currency ?? { decimalPlaces: 0 },
13083
+ align: field.align ?? "right",
13084
+ size: cp.size ?? "md"
13085
+ });
13086
+ }
13087
+ if (field.formatValue) return field.formatValue(value, row);
13088
+ if (opt) return opt.label;
13089
+ return value;
13090
+ }
13091
+ function hasFieldValue(field, row) {
13092
+ const value = row[field.key];
13093
+ return value != null && value !== "";
13094
+ }
13095
+
13061
13096
  function mapFieldsToTableColumns(fields) {
13062
13097
  return fields.filter((field) => field.showInTable !== false).map((field) => {
13063
13098
  let width = field.columnWidth;
13064
13099
  if (field.fixed && typeof field.columnWidth === "number") {
13065
13100
  width = `${field.columnWidth}px`;
13066
13101
  }
13067
- const options = field.uiProps?.options;
13068
- const build = (row) => {
13069
- const value = row[field.key];
13070
- const opt = options?.find((o) => String(o.value) === String(value));
13071
- if (field.moleculeType === "BADGE") {
13072
- if (value == null || value === "") return null;
13073
- return createElement(Badge, { color: opt?.color, children: opt?.label ?? String(value) });
13074
- }
13075
- if (field.moleculeType === "INPUT_CURRENCY") {
13076
- if (value == null || value === "") return null;
13077
- const cp = field.uiProps ?? {};
13078
- return createElement(CurrencyDisplay, {
13079
- value,
13080
- showCode: cp.showCode ?? true,
13081
- showSymbol: cp.showSymbol ?? true,
13082
- currency: cp.currency ?? { decimalPlaces: 0 },
13083
- align: field.align ?? "right",
13084
- size: cp.size ?? "md"
13085
- });
13086
- }
13087
- if (field.formatValue) return field.formatValue(value, row);
13088
- if (opt) return opt.label;
13089
- return value;
13090
- };
13102
+ const build = (row) => renderFieldValue(field, row);
13091
13103
  return {
13092
13104
  key: field.key,
13093
13105
  title: field.label,
@@ -13118,10 +13130,201 @@ function mapFieldsToFormFields(fields, mode) {
13118
13130
  }));
13119
13131
  }
13120
13132
 
13133
+ const CLASS$e = `${COMPONENT_PREFIX}field-value`;
13134
+ const FieldValue = ({
13135
+ label,
13136
+ children,
13137
+ layout = "inline",
13138
+ className
13139
+ }) => /* @__PURE__ */ jsxs("div", { className: [CLASS$e, `${CLASS$e}--${layout}`, className].filter(Boolean).join(" "), children: [
13140
+ /* @__PURE__ */ jsx("span", { className: `${CLASS$e}__label`, children: label }),
13141
+ /* @__PURE__ */ jsx("span", { className: `${CLASS$e}__value`, children })
13142
+ ] });
13143
+ FieldValue.displayName = "FieldValue";
13144
+
13145
+ const CLASS$d = `${COMPONENT_PREFIX}record-card`;
13146
+ const RecordCard = ({
13147
+ title,
13148
+ summary,
13149
+ children,
13150
+ actions,
13151
+ open = false,
13152
+ onToggle,
13153
+ ariaLabel,
13154
+ className
13155
+ }) => {
13156
+ const cuerpoId = useId();
13157
+ return /* @__PURE__ */ jsxs("div", { className: [CLASS$d, open ? `${CLASS$d}--open` : "", className].filter(Boolean).join(" "), children: [
13158
+ /* @__PURE__ */ jsxs(
13159
+ "button",
13160
+ {
13161
+ type: "button",
13162
+ className: `${CLASS$d}__header`,
13163
+ "aria-expanded": open,
13164
+ "aria-controls": cuerpoId,
13165
+ "aria-label": ariaLabel,
13166
+ onClick: onToggle,
13167
+ children: [
13168
+ /* @__PURE__ */ jsxs("span", { className: `${CLASS$d}__heading`, children: [
13169
+ /* @__PURE__ */ jsx("span", { className: `${CLASS$d}__title`, children: title }),
13170
+ summary && /* @__PURE__ */ jsx("span", { className: `${CLASS$d}__summary`, children: summary })
13171
+ ] }),
13172
+ /* @__PURE__ */ jsx(
13173
+ Icon,
13174
+ {
13175
+ type: open ? "chevron-up" : "chevron-down",
13176
+ width: 18,
13177
+ height: 18,
13178
+ className: `${CLASS$d}__chevron`,
13179
+ "aria-hidden": true
13180
+ }
13181
+ )
13182
+ ]
13183
+ }
13184
+ ),
13185
+ open && /* @__PURE__ */ jsxs("div", { className: `${CLASS$d}__body`, id: cuerpoId, children: [
13186
+ children,
13187
+ actions && /* @__PURE__ */ jsx("div", { className: `${CLASS$d}__actions`, children: actions })
13188
+ ] })
13189
+ ] });
13190
+ };
13191
+ RecordCard.displayName = "RecordCard";
13192
+
13193
+ const CLASS$c = `${COMPONENT_PREFIX}crud-cards`;
13194
+ function summaryFields(fields) {
13195
+ const visibles = fields.filter((f) => f.showInTable !== false);
13196
+ const marcados = visibles.filter((f) => f.summary);
13197
+ return marcados.length > 0 ? marcados : visibles.slice(0, 3);
13198
+ }
13199
+ function CardList({
13200
+ fields,
13201
+ rows,
13202
+ rowKey,
13203
+ buildOptions,
13204
+ loading = false,
13205
+ emptyText = "No hay registros"
13206
+ }) {
13207
+ const [abierta, setAbierta] = useState(null);
13208
+ const resumen = summaryFields(fields);
13209
+ const claveResumen = new Set(resumen.map((f) => f.key));
13210
+ const cuerpo = fields.filter((f) => f.showInTable !== false && !claveResumen.has(f.key));
13211
+ if (loading && rows.length === 0) {
13212
+ return /* @__PURE__ */ jsx("div", { className: `${CLASS$c}__estado`, children: "Cargando..." });
13213
+ }
13214
+ if (rows.length === 0) {
13215
+ return /* @__PURE__ */ jsx("div", { className: `${CLASS$c}__estado`, children: emptyText });
13216
+ }
13217
+ const [principal, ...secundarios] = resumen;
13218
+ return /* @__PURE__ */ jsx("div", { className: CLASS$c, children: rows.map((row) => {
13219
+ const key = rowKey(row);
13220
+ const opciones = buildOptions?.(row) ?? [];
13221
+ const titulo = principal ? renderFieldValue(principal, row) : key;
13222
+ return /* @__PURE__ */ jsx(
13223
+ RecordCard,
13224
+ {
13225
+ open: abierta === key,
13226
+ onToggle: () => setAbierta((actual) => actual === key ? null : key),
13227
+ ariaLabel: principal ? `${principal.label}: ${String(row[principal.key] ?? "")}` : void 0,
13228
+ title: titulo,
13229
+ summary: secundarios.length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: secundarios.map((f) => /* @__PURE__ */ jsx(React.Fragment, { children: renderFieldValue(f, row) }, f.key)) }) : void 0,
13230
+ actions: opciones.length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: opciones.map((o) => /* @__PURE__ */ jsxs(
13231
+ "button",
13232
+ {
13233
+ type: "button",
13234
+ className: [
13235
+ `${CLASS$c}__accion`,
13236
+ o.disabled && o.disabledReason ? "is-con-motivo" : ""
13237
+ ].filter(Boolean).join(" "),
13238
+ disabled: o.disabled,
13239
+ onClick: () => void o.onClick(),
13240
+ children: [
13241
+ /* @__PURE__ */ jsx("span", { children: o.label }),
13242
+ o.disabled && o.disabledReason && /* @__PURE__ */ jsx("span", { className: `${CLASS$c}__motivo`, children: o.disabledReason })
13243
+ ]
13244
+ },
13245
+ o.label
13246
+ )) }) : void 0,
13247
+ children: cuerpo.map(
13248
+ (f) => hasFieldValue(f, row) ? /* @__PURE__ */ jsx(FieldValue, { label: f.label, children: renderFieldValue(f, row) }, f.key) : null
13249
+ )
13250
+ },
13251
+ key
13252
+ );
13253
+ }) });
13254
+ }
13255
+ CardList.displayName = "CardList";
13256
+
13257
+ const CLASS$b = `${COMPONENT_PREFIX}crud-scroll-end`;
13258
+ const MARGEN = 24;
13259
+ const SELECTOR_CRUD = `.${COMPONENT_PREFIX}table-container, .${COMPONENT_PREFIX}crud-cards`;
13260
+ const ScrollToEnd = ({
13261
+ hostRef,
13262
+ selector = SELECTOR_CRUD,
13263
+ dep,
13264
+ label = "Ir al final de la lista"
13265
+ }) => {
13266
+ const [visible, setVisible] = useState(false);
13267
+ const scrollerRef = useRef(null);
13268
+ useEffect(() => {
13269
+ const host = hostRef.current;
13270
+ if (!host) return;
13271
+ const scroller = host.querySelector(selector) ?? host;
13272
+ scrollerRef.current = scroller;
13273
+ if (!scroller) {
13274
+ setVisible(false);
13275
+ return;
13276
+ }
13277
+ const revisar = () => {
13278
+ const s = scrollerRef.current;
13279
+ if (!s) return;
13280
+ setVisible(s.scrollHeight - s.clientHeight - s.scrollTop > MARGEN);
13281
+ };
13282
+ revisar();
13283
+ scroller.addEventListener("scroll", revisar, { passive: true });
13284
+ let observador;
13285
+ if (typeof ResizeObserver !== "undefined") {
13286
+ observador = new ResizeObserver(revisar);
13287
+ observador.observe(scroller);
13288
+ if (scroller.firstElementChild) observador.observe(scroller.firstElementChild);
13289
+ }
13290
+ return () => {
13291
+ scroller.removeEventListener("scroll", revisar);
13292
+ observador?.disconnect();
13293
+ };
13294
+ }, [hostRef, selector, dep]);
13295
+ const alFinal = useCallback(() => {
13296
+ const s = scrollerRef.current;
13297
+ if (!s) return;
13298
+ s.scrollTo({ top: s.scrollHeight, behavior: "smooth" });
13299
+ }, []);
13300
+ if (!visible) return null;
13301
+ return /* @__PURE__ */ jsx("button", { type: "button", className: CLASS$b, onClick: alFinal, "aria-label": label, title: label, children: /* @__PURE__ */ jsx(Icon, { type: "chevron-down", width: 18, height: 18, "aria-hidden": true }) });
13302
+ };
13303
+ ScrollToEnd.displayName = "ScrollToEnd";
13304
+
13121
13305
  function calculateTotalPages(totalRecords, limit) {
13122
13306
  return Math.ceil(totalRecords / limit);
13123
13307
  }
13124
13308
 
13309
+ const useAnchoPropio = () => {
13310
+ const ref = useRef(null);
13311
+ const [ancho, setAncho] = useState(null);
13312
+ useEffect(() => {
13313
+ const nodo = ref.current;
13314
+ if (!nodo) return;
13315
+ if (typeof ResizeObserver === "undefined") {
13316
+ setAncho(nodo.getBoundingClientRect().width);
13317
+ return;
13318
+ }
13319
+ const observador = new ResizeObserver((entradas) => {
13320
+ const w = entradas[0]?.contentRect.width;
13321
+ if (typeof w === "number") setAncho(w);
13322
+ });
13323
+ observador.observe(nodo);
13324
+ return () => observador.disconnect();
13325
+ }, []);
13326
+ return [ref, ancho];
13327
+ };
13125
13328
  const useIsMobile = () => {
13126
13329
  const [isMobile, setIsMobile] = useState(false);
13127
13330
  useEffect(() => {
@@ -13161,6 +13364,8 @@ function Crud({
13161
13364
  defaultFilters,
13162
13365
  tableHeight,
13163
13366
  tableScroll,
13367
+ layout = "auto",
13368
+ cardsBelow = 768,
13164
13369
  hidePagination = false,
13165
13370
  formDrawerWidth = "80%",
13166
13371
  formColumns = 2,
@@ -13265,6 +13470,69 @@ function Crud({
13265
13470
  }
13266
13471
  return columns;
13267
13472
  }, [renderByFields, isMobile, tableScroll?.x]);
13473
+ const buildRowOptions = useCallback((row) => {
13474
+ const menuOptions = [];
13475
+ if (rowActionTypes.includes("edit") && !disabledActions?.edit && onEdit) {
13476
+ menuOptions.push({
13477
+ label: labels?.editButton || "Editar",
13478
+ icon: "edit",
13479
+ onClick: () => {
13480
+ openFormDrawer("edit", row);
13481
+ }
13482
+ });
13483
+ }
13484
+ if (rowActionTypes.includes("delete") && !disabledActions?.delete && onDelete) {
13485
+ menuOptions.push({
13486
+ label: labels?.deleteButton || "Eliminar",
13487
+ icon: "trash",
13488
+ onClick: () => {
13489
+ openConfirmDrawer("delete", void 0, [row]);
13490
+ }
13491
+ });
13492
+ }
13493
+ if (rowActionTypes.includes("view") && !disabledActions?.view) {
13494
+ menuOptions.push({
13495
+ label: labels?.viewButton || "Ver",
13496
+ icon: "eye",
13497
+ onClick: async () => {
13498
+ if (onView) {
13499
+ await onView([row]);
13500
+ }
13501
+ openFormDrawer("view", row);
13502
+ }
13503
+ });
13504
+ }
13505
+ rowActions?.forEach((action) => {
13506
+ if (action.show && !action.show(row)) return;
13507
+ menuOptions.push({
13508
+ label: action.label,
13509
+ icon: action.icon,
13510
+ onClick: () => {
13511
+ if (action.drawerId) {
13512
+ openCustomDrawer(action.drawerId, row);
13513
+ }
13514
+ if (action.onClick) {
13515
+ action.onClick(row);
13516
+ }
13517
+ },
13518
+ disabled: action.disabled ? action.disabled(row) : false,
13519
+ // SPEC-090 T3 — una acción apagada sin motivo es indistinguible de una rota.
13520
+ disabledReason: action.disabledReason?.(row)
13521
+ });
13522
+ });
13523
+ return menuOptions;
13524
+ }, [
13525
+ rowActionTypes,
13526
+ disabledActions,
13527
+ onEdit,
13528
+ onDelete,
13529
+ onView,
13530
+ labels,
13531
+ openFormDrawer,
13532
+ openConfirmDrawer,
13533
+ openCustomDrawer,
13534
+ rowActions
13535
+ ]);
13268
13536
  const tableColumns = useMemo(() => {
13269
13537
  if (!showRowActions) return baseTableColumns;
13270
13538
  const actionsColumn = {
@@ -13276,55 +13544,7 @@ function Crud({
13276
13544
  cellType: "CHILDREN",
13277
13545
  dataSource: {
13278
13546
  build: (row) => {
13279
- const menuOptions = [];
13280
- if (rowActionTypes.includes("edit") && !disabledActions?.edit && onEdit) {
13281
- menuOptions.push({
13282
- label: labels?.editButton || "Editar",
13283
- icon: "edit",
13284
- onClick: () => {
13285
- openFormDrawer("edit", row);
13286
- }
13287
- });
13288
- }
13289
- if (rowActionTypes.includes("delete") && !disabledActions?.delete && onDelete) {
13290
- menuOptions.push({
13291
- label: labels?.deleteButton || "Eliminar",
13292
- icon: "trash",
13293
- onClick: () => {
13294
- openConfirmDrawer("delete", void 0, [row]);
13295
- }
13296
- });
13297
- }
13298
- if (rowActionTypes.includes("view") && !disabledActions?.view) {
13299
- menuOptions.push({
13300
- label: labels?.viewButton || "Ver",
13301
- icon: "eye",
13302
- onClick: async () => {
13303
- if (onView) {
13304
- await onView([row]);
13305
- }
13306
- openFormDrawer("view", row);
13307
- }
13308
- });
13309
- }
13310
- rowActions?.forEach((action) => {
13311
- if (action.show && !action.show(row)) return;
13312
- menuOptions.push({
13313
- label: action.label,
13314
- icon: action.icon,
13315
- onClick: () => {
13316
- if (action.drawerId) {
13317
- openCustomDrawer(action.drawerId, row);
13318
- }
13319
- if (action.onClick) {
13320
- action.onClick(row);
13321
- }
13322
- },
13323
- disabled: action.disabled ? action.disabled(row) : false,
13324
- // SPEC-090 T3 — una acción apagada sin motivo es indistinguible de una rota.
13325
- disabledReason: action.disabledReason?.(row)
13326
- });
13327
- });
13547
+ const menuOptions = buildRowOptions(row);
13328
13548
  if (menuOptions.length === 0) return null;
13329
13549
  return /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", width: "100%" }, children: /* @__PURE__ */ jsx(
13330
13550
  DropdownMenu,
@@ -13347,20 +13567,7 @@ function Crud({
13347
13567
  }
13348
13568
  };
13349
13569
  return [...baseTableColumns, actionsColumn];
13350
- }, [
13351
- baseTableColumns,
13352
- showRowActions,
13353
- rowActionTypes,
13354
- disabledActions,
13355
- labels,
13356
- onEdit,
13357
- onDelete,
13358
- onView,
13359
- rowActions,
13360
- openFormDrawer,
13361
- openConfirmDrawer,
13362
- openCustomDrawer
13363
- ]);
13570
+ }, [baseTableColumns, showRowActions, buildRowOptions]);
13364
13571
  const formFields = useMemo(() => {
13365
13572
  return mapFieldsToFormFields(renderByFields, formMode);
13366
13573
  }, [renderByFields, formMode]);
@@ -13557,6 +13764,10 @@ function Crud({
13557
13764
  return "\xBFEst\xE1 seguro que desea realizar esta acci\xF3n?";
13558
13765
  }
13559
13766
  };
13767
+ const [refContenedor, anchoPropio] = useAnchoPropio();
13768
+ const enTarjetas = layout === "cards" || // Mientras no se ha medido (`null`) se mantiene la tabla: pintar tarjetas y saltar a tabla un
13769
+ // instante después es el parpadeo que se acaba de quitar en otro sitio.
13770
+ layout === "auto" && anchoPropio !== null && anchoPropio < cardsBelow;
13560
13771
  const crudClasses = [
13561
13772
  `${COMPONENT_PREFIX}crud`,
13562
13773
  loading && `${COMPONENT_PREFIX}crud--loading`,
@@ -13573,24 +13784,43 @@ function Crud({
13573
13784
  showLabels: false
13574
13785
  }
13575
13786
  ) }),
13576
- !formOnly && /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX}crud__table`, children: /* @__PURE__ */ jsx(
13577
- Table,
13787
+ !formOnly && /* @__PURE__ */ jsxs(
13788
+ "div",
13578
13789
  {
13579
- dataSource,
13580
- columns: tableColumns,
13581
- selectable: showActionBar && actionBarMode === "full",
13582
- selectedRowKeys: selectedKeys,
13583
- onSelectionChange: handleSelectionChange,
13584
- rowKey: getRowKey,
13585
- loading,
13586
- height: tableHeight,
13587
- scroll: tableScroll,
13588
- compact: size === "small",
13589
- bordered: true,
13590
- hoverable: true,
13591
- emptyText: labels?.emptyText
13790
+ className: `${COMPONENT_PREFIX}crud__data${enTarjetas ? ` ${COMPONENT_PREFIX}crud__data--cards` : ""}`,
13791
+ children: [
13792
+ /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX}crud__table`, ref: refContenedor, children: enTarjetas ? /* @__PURE__ */ jsx(
13793
+ CardList,
13794
+ {
13795
+ fields: renderByFields,
13796
+ rows: dataSource,
13797
+ rowKey: getRowKey,
13798
+ buildOptions: showRowActions ? buildRowOptions : void 0,
13799
+ loading,
13800
+ emptyText: labels?.emptyText
13801
+ }
13802
+ ) : /* @__PURE__ */ jsx(
13803
+ Table,
13804
+ {
13805
+ dataSource,
13806
+ columns: tableColumns,
13807
+ selectable: showActionBar && actionBarMode === "full",
13808
+ selectedRowKeys: selectedKeys,
13809
+ onSelectionChange: handleSelectionChange,
13810
+ rowKey: getRowKey,
13811
+ loading,
13812
+ height: tableHeight,
13813
+ scroll: tableScroll,
13814
+ compact: size === "small",
13815
+ bordered: true,
13816
+ hoverable: true,
13817
+ emptyText: labels?.emptyText
13818
+ }
13819
+ ) }),
13820
+ /* @__PURE__ */ jsx(ScrollToEnd, { hostRef: refContenedor, dep: `${enTarjetas}:${dataSource.length}:${loading}` })
13821
+ ]
13592
13822
  }
13593
- ) }),
13823
+ ),
13594
13824
  !formOnly && !filters.all_data && !hidePagination && /* @__PURE__ */ jsx("div", { className: `${COMPONENT_PREFIX}crud__pagination`, children: /* @__PURE__ */ jsx(
13595
13825
  Pagination,
13596
13826
  {
@@ -13655,6 +13885,7 @@ function Crud({
13655
13885
  position: "right",
13656
13886
  size: "responsive",
13657
13887
  responsivePercentage: 30,
13888
+ mobileSheet: true,
13658
13889
  className: `${COMPONENT_PREFIX}crud__confirm-drawer`,
13659
13890
  children: /* @__PURE__ */ jsxs("div", { className: `${COMPONENT_PREFIX}crud__confirm-content`, children: [
13660
13891
  /* @__PURE__ */ jsx("p", { className: `${COMPONENT_PREFIX}crud__confirm-message`, children: getConfirmMessage() }),
@@ -13703,6 +13934,60 @@ function Crud({
13703
13934
  }
13704
13935
  Crud.displayName = "Crud";
13705
13936
 
13937
+ const CLASS$a = "px-chat-reactive-crud__chat-link";
13938
+ function Burbuja() {
13939
+ return /* @__PURE__ */ jsx(
13940
+ "svg",
13941
+ {
13942
+ width: 18,
13943
+ height: 18,
13944
+ viewBox: "0 0 24 24",
13945
+ fill: "none",
13946
+ stroke: "currentColor",
13947
+ strokeWidth: 2,
13948
+ strokeLinecap: "round",
13949
+ strokeLinejoin: "round",
13950
+ "aria-hidden": true,
13951
+ children: /* @__PURE__ */ jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
13952
+ }
13953
+ );
13954
+ }
13955
+ const ChatLinkCell = ({
13956
+ targets,
13957
+ eventBus
13958
+ }) => {
13959
+ if (targets.length === 0) return null;
13960
+ const abrir = (id) => eventBus?.emit(CHAT_EVENT.OPEN_CHAT, { chatId: id, closed: false });
13961
+ if (targets.length === 1) {
13962
+ const t = targets[0];
13963
+ const texto = t.label ? `Abrir chat ${t.label}` : "Abrir chat";
13964
+ return /* @__PURE__ */ jsx("button", { type: "button", className: CLASS$a, "aria-label": texto, title: texto, onClick: () => abrir(t.id), children: /* @__PURE__ */ jsx(Burbuja, {}) });
13965
+ }
13966
+ return /* @__PURE__ */ jsx(
13967
+ DropdownMenu,
13968
+ {
13969
+ options: targets.map((t) => ({
13970
+ label: t.label ?? "Chat",
13971
+ icon: "message-square",
13972
+ onClick: () => abrir(t.id)
13973
+ })),
13974
+ trigger: /* @__PURE__ */ jsx(
13975
+ "button",
13976
+ {
13977
+ type: "button",
13978
+ className: CLASS$a,
13979
+ "aria-label": `Abrir chat (${targets.length} conversaciones)`,
13980
+ title: "Abrir chat",
13981
+ children: /* @__PURE__ */ jsx(Burbuja, {})
13982
+ }
13983
+ ),
13984
+ position: "bottom-left",
13985
+ usePortal: true
13986
+ }
13987
+ );
13988
+ };
13989
+ ChatLinkCell.displayName = "ChatLinkCell";
13990
+
13706
13991
  function buildCrudYupSchema(fields) {
13707
13992
  const shape = {};
13708
13993
  for (const f of fields) {
@@ -13783,8 +14068,21 @@ function unwrap$3(raw) {
13783
14068
  }
13784
14069
  return raw;
13785
14070
  }
13786
- async function loadOptions(eventBus, ep) {
13787
- const raw = await fetchViaEventBus(eventBus, ep.service, ep.url, ep.method, ep.body ?? {});
14071
+ function resolveBody(body, ctx) {
14072
+ if (!body) return {};
14073
+ if (!ctx) return body;
14074
+ return Object.fromEntries(
14075
+ Object.entries(body).map(([k, v]) => {
14076
+ if (typeof v === "string" && v.startsWith("$")) {
14077
+ const key = v.slice(1);
14078
+ return [k, key in ctx ? ctx[key] : v];
14079
+ }
14080
+ return [k, v];
14081
+ })
14082
+ );
14083
+ }
14084
+ async function loadOptions(eventBus, ep, ctx) {
14085
+ const raw = await fetchViaEventBus(eventBus, ep.service, ep.url, ep.method, resolveBody(ep.body, ctx));
13788
14086
  let data = unwrap$3(raw);
13789
14087
  if (ep.response_path && data && typeof data === "object" && !Array.isArray(data)) {
13790
14088
  data = data[ep.response_path];
@@ -13860,7 +14158,7 @@ function useReactiveCrud(config, eventBus) {
13860
14158
  const loadList = useCallback(async () => {
13861
14159
  if (!eventBus) return;
13862
14160
  const myReq = ++reqIdRef.current;
13863
- setState((s) => ({ ...s, loading: true, error: null }));
14161
+ setState((s) => s.rows.length === 0 ? { ...s, loading: true, error: null } : { ...s, error: null });
13864
14162
  try {
13865
14163
  const { service, url, method } = config.data.list;
13866
14164
  const raw = await fetchViaEventBus(eventBus, service, url, method, {
@@ -14111,7 +14409,7 @@ function ActionFormDrawer({ action, row, idField, eventBus, onExecute, onClose }
14111
14409
  void Promise.all(
14112
14410
  toLoad.map(async (f) => {
14113
14411
  try {
14114
- const opts = await loadOptions(eventBus, f.optionsEndpoint);
14412
+ const opts = await loadOptions(eventBus, f.optionsEndpoint, { ...row, id: row[idField] });
14115
14413
  return [f.name, opts];
14116
14414
  } catch {
14117
14415
  return [f.name, []];
@@ -14800,6 +15098,7 @@ function unwrap$1(raw) {
14800
15098
  }
14801
15099
  return raw;
14802
15100
  }
15101
+ const DETALLE_OCULTOS = /* @__PURE__ */ new Set(["LOCATION", "CHAT_LINK", "FILE"]);
14803
15102
  function DetailDrawer({ row, config, eventBus, onClose, loadedOptions }) {
14804
15103
  const detail = config.detail;
14805
15104
  const [files, setFiles] = useState([]);
@@ -14898,7 +15197,7 @@ function DetailDrawer({ row, config, eventBus, onClose, loadedOptions }) {
14898
15197
  }
14899
15198
  };
14900
15199
  return /* @__PURE__ */ jsx(Drawer$1, { isOpen: true, onClose, title, placement: "right", children: /* @__PURE__ */ jsxs("div", { className: "px-chat-reactive-crud-detail", children: [
14901
- /* @__PURE__ */ jsx("dl", { className: "px-chat-reactive-crud-detail__fields", children: config.fields.map((f) => {
15200
+ /* @__PURE__ */ jsx("dl", { className: "px-chat-reactive-crud-detail__fields", children: config.fields.filter((f) => !DETALLE_OCULTOS.has(f.moleculeType)).map((f) => {
14902
15201
  const { node, copyText } = renderField(f);
14903
15202
  return /* @__PURE__ */ jsxs("div", { className: "px-chat-reactive-crud-detail__row", children: [
14904
15203
  /* @__PURE__ */ jsx("dt", { className: "px-chat-reactive-crud-detail__label", children: f.label }),
@@ -15560,35 +15859,13 @@ const LocationField = ({
15560
15859
  };
15561
15860
  LocationField.displayName = "LocationField";
15562
15861
 
15563
- function chatLinkButton(id, eventBus, label) {
15564
- return createElement(
15565
- "button",
15566
- {
15567
- key: label ?? id,
15568
- type: "button",
15569
- className: "px-chat-reactive-crud__chat-link",
15570
- "aria-label": label ? `Abrir chat ${label}` : "Abrir chat",
15571
- title: label ?? "Abrir chat",
15572
- onClick: () => eventBus?.emit(CHAT_EVENT.OPEN_CHAT, { chatId: id, closed: false })
15573
- },
15574
- createElement(
15575
- "svg",
15576
- { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" },
15577
- createElement("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
15578
- ),
15579
- label ? createElement("span", { className: "px-chat-reactive-crud__chat-link-label" }, label) : null
15580
- );
15581
- }
15582
15862
  function chatLinkFormatter(field, eventBus) {
15583
15863
  const sources = field.chats;
15584
15864
  return (value, row) => {
15585
15865
  const r = row;
15586
- if (sources && sources.length) {
15587
- const btns = sources.map((s) => ({ id: r ? r[s.field] : void 0, label: s.label })).filter((s) => s.id != null && s.id !== "").map((s) => chatLinkButton(String(s.id), eventBus, s.label));
15588
- return btns.length ? createElement("div", { className: "px-chat-reactive-crud__chat-links" }, btns) : null;
15589
- }
15590
- const id = value != null && value !== "" ? String(value) : "";
15591
- return id ? chatLinkButton(id, eventBus) : null;
15866
+ const targets = sources?.length ? sources.map((s) => ({ id: r ? r[s.field] : void 0, label: s.label })).filter((s) => s.id != null && s.id !== "").map((s) => ({ id: String(s.id), label: s.label })) : value != null && value !== "" ? [{ id: String(value) }] : [];
15867
+ if (!targets.length) return null;
15868
+ return createElement(ChatLinkCell, { targets, eventBus });
15592
15869
  };
15593
15870
  }
15594
15871
  function toRenderField(f, loaded, eventBus, mapsApiKey) {
@@ -15627,6 +15904,8 @@ function toRenderField(f, loaded, eventBus, mapsApiKey) {
15627
15904
  // FILE/CHAT_LINK solo son columnas → INPUT (el render lo define formatValue/build).
15628
15905
  moleculeType: f.moleculeType === "FILE" || isChatLink ? "INPUT" : f.moleculeType,
15629
15906
  showInTable: f.showInTable,
15907
+ summary: f.summary,
15908
+ // SPEC-093
15630
15909
  showInForm: f.showInForm,
15631
15910
  showInModes: f.showInModes,
15632
15911
  required: f.required,
@@ -15756,6 +16035,8 @@ function ReactiveCrud({ config, eventBus, autoOpenCreate, prefill, onCreated, on
15756
16035
  loading: crud.loading,
15757
16036
  filters: { skip: crud.skip, limit: crud.pageSize, all_data: false, filters: crud.filters },
15758
16037
  tableScroll: config.tableScroll,
16038
+ layout: config.layout,
16039
+ cardsBelow: config.cardsBelow,
15759
16040
  validationSchema,
15760
16041
  getRowKey: (row) => String(row[config.idField]),
15761
16042
  onCreate: config.data.create ? async (rows) => {
@@ -16025,12 +16306,18 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
16025
16306
  "button",
16026
16307
  {
16027
16308
  type: "button",
16028
- className: `px-chat-crud-item__action${a.intent === "danger" ? " is-danger" : ""}`,
16309
+ className: [
16310
+ "px-chat-crud-item__action",
16311
+ a.intent === "danger" ? "is-danger" : "",
16312
+ disabled && a.disabledReason ? "is-con-motivo" : ""
16313
+ ].filter(Boolean).join(" "),
16029
16314
  disabled,
16030
- title: disabled ? a.disabledReason : void 0,
16031
16315
  onClick: () => a.form ? setActiveAction({ action: a, row }) : crud.runEndpoints(a.endpoints ?? [a.endpoint], { ...row, id: row[config.idField] }),
16032
16316
  children: [
16033
- /* @__PURE__ */ jsx("span", { children: a.label }),
16317
+ /* @__PURE__ */ jsxs("span", { className: "px-chat-crud-item__action-texts", children: [
16318
+ /* @__PURE__ */ jsx("span", { children: a.label }),
16319
+ disabled && a.disabledReason && /* @__PURE__ */ jsx("span", { className: "px-chat-crud-item__action-reason", children: a.disabledReason })
16320
+ ] }),
16034
16321
  done && /* @__PURE__ */ jsx(Icon$1, { type: "check-circle", width: 18, height: 18, className: "px-chat-crud-item__done", "aria-label": "Hecho" })
16035
16322
  ]
16036
16323
  },
@@ -16665,6 +16952,7 @@ function ChatNavigator({ config, eventBus }) {
16665
16952
  useEffect(() => {
16666
16953
  void load();
16667
16954
  }, [load]);
16955
+ const listaRef = useRef(null);
16668
16956
  const loadRef = useRef(load);
16669
16957
  loadRef.current = load;
16670
16958
  useEffect(() => {
@@ -16712,8 +17000,6 @@ function ChatNavigator({ config, eventBus }) {
16712
17000
  };
16713
17001
  const page = Math.floor(skip / pageSize) + 1;
16714
17002
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
16715
- const canPrev = skip > 0;
16716
- const canNext = skip + pageSize < total;
16717
17003
  return /* @__PURE__ */ jsxs("div", { className: "px-chat-chat-navigator", children: [
16718
17004
  config.search && /* @__PURE__ */ jsxs("div", { className: "px-chat-chat-navigator__search", children: [
16719
17005
  /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "px-chat-chat-navigator__search-icon", children: [
@@ -16793,143 +17079,126 @@ function ChatNavigator({ config, eventBus }) {
16793
17079
  loading && /* @__PURE__ */ jsx("div", { className: "px-chat-chat-navigator__state", children: "Cargando conversaciones\u2026" }),
16794
17080
  error && !loading && /* @__PURE__ */ jsx("div", { className: "px-chat-chat-navigator__state px-chat-chat-navigator__state--error", children: error }),
16795
17081
  !loading && !error && items.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-chat-chat-navigator__state", children: labels.emptyText ?? "Sin conversaciones" }),
16796
- /* @__PURE__ */ jsx("ul", { className: "px-chat-chat-navigator__list", children: items.map((item) => {
16797
- const isRenaming = renamingId === item.id;
16798
- const displayTitle = item.title?.trim() || fallbackTitle(item);
16799
- return /* @__PURE__ */ jsxs("li", { className: "px-chat-chat-navigator__item", children: [
16800
- isRenaming ? /* @__PURE__ */ jsx(
16801
- "form",
16802
- {
16803
- className: "px-chat-chat-navigator__rename",
16804
- onSubmit: (e) => {
16805
- e.preventDefault();
16806
- void submitRename(item.id);
16807
- },
16808
- children: /* @__PURE__ */ jsx(
16809
- "input",
16810
- {
16811
- autoFocus: true,
16812
- className: "px-chat-chat-navigator__rename-input",
16813
- value: renameValue,
16814
- onChange: (e) => setRenameValue(e.target.value),
16815
- onBlur: () => void submitRename(item.id),
16816
- "aria-label": labels.renameTitle ?? "Nuevo t\xEDtulo"
16817
- }
16818
- )
16819
- }
16820
- ) : /* @__PURE__ */ jsxs("button", { type: "button", className: "px-chat-chat-navigator__open", onClick: () => open(item), children: [
16821
- /* @__PURE__ */ jsxs("span", { className: "px-chat-chat-navigator__title", children: [
16822
- displayTitle,
16823
- item.unread_proactive_count && item.unread_proactive_count >= 1 ? /* @__PURE__ */ jsx(
16824
- "span",
16825
- {
16826
- className: "px-chat-chat-navigator__badge-count",
16827
- "aria-label": `${item.unread_proactive_count} mensajes nuevos sin leer`,
16828
- title: `${item.unread_proactive_count} sin leer`,
16829
- children: item.unread_proactive_count >= 100 ? "100+" : item.unread_proactive_count
16830
- }
16831
- ) : null
16832
- ] }),
16833
- /* @__PURE__ */ jsxs("span", { className: "px-chat-chat-navigator__meta", children: [
16834
- item.agent_name ? /* @__PURE__ */ jsx("span", { className: "px-chat-chat-navigator__agent", children: item.agent_name }) : null,
16835
- /* @__PURE__ */ jsx("span", { className: "px-chat-chat-navigator__time", children: relativeTime(item.updated_date) }),
16836
- (() => {
16837
- const opt = item.rol_code ? (config.originActorOptions ?? []).find((o) => o.value === item.rol_code) : void 0;
16838
- if (!opt) return null;
16839
- const c = opt.color;
16840
- const nameField = config.originActorNameField;
16841
- const allyName = nameField ? item[nameField] : void 0;
16842
- const label = allyName ? String(allyName) : opt.label;
16843
- return /* @__PURE__ */ jsx(
16844
- "span",
16845
- {
16846
- className: "px-chat-chat-navigator__origin-badge",
16847
- style: c ? { color: c, background: `${c}22`, borderColor: `${c}55` } : void 0,
16848
- title: label,
16849
- children: label
16850
- }
16851
- );
16852
- })(),
16853
- (() => {
16854
- const field = config.tagField;
16855
- if (!field) return null;
16856
- const value = item[field];
16857
- if (!value) return null;
16858
- const opt = (config.tagOptions ?? []).find((o) => o.value === String(value));
16859
- if (!opt) return null;
16860
- const c = opt.color;
16861
- return /* @__PURE__ */ jsx(
16862
- "span",
17082
+ /* @__PURE__ */ jsxs("div", { className: "px-chat-chat-navigator__list-wrap", ref: listaRef, children: [
17083
+ /* @__PURE__ */ jsx("ul", { className: "px-chat-chat-navigator__list", children: items.map((item) => {
17084
+ const isRenaming = renamingId === item.id;
17085
+ const displayTitle = item.title?.trim() || fallbackTitle(item);
17086
+ return /* @__PURE__ */ jsxs("li", { className: "px-chat-chat-navigator__item", children: [
17087
+ isRenaming ? /* @__PURE__ */ jsx(
17088
+ "form",
17089
+ {
17090
+ className: "px-chat-chat-navigator__rename",
17091
+ onSubmit: (e) => {
17092
+ e.preventDefault();
17093
+ void submitRename(item.id);
17094
+ },
17095
+ children: /* @__PURE__ */ jsx(
17096
+ "input",
16863
17097
  {
16864
- className: "px-chat-chat-navigator__origin-badge",
16865
- style: c ? { color: c, background: `${c}22`, borderColor: `${c}55` } : void 0,
16866
- title: opt.label,
16867
- children: opt.label
17098
+ autoFocus: true,
17099
+ className: "px-chat-chat-navigator__rename-input",
17100
+ value: renameValue,
17101
+ onChange: (e) => setRenameValue(e.target.value),
17102
+ onBlur: () => void submitRename(item.id),
17103
+ "aria-label": labels.renameTitle ?? "Nuevo t\xEDtulo"
16868
17104
  }
16869
- );
16870
- })(),
16871
- item.service_status ? (() => {
16872
- const opt = (config.serviceStatusOptions ?? []).find(
16873
- (o) => o.value === item.service_status
16874
- );
16875
- const c = opt?.color;
16876
- return /* @__PURE__ */ jsx(
17105
+ )
17106
+ }
17107
+ ) : /* @__PURE__ */ jsxs("button", { type: "button", className: "px-chat-chat-navigator__open", onClick: () => open(item), children: [
17108
+ /* @__PURE__ */ jsxs("span", { className: "px-chat-chat-navigator__title", children: [
17109
+ displayTitle,
17110
+ item.unread_proactive_count && item.unread_proactive_count >= 1 ? /* @__PURE__ */ jsx(
16877
17111
  "span",
16878
17112
  {
16879
- className: "px-chat-chat-navigator__service-badge",
16880
- style: c ? { color: c, background: `${c}22`, borderColor: `${c}55` } : void 0,
16881
- children: opt?.label ?? item.service_status
17113
+ className: "px-chat-chat-navigator__badge-count",
17114
+ "aria-label": `${item.unread_proactive_count} mensajes nuevos sin leer`,
17115
+ title: `${item.unread_proactive_count} sin leer`,
17116
+ children: item.unread_proactive_count >= 100 ? "100+" : item.unread_proactive_count
16882
17117
  }
16883
- );
16884
- })() : null,
16885
- item.closed ? /* @__PURE__ */ jsx("span", { className: "px-chat-chat-navigator__badge", children: labels.closedBadge ?? "Cerrado" }) : null
16886
- ] })
16887
- ] }),
16888
- config.data.rename && !isRenaming && /* @__PURE__ */ jsx(
16889
- "button",
16890
- {
16891
- type: "button",
16892
- className: "px-chat-chat-navigator__rename-btn",
16893
- "aria-label": "Renombrar",
16894
- title: "Renombrar",
16895
- onClick: () => startRename(item),
16896
- children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
16897
- /* @__PURE__ */ jsx("path", { d: "M12 20h9" }),
16898
- /* @__PURE__ */ jsx("path", { d: "M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z" })
17118
+ ) : null
17119
+ ] }),
17120
+ /* @__PURE__ */ jsxs("span", { className: "px-chat-chat-navigator__meta", children: [
17121
+ item.agent_name ? /* @__PURE__ */ jsx("span", { className: "px-chat-chat-navigator__agent", children: item.agent_name }) : null,
17122
+ /* @__PURE__ */ jsx("span", { className: "px-chat-chat-navigator__time", children: relativeTime(item.updated_date) }),
17123
+ (() => {
17124
+ const opt = item.rol_code ? (config.originActorOptions ?? []).find((o) => o.value === item.rol_code) : void 0;
17125
+ if (!opt) return null;
17126
+ const c = opt.color;
17127
+ const nameField = config.originActorNameField;
17128
+ const allyName = nameField ? item[nameField] : void 0;
17129
+ const label = allyName ? String(allyName) : opt.label;
17130
+ return /* @__PURE__ */ jsx(
17131
+ "span",
17132
+ {
17133
+ className: "px-chat-chat-navigator__origin-badge",
17134
+ style: c ? { color: c, background: `${c}22`, borderColor: `${c}55` } : void 0,
17135
+ title: label,
17136
+ children: label
17137
+ }
17138
+ );
17139
+ })(),
17140
+ (() => {
17141
+ const field = config.tagField;
17142
+ if (!field) return null;
17143
+ const value = item[field];
17144
+ if (!value) return null;
17145
+ const opt = (config.tagOptions ?? []).find((o) => o.value === String(value));
17146
+ if (!opt) return null;
17147
+ const c = opt.color;
17148
+ return /* @__PURE__ */ jsx(
17149
+ "span",
17150
+ {
17151
+ className: "px-chat-chat-navigator__origin-badge",
17152
+ style: c ? { color: c, background: `${c}22`, borderColor: `${c}55` } : void 0,
17153
+ title: opt.label,
17154
+ children: opt.label
17155
+ }
17156
+ );
17157
+ })(),
17158
+ item.service_status ? (() => {
17159
+ const opt = (config.serviceStatusOptions ?? []).find(
17160
+ (o) => o.value === item.service_status
17161
+ );
17162
+ const c = opt?.color;
17163
+ return /* @__PURE__ */ jsx(
17164
+ "span",
17165
+ {
17166
+ className: "px-chat-chat-navigator__service-badge",
17167
+ style: c ? { color: c, background: `${c}22`, borderColor: `${c}55` } : void 0,
17168
+ children: opt?.label ?? item.service_status
17169
+ }
17170
+ );
17171
+ })() : null,
17172
+ item.closed ? /* @__PURE__ */ jsx("span", { className: "px-chat-chat-navigator__badge", children: labels.closedBadge ?? "Cerrado" }) : null
16899
17173
  ] })
16900
- }
16901
- )
16902
- ] }, item.id);
16903
- }) }),
16904
- total > pageSize && /* @__PURE__ */ jsxs("div", { className: "px-chat-chat-navigator__pager", children: [
16905
- /* @__PURE__ */ jsx(
16906
- "button",
16907
- {
16908
- type: "button",
16909
- className: "px-chat-chat-navigator__pager-btn",
16910
- disabled: !canPrev,
16911
- onClick: () => setSkip(Math.max(0, skip - pageSize)),
16912
- "aria-label": "P\xE1gina anterior",
16913
- children: "\u2039"
16914
- }
16915
- ),
16916
- /* @__PURE__ */ jsxs("span", { className: "px-chat-chat-navigator__pager-info", children: [
16917
- page,
16918
- " / ",
16919
- totalPages
16920
- ] }),
16921
- /* @__PURE__ */ jsx(
16922
- "button",
16923
- {
16924
- type: "button",
16925
- className: "px-chat-chat-navigator__pager-btn",
16926
- disabled: !canNext,
16927
- onClick: () => setSkip(skip + pageSize),
16928
- "aria-label": "P\xE1gina siguiente",
16929
- children: "\u203A"
16930
- }
16931
- )
17174
+ ] }),
17175
+ config.data.rename && !isRenaming && /* @__PURE__ */ jsx(
17176
+ "button",
17177
+ {
17178
+ type: "button",
17179
+ className: "px-chat-chat-navigator__rename-btn",
17180
+ "aria-label": "Renombrar",
17181
+ title: "Renombrar",
17182
+ onClick: () => startRename(item),
17183
+ children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
17184
+ /* @__PURE__ */ jsx("path", { d: "M12 20h9" }),
17185
+ /* @__PURE__ */ jsx("path", { d: "M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z" })
17186
+ ] })
17187
+ }
17188
+ )
17189
+ ] }, item.id);
17190
+ }) }),
17191
+ /* @__PURE__ */ jsx(ScrollToEnd, { hostRef: listaRef, selector: ".px-chat-chat-navigator__list", dep: `${items.length}:${loading}` })
16932
17192
  ] }),
17193
+ total > pageSize && /* @__PURE__ */ jsx("div", { className: "px-chat-chat-navigator__pager", children: /* @__PURE__ */ jsx(
17194
+ Pagination,
17195
+ {
17196
+ current: page,
17197
+ total: totalPages,
17198
+ onChange: (p) => setSkip((p - 1) * pageSize),
17199
+ showTotal: false
17200
+ }
17201
+ ) }),
16933
17202
  config.advancedFilters?.length ? /* @__PURE__ */ jsx(Drawer$1, { isOpen: advOpen, onClose: () => setAdvOpen(false), title: "Filtros avanzados", children: /* @__PURE__ */ jsx(
16934
17203
  Filter,
16935
17204
  {
@@ -24272,4 +24541,4 @@ function buildBreadcrumbPath(items, targetKey, currentPath = []) {
24272
24541
  return [];
24273
24542
  }
24274
24543
 
24275
- export { BottomSheet, CHAT_CONFIG_DEFAULTS, CHAT_EVENT, ICON_TYPES as CHAT_ICON_TYPES, Chat, AssistantMessage as ChatAssistantMessage, AssistantThinkingIndicator as ChatAssistantThinkingIndicator, AttachmentPreview as ChatAttachmentPreview, Avatar as ChatAvatar, Button$1 as ChatButton, ChatConfigProvider, DateDivider as ChatDateDivider, FileViewer as ChatFileViewer, ChatFloatingActions, FullscreenViewer as ChatFullscreenViewer, ChatHeader as ChatHeaderComponent, Icon$1 as ChatIcon, Input$2 as ChatInput, ChatInput as ChatInputComponent, Link as ChatLink, Loader$1 as ChatLoader, Logo as ChatLogo, MessageStatus as ChatMessageStatus, Modal as ChatModal, ChatNavigator, Select$2 as ChatSelect, SelectMenu as ChatSelectMenu, StructuredContent as ChatStructuredContent, Text as ChatText, Textarea as ChatTextarea, UserAttachments as ChatUserAttachments, UserMessage as ChatUserMessage, ChatWidget, FileField, BADGE_VARIANTS as LUMI_BADGE_VARIANTS, DEFAULT_TITLES as LUMI_DEFAULT_TITLES, LUMI_ICON_TYPES, LiveIndicator, LocationField, ActionBar as LumiActionBar, Badge as LumiBadge, Base as LumiBase, BaseNavbar as LumiBaseNavbar, BaseWorkspace as LumiBaseWorkspace, Breadcrumb as LumiBreadcrumb, BreadcrumbItem as LumiBreadcrumbItem, BreadcrumbSeparator as LumiBreadcrumbSeparator, Button as LumiButton, Calendar as LumiCalendar, Card as LumiCard, Checkbox$1 as LumiCheckbox, Crud as LumiCrud, CurrencyDisplay as LumiCurrencyDisplay, Dashboard as LumiDashboard, DashboardNavbar as LumiDashboardNavbar, DashboardSidebar as LumiDashboardSidebar, DashboardWorkspace as LumiDashboardWorkspace, DateDisplay as LumiDateDisplay, DateInput$1 as LumiDateInput, Drawer as LumiDrawer, DropdownMenu as LumiDropdownMenu, DynamicForm as LumiDynamicForm, Filter as LumiFilter, FilterRow as LumiFilterRow, Checkbox as LumiFormCheckbox, DateInput as LumiFormDateInput, FormDrawer as LumiFormDrawer, Input as LumiFormInput, Select as LumiFormSelect, TimeInput as LumiFormTimeInput, Icon as LumiIcon, Input$1 as LumiInput, Loader as LumiLoader, Menu as LumiMenu, MenuItem as LumiMenuItem, MenuItemGroup as LumiMenuItemGroup, Notification as LumiNotification, Pagination as LumiPagination, Popover as LumiPopover, QRCode as LumiQRCode, Select$1 as LumiSelect, StepIndicator as LumiStepIndicator, Stepper as LumiStepper, SubMenu as LumiSubMenu, Table as LumiTable, Tabs as LumiTabs, TextArea as LumiTextArea, TimeInput$1 as LumiTimeInput, Tooltip as LumiTooltip, MapView, ReactiveCrud, ServiceShortcuts, ServicesMap, SessionExpiryPrompt, UserTools, chatEventBus, createDeepPropertySubscriber, createEventBus, createStore, createStoreMerger, deepMerge, getLastFleetSnapshot, setLastFleetSnapshot, useChatConfig };
24544
+ export { BottomSheet, CHAT_CONFIG_DEFAULTS, CHAT_EVENT, ICON_TYPES as CHAT_ICON_TYPES, Chat, AssistantMessage as ChatAssistantMessage, AssistantThinkingIndicator as ChatAssistantThinkingIndicator, AttachmentPreview as ChatAttachmentPreview, Avatar as ChatAvatar, Button$1 as ChatButton, ChatConfigProvider, DateDivider as ChatDateDivider, FileViewer as ChatFileViewer, ChatFloatingActions, FullscreenViewer as ChatFullscreenViewer, ChatHeader as ChatHeaderComponent, Icon$1 as ChatIcon, Input$2 as ChatInput, ChatInput as ChatInputComponent, Link as ChatLink, Loader$1 as ChatLoader, Logo as ChatLogo, MessageStatus as ChatMessageStatus, Modal as ChatModal, ChatNavigator, Select$2 as ChatSelect, SelectMenu as ChatSelectMenu, StructuredContent as ChatStructuredContent, Text as ChatText, Textarea as ChatTextarea, UserAttachments as ChatUserAttachments, UserMessage as ChatUserMessage, ChatWidget, FileField, BADGE_VARIANTS as LUMI_BADGE_VARIANTS, DEFAULT_TITLES as LUMI_DEFAULT_TITLES, LUMI_ICON_TYPES, LiveIndicator, LocationField, ActionBar as LumiActionBar, Badge as LumiBadge, Base as LumiBase, BaseNavbar as LumiBaseNavbar, BaseWorkspace as LumiBaseWorkspace, Breadcrumb as LumiBreadcrumb, BreadcrumbItem as LumiBreadcrumbItem, BreadcrumbSeparator as LumiBreadcrumbSeparator, Button as LumiButton, Calendar as LumiCalendar, Card as LumiCard, Checkbox$1 as LumiCheckbox, Crud as LumiCrud, CurrencyDisplay as LumiCurrencyDisplay, Dashboard as LumiDashboard, DashboardNavbar as LumiDashboardNavbar, DashboardSidebar as LumiDashboardSidebar, DashboardWorkspace as LumiDashboardWorkspace, DateDisplay as LumiDateDisplay, DateInput$1 as LumiDateInput, Drawer as LumiDrawer, DropdownMenu as LumiDropdownMenu, DynamicForm as LumiDynamicForm, FieldValue as LumiFieldValue, Filter as LumiFilter, FilterRow as LumiFilterRow, Checkbox as LumiFormCheckbox, DateInput as LumiFormDateInput, FormDrawer as LumiFormDrawer, Input as LumiFormInput, Select as LumiFormSelect, TimeInput as LumiFormTimeInput, Icon as LumiIcon, Input$1 as LumiInput, Loader as LumiLoader, Menu as LumiMenu, MenuItem as LumiMenuItem, MenuItemGroup as LumiMenuItemGroup, Notification as LumiNotification, Pagination as LumiPagination, Popover as LumiPopover, QRCode as LumiQRCode, RecordCard as LumiRecordCard, Select$1 as LumiSelect, StepIndicator as LumiStepIndicator, Stepper as LumiStepper, SubMenu as LumiSubMenu, Table as LumiTable, Tabs as LumiTabs, TextArea as LumiTextArea, TimeInput$1 as LumiTimeInput, Tooltip as LumiTooltip, MapView, ReactiveCrud, ServiceShortcuts, ServicesMap, SessionExpiryPrompt, UserTools, chatEventBus, createDeepPropertySubscriber, createEventBus, createStore, createStoreMerger, deepMerge, getLastFleetSnapshot, setLastFleetSnapshot, useChatConfig };