@prolibu-suite/cobalt-core 0.9.2 → 0.9.4

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 (245) hide show
  1. package/custom-elements.json +375 -25
  2. package/dist/cjs/co-audio-player.cjs.entry.js +107 -18
  3. package/dist/cjs/co-avatar_2.cjs.entry.js +7 -31
  4. package/dist/cjs/co-button.cjs.entry.js +6 -4
  5. package/dist/cjs/co-calendar-month_2.cjs.entry.js +59 -2
  6. package/dist/cjs/co-checkbox.cjs.entry.js +10 -4
  7. package/dist/cjs/co-chip_2.cjs.entry.js +388 -18
  8. package/dist/cjs/co-color-picker.cjs.entry.js +36 -3
  9. package/dist/cjs/co-combobox.cjs.entry.js +44 -4
  10. package/dist/cjs/co-event-popover.cjs.entry.js +5 -2
  11. package/dist/cjs/co-file-field.cjs.entry.js +12 -6
  12. package/dist/cjs/co-icon-button.cjs.entry.js +5 -2
  13. package/dist/cjs/co-icon.cjs.entry.js +17 -1
  14. package/dist/cjs/co-input.cjs.entry.js +21 -1
  15. package/dist/cjs/co-loader.cjs.entry.js +1 -1
  16. package/dist/cjs/co-number-field.cjs.entry.js +22 -2
  17. package/dist/cjs/co-ref-field.cjs.entry.js +87 -13
  18. package/dist/cjs/co-select.cjs.entry.js +273 -8
  19. package/dist/cjs/co-tags-field.cjs.entry.js +1 -1
  20. package/dist/cjs/cobalt.cjs.js +1 -1
  21. package/dist/cjs/color-YhUkm10t.js +32 -0
  22. package/dist/cjs/fieldChip-BLzo9MEV.js +7 -0
  23. package/dist/cjs/index-DK-2Lzmf.js +4 -4
  24. package/dist/cjs/loader.cjs.js +1 -1
  25. package/dist/cobalt/cobalt.esm.js +1 -1
  26. package/dist/cobalt/p-0c463d9a.entry.js +1 -0
  27. package/dist/cobalt/p-0caa059c.entry.js +1 -0
  28. package/dist/cobalt/{p-3ced4269.entry.js → p-2828ecf6.entry.js} +1 -1
  29. package/dist/cobalt/p-2f88d151.entry.js +1 -0
  30. package/dist/cobalt/p-409f28bb.entry.js +1 -0
  31. package/dist/cobalt/{p-18af9e44.entry.js → p-568cfe8d.entry.js} +1 -1
  32. package/dist/cobalt/p-6bf814f9.entry.js +1 -0
  33. package/dist/cobalt/p-7ea87b75.entry.js +1 -0
  34. package/dist/cobalt/p-8b4b3589.entry.js +1 -0
  35. package/dist/cobalt/p-93c68029.entry.js +1 -0
  36. package/dist/cobalt/p-BG4WRR22.js +1 -0
  37. package/dist/cobalt/p-a2d31248.entry.js +1 -0
  38. package/dist/cobalt/p-bcedbd73.entry.js +1 -0
  39. package/dist/cobalt/p-dfd25f1d.entry.js +1 -0
  40. package/dist/cobalt/p-e364b8a5.entry.js +1 -0
  41. package/dist/cobalt/p-f00be11f.entry.js +1 -0
  42. package/dist/cobalt/p-f25967fb.entry.js +1 -0
  43. package/dist/cobalt/p-f5f1b463.entry.js +1 -0
  44. package/dist/cobalt/p-fef5db54.entry.js +1 -0
  45. package/dist/cobalt/p-mAGnZXRn.js +1 -0
  46. package/dist/collection/components/co-audio-player/co-audio-player.js +81 -17
  47. package/dist/collection/components/co-audio-player/co-audio-player.utils.js +27 -2
  48. package/dist/collection/components/co-autocomplete/co-autocomplete.js +1 -1
  49. package/dist/collection/components/co-avatar/co-avatar.js +5 -1
  50. package/dist/collection/components/co-avatar-group/co-avatar-group.js +1 -1
  51. package/dist/collection/components/co-button/co-button.css +7 -0
  52. package/dist/collection/components/co-button/co-button.js +7 -5
  53. package/dist/collection/components/co-calendar-month/co-calendar-month.js +59 -2
  54. package/dist/collection/components/co-checkbox/co-checkbox.css +22 -0
  55. package/dist/collection/components/co-checkbox/co-checkbox.js +9 -3
  56. package/dist/collection/components/co-checkbox-group/co-checkbox-group.js +1 -1
  57. package/dist/collection/components/co-color-picker/co-color-picker.css +7 -0
  58. package/dist/collection/components/co-color-picker/co-color-picker.js +35 -2
  59. package/dist/collection/components/co-combobox/co-combobox.css +7 -0
  60. package/dist/collection/components/co-combobox/co-combobox.js +44 -4
  61. package/dist/collection/components/co-command-search/co-command-search.js +1 -1
  62. package/dist/collection/components/co-data-table/co-data-table.js +1 -1
  63. package/dist/collection/components/co-date-range-picker/co-date-range-picker.js +2 -2
  64. package/dist/collection/components/co-event-popover/co-event-popover.js +5 -2
  65. package/dist/collection/components/co-file-field/co-file-field.css +7 -4
  66. package/dist/collection/components/co-file-field/co-file-field.js +8 -5
  67. package/dist/collection/components/co-icon/iconLoader.js +17 -1
  68. package/dist/collection/components/co-icon-button/co-icon-button.css +7 -0
  69. package/dist/collection/components/co-icon-button/co-icon-button.js +6 -3
  70. package/dist/collection/components/co-input/co-input.css +13 -0
  71. package/dist/collection/components/co-input/co-input.js +21 -0
  72. package/dist/collection/components/co-loader/co-loader.css +5 -3
  73. package/dist/collection/components/co-number-field/co-number-field.js +23 -2
  74. package/dist/collection/components/co-option-list/co-option-list.css +45 -2
  75. package/dist/collection/components/co-option-list/co-option-list.js +468 -18
  76. package/dist/collection/components/co-option-list/optionListLogic.js +25 -0
  77. package/dist/collection/components/co-popover/co-popover.js +1 -1
  78. package/dist/collection/components/co-radio-group/co-radio-group.js +1 -1
  79. package/dist/collection/components/co-ref-field/co-ref-field.css +49 -0
  80. package/dist/collection/components/co-ref-field/co-ref-field.js +240 -12
  81. package/dist/collection/components/co-segmented-bar/co-segmented-bar.js +1 -1
  82. package/dist/collection/components/co-select/co-select.css +19 -0
  83. package/dist/collection/components/co-select/co-select.js +275 -9
  84. package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.js +1 -1
  85. package/dist/collection/components/co-toast/co-toast.js +2 -2
  86. package/dist/collection/components/co-transfer-list/co-transfer-list.js +1 -1
  87. package/dist/collection/utils/fieldChip.js +1 -1
  88. package/dist/collection/utils/fileI18n.js +3 -0
  89. package/dist/components/co-accordion.js +1 -1
  90. package/dist/components/co-action-bar.js +1 -1
  91. package/dist/components/co-audio-player.js +1 -1
  92. package/dist/components/co-autocomplete.js +1 -1
  93. package/dist/components/co-avatar-group.js +1 -1
  94. package/dist/components/co-avatar.js +1 -1
  95. package/dist/components/co-breadcrumb-item.js +1 -1
  96. package/dist/components/co-breadcrumb.js +1 -1
  97. package/dist/components/co-button.js +1 -1
  98. package/dist/components/co-calendar-month.js +1 -1
  99. package/dist/components/co-calendar-timegrid.js +1 -1
  100. package/dist/components/co-calendar.js +1 -1
  101. package/dist/components/co-carousel.js +1 -1
  102. package/dist/components/co-checkbox-group.js +1 -1
  103. package/dist/components/co-checkbox.js +1 -1
  104. package/dist/components/co-chip.js +1 -1
  105. package/dist/components/co-color-picker.js +1 -1
  106. package/dist/components/co-column-picker.js +1 -1
  107. package/dist/components/co-combobox.js +1 -1
  108. package/dist/components/co-command-search.js +1 -1
  109. package/dist/components/co-data-table-pagination.js +1 -1
  110. package/dist/components/co-data-table.js +1 -1
  111. package/dist/components/co-date-field.js +1 -1
  112. package/dist/components/co-date-picker.js +1 -1
  113. package/dist/components/co-date-range-picker.js +1 -1
  114. package/dist/components/co-date-range.js +1 -1
  115. package/dist/components/co-date-time-picker.js +1 -1
  116. package/dist/components/co-drawer.js +1 -1
  117. package/dist/components/co-drive-card.js +1 -1
  118. package/dist/components/co-drop-zone.js +1 -1
  119. package/dist/components/co-emoji-picker.js +1 -1
  120. package/dist/components/co-empty-state.js +1 -1
  121. package/dist/components/co-event-calendar.js +1 -1
  122. package/dist/components/co-event-popover.js +1 -1
  123. package/dist/components/co-fab.js +1 -1
  124. package/dist/components/co-file-field.js +1 -1
  125. package/dist/components/co-file-type-tile.js +1 -1
  126. package/dist/components/co-helper-text.js +1 -1
  127. package/dist/components/co-icon-button.js +1 -1
  128. package/dist/components/co-icon.js +1 -1
  129. package/dist/components/co-input.js +1 -1
  130. package/dist/components/co-json-field.js +1 -1
  131. package/dist/components/co-lightbox.js +1 -1
  132. package/dist/components/co-list-footer.js +1 -1
  133. package/dist/components/co-list-item.js +1 -1
  134. package/dist/components/co-loader.js +1 -1
  135. package/dist/components/co-menu-item.js +1 -1
  136. package/dist/components/co-modal.js +1 -1
  137. package/dist/components/co-number-field.js +1 -1
  138. package/dist/components/co-option-list.js +1 -1
  139. package/dist/components/co-page-header.js +1 -1
  140. package/dist/components/co-phone-field.js +1 -1
  141. package/dist/components/co-radio-group.js +1 -1
  142. package/dist/components/co-rating.js +1 -1
  143. package/dist/components/co-ref-field.js +1 -1
  144. package/dist/components/co-rich-text-editor.js +1 -1
  145. package/dist/components/co-rich-text-toolbar.js +1 -1
  146. package/dist/components/co-select.js +1 -1
  147. package/dist/components/co-sidebar-nav.js +1 -1
  148. package/dist/components/co-slider.js +1 -1
  149. package/dist/components/co-switch.js +1 -1
  150. package/dist/components/co-tab.js +1 -1
  151. package/dist/components/co-tags-field.js +1 -1
  152. package/dist/components/co-textarea.js +1 -1
  153. package/dist/components/co-toast.js +1 -1
  154. package/dist/components/co-toggle-button.js +1 -1
  155. package/dist/components/co-transfer-list.js +1 -1
  156. package/dist/components/co-video.js +1 -1
  157. package/dist/components/{p-CklsvHeL.js → p-B0Dc-I_C.js} +1 -1
  158. package/dist/components/{p-DzoNGEDU.js → p-BH184F0X.js} +1 -1
  159. package/dist/components/{p-BGD3oQ73.js → p-BHYtxTzM.js} +1 -1
  160. package/dist/components/{p-mom5kiBa.js → p-BTQEg3UO.js} +1 -1
  161. package/dist/components/p-BZIB4JDs.js +1 -0
  162. package/dist/components/p-Bbny3WUc.js +1 -0
  163. package/dist/components/{p-D5QJpmqf.js → p-Bxk96Zgc.js} +1 -1
  164. package/dist/components/p-C1Kv3zYZ.js +1 -0
  165. package/dist/components/p-C4U2tbRp.js +1 -0
  166. package/dist/components/{p-CyMaOb1j.js → p-CA_JAK9s.js} +1 -1
  167. package/dist/components/{p-AvSaw4Ua.js → p-CR0izsJC.js} +1 -1
  168. package/dist/components/p-CuZXTvDM.js +1 -0
  169. package/dist/components/{p-_131DL6m.js → p-D4qzGifz.js} +1 -1
  170. package/dist/components/{p-BsQQ7Mki.js → p-D5EdMieb.js} +1 -1
  171. package/dist/components/p-Dabi98BI.js +1 -0
  172. package/dist/components/p-DbipMAyT.js +1 -0
  173. package/dist/components/p-DgUBcJIS.js +1 -0
  174. package/dist/components/p-Dj1EZ5qD.js +1 -0
  175. package/dist/components/{p-DkmKOF60.js → p-P8wvwhM2.js} +1 -1
  176. package/dist/components/{p-nwy6X1QT.js → p-hfGFsvaD.js} +1 -1
  177. package/dist/esm/co-audio-player.entry.js +107 -18
  178. package/dist/esm/co-avatar_2.entry.js +6 -30
  179. package/dist/esm/co-button.entry.js +6 -4
  180. package/dist/esm/co-calendar-month_2.entry.js +59 -2
  181. package/dist/esm/co-checkbox.entry.js +10 -4
  182. package/dist/esm/co-chip_2.entry.js +388 -18
  183. package/dist/esm/co-color-picker.entry.js +36 -3
  184. package/dist/esm/co-combobox.entry.js +44 -4
  185. package/dist/esm/co-event-popover.entry.js +5 -2
  186. package/dist/esm/co-file-field.entry.js +12 -6
  187. package/dist/esm/co-icon-button.entry.js +5 -2
  188. package/dist/esm/co-icon.entry.js +17 -1
  189. package/dist/esm/co-input.entry.js +21 -1
  190. package/dist/esm/co-loader.entry.js +1 -1
  191. package/dist/esm/co-number-field.entry.js +22 -2
  192. package/dist/esm/co-ref-field.entry.js +87 -13
  193. package/dist/esm/co-select.entry.js +273 -8
  194. package/dist/esm/co-tags-field.entry.js +1 -1
  195. package/dist/esm/cobalt.js +1 -1
  196. package/dist/esm/color-BG4WRR22.js +30 -0
  197. package/dist/esm/fieldChip-DsAfq1e0.js +5 -0
  198. package/dist/esm/index-CrtiywTB.js +4 -4
  199. package/dist/esm/loader.js +1 -1
  200. package/dist/types/components/co-audio-player/co-audio-player.d.ts +13 -0
  201. package/dist/types/components/co-audio-player/co-audio-player.utils.d.ts +18 -1
  202. package/dist/types/components/co-button/co-button.d.ts +3 -1
  203. package/dist/types/components/co-calendar-month/co-calendar-month.d.ts +7 -0
  204. package/dist/types/components/co-checkbox/co-checkbox.d.ts +1 -0
  205. package/dist/types/components/co-color-picker/co-color-picker.d.ts +15 -0
  206. package/dist/types/components/co-combobox/co-combobox.d.ts +17 -0
  207. package/dist/types/components/co-icon-button/co-icon-button.d.ts +3 -0
  208. package/dist/types/components/co-input/co-input.d.ts +9 -0
  209. package/dist/types/components/co-number-field/co-number-field.d.ts +9 -0
  210. package/dist/types/components/co-option-list/co-option-list.d.ts +79 -0
  211. package/dist/types/components/co-option-list/optionListLogic.d.ts +23 -1
  212. package/dist/types/components/co-ref-field/co-ref-field.d.ts +46 -0
  213. package/dist/types/components/co-select/co-select.d.ts +67 -0
  214. package/dist/types/components.d.ts +110 -4
  215. package/dist/types/utils/fieldChip.d.ts +5 -0
  216. package/dist/types/utils/fileI18n.d.ts +1 -0
  217. package/package.json +4 -4
  218. package/dist/cjs/fieldChip-xNJPEFcS.js +0 -7
  219. package/dist/cobalt/p-02ac492f.entry.js +0 -1
  220. package/dist/cobalt/p-0ccb672b.entry.js +0 -1
  221. package/dist/cobalt/p-2d81b292.entry.js +0 -1
  222. package/dist/cobalt/p-4a503187.entry.js +0 -1
  223. package/dist/cobalt/p-55566b37.entry.js +0 -1
  224. package/dist/cobalt/p-7457aa89.entry.js +0 -1
  225. package/dist/cobalt/p-77719335.entry.js +0 -1
  226. package/dist/cobalt/p-8f600512.entry.js +0 -1
  227. package/dist/cobalt/p-CQAYgqA6.js +0 -1
  228. package/dist/cobalt/p-a02db338.entry.js +0 -1
  229. package/dist/cobalt/p-a51d8775.entry.js +0 -1
  230. package/dist/cobalt/p-a9096b5c.entry.js +0 -1
  231. package/dist/cobalt/p-aafb9d11.entry.js +0 -1
  232. package/dist/cobalt/p-b28dc0fe.entry.js +0 -1
  233. package/dist/cobalt/p-c6b9b9d6.entry.js +0 -1
  234. package/dist/cobalt/p-d4debd6f.entry.js +0 -1
  235. package/dist/cobalt/p-d629fb4e.entry.js +0 -1
  236. package/dist/components/p-B3TkpLNh.js +0 -1
  237. package/dist/components/p-B7hvddnu.js +0 -1
  238. package/dist/components/p-BT5tSgZa.js +0 -1
  239. package/dist/components/p-CXLX8DpD.js +0 -1
  240. package/dist/components/p-DTvb412h.js +0 -1
  241. package/dist/components/p-DvhR3H61.js +0 -1
  242. package/dist/components/p-KWTokD0C.js +0 -1
  243. package/dist/components/p-Q6caHt79.js +0 -1
  244. package/dist/components/p-WWlZiln1.js +0 -1
  245. package/dist/esm/fieldChip-BZDUy9Z-.js +0 -5
@@ -1,7 +1,7 @@
1
1
  import { h } from "@stencil/core";
2
2
  import { highlightMatch } from "../../utils/normalizeText";
3
3
  import { initOverlayScroll } from "../../utils/overlayScroll";
4
- import { buildRows, deriveMore, nextActiveIndex, orderItems, parseItems, parseValue, reorderIds, virtualSlice, VIRTUAL_ITEM_HEIGHT, VIRTUAL_VIEWPORT_ITEMS, } from "./optionListLogic";
4
+ import { buildRows, deriveMore, listReorderIds, liveSelectedOrder, nextActiveIndex, orderItems, parseItems, parseValue, selectedActiveIndex, virtualSlice, VIRTUAL_ITEM_HEIGHT, VIRTUAL_VIEWPORT_ITEMS, } from "./optionListLogic";
5
5
  /**
6
6
  * Núcleo de lista de opciones — la única fuente del look & behavior de los
7
7
  * dropdowns Cobalt (co-ref-field, co-combobox, co-autocomplete,
@@ -30,6 +30,13 @@ export class CoOptionList {
30
30
  this.removableItems = false;
31
31
  /** Habilita reorder por drag del bloque de seleccionados (selected-first). */
32
32
  this.reorderable = false;
33
+ /** Botón push-pin por fila (siempre visible). Emite coPinToggle; el estado
34
+ * pinned viene en item.pinned — el componente NO lo muta (controlado). */
35
+ this.pinnable = false;
36
+ /** Drag-reorder de la LISTA completa (no del bloque seleccionado): handle en
37
+ * filas no-pineadas, emite coListReorder con el orden visible completo.
38
+ * Independiente de multiple/selectedFirst. No soportado con `virtual`. */
39
+ this.listReorderable = false;
33
40
  // ── Search integrado (opcional) ────────────────────────────
34
41
  this.searchable = false;
35
42
  this.searchPlaceholder = 'Search…';
@@ -69,9 +76,13 @@ export class CoOptionList {
69
76
  this.overKey = '';
70
77
  /** Dirección del drop sobre overKey (true = el ítem cae DESPUÉS del target). */
71
78
  this.dropAfter = false;
79
+ /** Longitud de lista para la que ya se pidió un fill (ver fillViewport). */
80
+ this.lastFillLen = -1;
72
81
  /** Snapshot selected-first (ver snapshotOrder). */
73
82
  this.sortSnapshot = new Set();
74
83
  this.displaySnapshot = [];
84
+ /** Orden del live-preview en curso (drag por puntero del bloque seleccionado). */
85
+ this.previewOrder = [];
75
86
  /**
76
87
  * Enter sobre un control real (footer, fila clear) activa ese control
77
88
  * nativamente — nunca el highlight (regla heredada de CellRefPicker).
@@ -94,15 +105,95 @@ export class CoOptionList {
94
105
  const v = e.target.value;
95
106
  this.term = v;
96
107
  this.activeIndex = -1;
108
+ // Resultset nuevo: re-habilita fillViewport aunque venga del mismo largo.
109
+ this.lastFillLen = -1;
97
110
  if (this.debounceTimer)
98
111
  clearTimeout(this.debounceTimer);
99
112
  this.debounceTimer = setTimeout(() => this.coSearch.emit(v), this.searchDebounce);
100
113
  };
114
+ this.onPtrMove = (e) => {
115
+ const d = this.ptrDrag;
116
+ if (!d)
117
+ return;
118
+ if (!d.started) {
119
+ if (Math.abs(e.clientY - d.startY) < 3)
120
+ return; // umbral: no secuestrar clicks
121
+ d.started = true;
122
+ this.dragKey = d.id; // → clase --lifted
123
+ this.previewOrder = d.originOrder;
124
+ this.el.style.userSelect = 'none';
125
+ // Selección fresca fuera del bloque: entra al bloque al levantarla (FLIP),
126
+ // así la geometría de slots (blockTop + i×pitch) vale toda la sesión.
127
+ if (!this.sortSnapshot.has(d.id))
128
+ this.applyPreview([...d.originOrder]);
129
+ }
130
+ e.preventDefault();
131
+ const n = this.previewOrder.length;
132
+ const min = d.blockTop;
133
+ const max = d.blockTop + (n - 1) * d.pitch;
134
+ d.desiredTop = Math.max(min, Math.min(max, e.clientY - d.grabDY));
135
+ this.positionLifted();
136
+ const i = this.previewOrder.indexOf(d.id);
137
+ const j = Math.max(0, Math.min(n - 1, Math.round((d.desiredTop - d.blockTop) / d.pitch)));
138
+ if (j !== i && i !== -1) {
139
+ const next = [...this.previewOrder];
140
+ next.splice(j, 0, next.splice(i, 1)[0]);
141
+ this.applyPreview(next);
142
+ }
143
+ };
144
+ this.onPtrUp = () => {
145
+ const d = this.ptrDrag;
146
+ this.removePtrListeners();
147
+ this.ptrDrag = undefined;
148
+ if (!d || !d.started)
149
+ return;
150
+ // El browser genera un click sintético tras el pointerup del drag; si cae
151
+ // sobre una fila dispara pick() y DESELECCIONA el ítem recién soltado.
152
+ // Supresor de un solo click, auto-removido en el próximo macrotask.
153
+ const suppress = (ev) => { ev.stopPropagation(); ev.preventDefault(); };
154
+ window.addEventListener('click', suppress, true);
155
+ setTimeout(() => window.removeEventListener('click', suppress, true), 0);
156
+ this.settleLifted(d);
157
+ if (this.previewOrder.length && this.previewOrder.join(' ') !== d.originOrder.join(' ')) {
158
+ const byId = new Map(this.displaySnapshot.map((x) => [x._id, x]));
159
+ this.coReorder.emit({ value: this.previewOrder, item: byId.get(d.id) });
160
+ }
161
+ this.previewOrder = [];
162
+ };
163
+ this.onPtrKey = (e) => {
164
+ var _a;
165
+ if (e.key !== 'Escape' || !this.ptrDrag)
166
+ return;
167
+ e.stopPropagation(); // el ESC del drag no debe cerrar el popover host
168
+ e.preventDefault();
169
+ const d = this.ptrDrag;
170
+ this.removePtrListeners();
171
+ this.ptrDrag = undefined;
172
+ if (!d.started)
173
+ return;
174
+ if (this.displaySnapshot !== d.originDisplay) {
175
+ // Hubo preview: restaurar snapshots originales — FLIP con spring para la
176
+ // fila que vuelve (captura ANTES de restaurar, incluye su transform actual).
177
+ this.pendingFlip = { tops: this.captureRowTops(), movedId: d.id, spring: true };
178
+ const row = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(`.co-option-list__option[data-id="${CSS.escape(d.id)}"]`);
179
+ if (row) {
180
+ row.style.transition = 'none';
181
+ row.style.transform = '';
182
+ }
183
+ this.displaySnapshot = d.originDisplay;
184
+ this.sortSnapshot = d.originSort;
185
+ this.dragKey = '';
186
+ this.el.style.userSelect = '';
187
+ }
188
+ else {
189
+ this.settleLifted(d);
190
+ }
191
+ this.previewOrder = [];
192
+ };
101
193
  this.handleRowDragEnd = () => { this.resetDragState(); };
102
194
  this.handleRowDragLeave = (e, id) => {
103
- // Limpia el highlight al salir de la fila (evita drop-target stale al pasar sobre
104
- // el bloque no-seleccionado, que no tiene onDragOver). Guard `contains`: dragleave
105
- // también dispara al entrar a un hijo, no solo al salir de la fila.
195
+ // Limpia el highlight al salir de la fila (evita drop-target stale). Guard
196
+ // `contains`: dragleave también dispara al entrar a un hijo de la fila.
106
197
  if (this.overKey === id && !e.currentTarget.contains(e.relatedTarget)) {
107
198
  this.overKey = '';
108
199
  }
@@ -148,6 +239,11 @@ export class CoOptionList {
148
239
  this.maybeLoadMore(vp.scrollTop, vp.clientHeight, vp.scrollHeight);
149
240
  });
150
241
  }
242
+ this.fillViewport();
243
+ this.runFlip();
244
+ // Re-ancla la fila lifted tras cada re-render del preview: su slot de layout
245
+ // cambió, pero su posición visual la dicta el puntero.
246
+ this.positionLifted();
151
247
  }
152
248
  connectedCallback() {
153
249
  window.addEventListener('mouseup', this.disarmDrag);
@@ -159,6 +255,7 @@ export class CoOptionList {
159
255
  (_a = this.osInstance) === null || _a === void 0 ? void 0 : _a.destroy();
160
256
  this.osInstance = undefined;
161
257
  window.removeEventListener('mouseup', this.disarmDrag);
258
+ this.removePtrListeners();
162
259
  }
163
260
  onItemsChange() {
164
261
  // Nueva página / nuevos resultados: si autoHighlight, re-resalta la primera fila
@@ -199,6 +296,45 @@ export class CoOptionList {
199
296
  await new Promise((resolve) => requestAnimationFrame(() => resolve()));
200
297
  }
201
298
  }
299
+ /**
300
+ * Ancla la sesión del panel en la selección: highlight sobre la primera fila
301
+ * seleccionada y scroll hasta dejarla visible (paridad resetActiveIndex de
302
+ * co-select). El host la llama al ABRIR su panel — la lista queda montada
303
+ * entre aperturas y no sabe cuándo se abre (mismo contrato que
304
+ * focusSearch/snapshotOrder). Espera layout real igual que focusSearch: el
305
+ * panel se hace visible frames después y un scroll sobre subtree oculto se
306
+ * clampea a 0 en silencio.
307
+ */
308
+ async scrollToSelected() {
309
+ var _a, _b, _c, _d;
310
+ const idx = selectedActiveIndex(this.orderedItems, this.selectedIds);
311
+ if (idx === -1)
312
+ return;
313
+ this.activeIndex = idx;
314
+ for (let i = 0; i < 20; i++) {
315
+ const vp = (_b = (_a = this.osInstance) === null || _a === void 0 ? void 0 : _a.elements().viewport) !== null && _b !== void 0 ? _b : this.optionsEl;
316
+ if (vp && vp.clientHeight > 0) {
317
+ if (this.virtual) {
318
+ // Fila fuera del slice virtual: no hay nodo al que hacer scrollIntoView —
319
+ // misma matemática 'nearest' que co-select, sobre la ventana virtual.
320
+ const rowTop = idx * VIRTUAL_ITEM_HEIGHT;
321
+ let target = vp.scrollTop;
322
+ if (rowTop < target)
323
+ target = rowTop;
324
+ else if (rowTop + VIRTUAL_ITEM_HEIGHT > target + vp.clientHeight) {
325
+ target = rowTop + VIRTUAL_ITEM_HEIGHT - vp.clientHeight;
326
+ }
327
+ this.scrollTop = target;
328
+ vp.scrollTop = target;
329
+ }
330
+ else {
331
+ (_d = (_c = this.el.shadowRoot) === null || _c === void 0 ? void 0 : _c.getElementById(`co-optlist-${idx}`)) === null || _d === void 0 ? void 0 : _d.scrollIntoView({ block: 'nearest' });
332
+ }
333
+ return;
334
+ }
335
+ await new Promise((resolve) => requestAnimationFrame(() => resolve()));
336
+ }
337
+ }
202
338
  /** Navegación para hosts con input externo. true = tecla consumida (host hace preventDefault). */
203
339
  async handleKey(e) {
204
340
  return this.processKey(e.key);
@@ -269,6 +405,16 @@ export class CoOptionList {
269
405
  }
270
406
  }
271
407
  // ── Reorder (drag del bloque selected-first) ───────────────
408
+ /** true = drag de lista completa; el modo selected-block (chips multiple) tiene prioridad
409
+ * si ambos están activos (no coexisten en la práctica). */
410
+ get listDragActive() {
411
+ return this.listReorderable && !(this.reorderable && this.selectedFirst);
412
+ }
413
+ /** Universo del drag de LISTA COMPLETA (listReorderable). El bloque
414
+ * seleccionado usa `previewOrder` (live-preview, ver handleRowDragStart). */
415
+ dragOrderIds() {
416
+ return this.orderedItems.map((i) => i._id);
417
+ }
272
418
  handleRowDragStart(e, id) {
273
419
  if (this.armedKey !== id) {
274
420
  e.preventDefault();
@@ -289,22 +435,181 @@ export class CoOptionList {
289
435
  this.overKey = id;
290
436
  // Dirección: al arrastrar hacia abajo (from<to) el ítem cae DESPUÉS del target
291
437
  // (semántica de reorderIds) → el indicador va en el borde inferior; hacia arriba, superior.
292
- const ids = this.displaySnapshot.map((d) => d._id);
438
+ const ids = this.dragOrderIds();
293
439
  this.dropAfter = ids.indexOf(this.dragKey) < ids.indexOf(id);
294
440
  }
441
+ // ── Drag por puntero (bloque seleccionado, estilo motion.dev) ──
442
+ // La fila agarrada sigue al puntero 1:1 (transform, sin el ghost nativo del
443
+ // browser) con lift (sombra + escala); las demás se apartan EN VIVO con FLIP.
444
+ // Soltar confirma (emite coReorder); ESC revierte con settle.
445
+ /** Aplica un orden de preview al bloque seleccionado con FLIP (todo ease-out;
446
+ * la fila lifted queda fuera del FLIP — su posición la dicta el puntero). */
447
+ applyPreview(next) {
448
+ this.pendingFlip = { tops: this.captureRowTops(), movedId: this.dragKey, spring: false };
449
+ const byId = new Map(this.orderedItems.map((i) => [i._id, i]));
450
+ for (const d of this.displaySnapshot)
451
+ if (!byId.has(d._id))
452
+ byId.set(d._id, d);
453
+ this.sortSnapshot = new Set(next);
454
+ this.displaySnapshot = next.map((x) => byId.get(x)).filter(Boolean);
455
+ this.previewOrder = next;
456
+ }
457
+ startPointerDrag(e, id) {
458
+ var _a;
459
+ if (e.button !== 0 || this.ptrDrag)
460
+ return;
461
+ const order = liveSelectedOrder(this.orderedItems, this.selectedIds);
462
+ if (!order.includes(id))
463
+ return;
464
+ const row = e.currentTarget.closest('.co-option-list__option');
465
+ if (!row)
466
+ return;
467
+ e.preventDefault();
468
+ e.stopPropagation();
469
+ const rect = row.getBoundingClientRect();
470
+ // Pitch MEDIDO de la lista real (alto de fila + gap): las filas de este
471
+ // panel son content-driven (nombre + email ≈ 44px), NO el alto fijo de la
472
+ // lista virtual — asumir VIRTUAL_ITEM_HEIGHT desvía el slot y la fila
473
+ // aterriza fuera de lugar al soltar.
474
+ const rows = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.co-option-list__option[data-id]');
475
+ const first = rows === null || rows === void 0 ? void 0 : rows[0];
476
+ const pitch = (rows && rows.length >= 2)
477
+ ? rows[1].getBoundingClientRect().top - rows[0].getBoundingClientRect().top
478
+ : rect.height || VIRTUAL_ITEM_HEIGHT;
479
+ // Top geométrico del slot 0: primera fila renderizada − su índice × pitch
480
+ // (la fila agarrada puede vivir FUERA del bloque si es una selección
481
+ // fresca, por eso no sirve de ancla).
482
+ const firstIdx = first ? this.orderedItems.findIndex((i) => i._id === first.dataset.id) : 0;
483
+ const blockTop = first
484
+ ? first.getBoundingClientRect().top - Math.max(0, firstIdx) * pitch
485
+ : rect.top;
486
+ this.ptrDrag = {
487
+ id,
488
+ grabDY: e.clientY - rect.top,
489
+ blockTop,
490
+ pitch,
491
+ originOrder: order,
492
+ originDisplay: this.displaySnapshot,
493
+ originSort: this.sortSnapshot,
494
+ desiredTop: rect.top,
495
+ startY: e.clientY,
496
+ started: false,
497
+ };
498
+ window.addEventListener('pointermove', this.onPtrMove);
499
+ window.addEventListener('pointerup', this.onPtrUp);
500
+ window.addEventListener('keydown', this.onPtrKey, true);
501
+ }
502
+ /** Posiciona la fila lifted bajo el puntero (transform sobre su slot de layout). */
503
+ positionLifted() {
504
+ var _a;
505
+ const d = this.ptrDrag;
506
+ if (!d || !d.started)
507
+ return;
508
+ const row = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(`.co-option-list__option[data-id="${CSS.escape(d.id)}"]`);
509
+ if (!row)
510
+ return;
511
+ const idx = this.previewOrder.indexOf(d.id);
512
+ if (idx === -1)
513
+ return;
514
+ const layoutTop = d.blockTop + idx * d.pitch;
515
+ row.style.transition = 'none';
516
+ row.style.transform = `translateY(${d.desiredTop - layoutTop}px) scale(1.02)`;
517
+ }
518
+ /** Settle de la fila lifted: de su posición visual actual a su slot, con spring. */
519
+ settleLifted(d) {
520
+ var _a;
521
+ const row = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(`.co-option-list__option[data-id="${CSS.escape(d.id)}"]`);
522
+ const done = () => {
523
+ this.dragKey = '';
524
+ this.el.style.userSelect = '';
525
+ };
526
+ if (!row) {
527
+ done();
528
+ return;
529
+ }
530
+ void row.offsetHeight; // fija la posición visual actual antes de animar
531
+ row.style.transition = 'transform var(--co-motion-duration-base) var(--co-motion-ease-spring)';
532
+ row.style.transform = '';
533
+ row.addEventListener('transitionend', () => { row.style.transition = ''; done(); }, { once: true });
534
+ }
535
+ removePtrListeners() {
536
+ window.removeEventListener('pointermove', this.onPtrMove);
537
+ window.removeEventListener('pointerup', this.onPtrUp);
538
+ window.removeEventListener('keydown', this.onPtrKey, true);
539
+ }
295
540
  handleRowDrop(e, id) {
296
541
  e.preventDefault();
297
542
  e.stopPropagation();
298
543
  const fromId = this.dragKey;
299
- const order = this.displaySnapshot.map((d) => d._id);
544
+ const order = this.dragOrderIds();
300
545
  this.resetDragState();
301
- // Solo reordenar dentro del bloque seleccionado
302
546
  if (fromId === id || !order.includes(fromId) || !order.includes(id))
303
547
  return;
304
- const next = reorderIds(order, fromId, id);
305
- const byId = new Map(this.displaySnapshot.map((d) => [d._id, d]));
306
- this.displaySnapshot = next.map((x) => byId.get(x)); // reflow en vivo del panel
307
- this.coReorder.emit({ value: next, item: byId.get(fromId) });
548
+ const byId = new Map(this.orderedItems.map((i) => [i._id, i]));
549
+ const next = listReorderIds(order, fromId, id, (x) => { var _a; return !!((_a = byId.get(x)) === null || _a === void 0 ? void 0 : _a.pinned); });
550
+ if (next === order)
551
+ return; // extremo pineado o no-op
552
+ this.coListReorder.emit({ value: next, item: byId.get(fromId) });
553
+ }
554
+ captureRowTops() {
555
+ var _a;
556
+ const tops = new Map();
557
+ (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.co-option-list__option[data-id]').forEach((row) => tops.set(row.dataset.id, row.getBoundingClientRect().top));
558
+ return tops;
559
+ }
560
+ /**
561
+ * FLIP de cada reacomodo (swap del live-preview y revert): las filas arrancan
562
+ * desplazadas a su posición visual anterior (transform) y transicionan a la
563
+ * nueva. Solo transform, con tokens de motion (reduced-motion se resuelve
564
+ * global vía zeroing). Swaps mid-drag: todo ease-out (fluido, sin rebote);
565
+ * spring solo para la fila movida en el settle del revert.
566
+ * Batcheado (writes → reads → writes, un solo flush) y robusto a interrupciones:
567
+ * neutraliza transforms de un FLIP anterior ANTES de medir el layout nuevo.
568
+ */
569
+ runFlip() {
570
+ var _a, _b, _c;
571
+ if (!this.pendingFlip)
572
+ return;
573
+ const { tops, movedId, spring } = this.pendingFlip;
574
+ this.pendingFlip = undefined;
575
+ const rows = Array.from((_b = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.co-option-list__option[data-id]')) !== null && _b !== void 0 ? _b : []);
576
+ // La fila lifted (drag por puntero activo) queda FUERA del FLIP: su posición
577
+ // la dicta el puntero (positionLifted re-ancla tras el render).
578
+ const liftedId = ((_c = this.ptrDrag) === null || _c === void 0 ? void 0 : _c.started) ? this.ptrDrag.id : null;
579
+ for (const row of rows) {
580
+ if (row.dataset.id === liftedId)
581
+ continue;
582
+ row.style.transition = 'none';
583
+ row.style.transform = '';
584
+ }
585
+ const moves = [];
586
+ for (const row of rows) {
587
+ const id = row.dataset.id;
588
+ if (id === liftedId)
589
+ continue;
590
+ const first = tops.get(id);
591
+ if (first === undefined)
592
+ continue;
593
+ const delta = first - row.getBoundingClientRect().top;
594
+ if (delta)
595
+ moves.push({ row, delta, spring: spring && id === movedId });
596
+ }
597
+ for (const { row, delta } of moves)
598
+ row.style.transform = `translateY(${delta}px)`;
599
+ void this.el.offsetHeight; // flush único: fija el estado invertido antes de animar
600
+ for (const row of rows) {
601
+ if (row.dataset.id === liftedId)
602
+ continue;
603
+ const mv = moves.find((m) => m.row === row);
604
+ if (!mv) {
605
+ row.style.transition = '';
606
+ continue;
607
+ }
608
+ const ease = mv.spring ? 'var(--co-motion-ease-spring)' : 'var(--co-motion-ease-out)';
609
+ row.style.transition = `transform var(--co-motion-duration-base) ${ease}`;
610
+ row.style.transform = '';
611
+ row.addEventListener('transitionend', () => { row.style.transition = ''; }, { once: true });
612
+ }
308
613
  }
309
614
  resetDragState() {
310
615
  this.armedKey = '';
@@ -319,6 +624,30 @@ export class CoOptionList {
319
624
  if (hasMore && scrollTop + clientHeight >= scrollHeight - 40)
320
625
  this.coLoadMore.emit();
321
626
  }
627
+ /** El infinite scroll asume que cada página desborda el contenedor. Con
628
+ * paneles altos (--co-option-list-max-height) una página puede caber entera
629
+ * → sin overflow no hay evento de scroll y la paginación queda muerta. Tras
630
+ * cada render, si el contenido no deja distancia scrolleable (mismo slack
631
+ * de 40px que maybeLoadMore) y hay más resultados, pide otra página. Se
632
+ * emite UNA vez por longitud de lista: si el host no responde no re-emite,
633
+ * y el append de la página siguiente re-habilita el check. */
634
+ fillViewport() {
635
+ var _a, _b;
636
+ const count = this.parsedItems.length;
637
+ if (this.loading || count === 0 || count === this.lastFillLen)
638
+ return;
639
+ const { hasMore } = deriveMore(count, this.total, this.hasMore);
640
+ if (!hasMore)
641
+ return;
642
+ const vp = (_b = (_a = this.osInstance) === null || _a === void 0 ? void 0 : _a.elements().viewport) !== null && _b !== void 0 ? _b : this.optionsEl;
643
+ // clientHeight 0 = panel oculto/sin layout: las métricas mienten, no pedir.
644
+ if (!vp || vp.clientHeight === 0)
645
+ return;
646
+ if (vp.scrollHeight - vp.clientHeight <= 40) {
647
+ this.lastFillLen = count;
648
+ this.coLoadMore.emit();
649
+ }
650
+ }
322
651
  scrollActiveIntoView() {
323
652
  requestAnimationFrame(() => {
324
653
  var _a, _b;
@@ -343,18 +672,34 @@ export class CoOptionList {
343
672
  return label;
344
673
  return [seg.pre, h("span", { class: "co-option-list__match" }, seg.match), seg.post];
345
674
  }
675
+ /** Pill junto al label. Con `tooltip` va envuelto en un `co-tooltip` — el
676
+ * label del badge se abrevia (3 letras en el de workspace) y sin el texto
677
+ * completo al hover no hay forma de saber a qué se refiere. Sin `tooltip`
678
+ * renderiza el span pelado, igual que antes (mismo patrón que la prop
679
+ * `name` de co-avatar). */
680
+ renderBadge(badge) {
681
+ const pill = (h("span", { class: "co-option-list__badge", style: badge.color ? { backgroundColor: badge.color, color: 'var(--co-color-base-blanco, #fff)' } : undefined }, badge.label));
682
+ if (!badge.tooltip)
683
+ return pill;
684
+ return (h("co-tooltip", { class: "co-option-list__badge-tip", content: badge.tooltip }, pill));
685
+ }
346
686
  renderRow(item, index, selectedIds) {
347
687
  const isSelected = selectedIds.includes(item._id);
348
- const canDrag = this.reorderable && this.selectedFirst && isSelected && !this.term;
688
+ // Dos modos de drag EXCLUYENTES: bloque seleccionado = drag por puntero
689
+ // (motion.dev-like); lista completa (listReorderable) = HTML5 DnD con
690
+ // indicador de línea.
691
+ const ptrDragRow = !this.listDragActive && this.reorderable && this.selectedFirst && isSelected && !this.term;
692
+ const listDragRow = this.listDragActive && !item.pinned && !this.term;
349
693
  return (h("div", { class: {
350
694
  'co-option-list__option': true,
351
695
  'co-option-list__option--selected': isSelected,
352
696
  'co-option-list__option--active': index === this.activeIndex,
353
697
  'co-option-list__option--disabled': !!item.disabled,
354
- 'co-option-list__option--dragging': this.dragKey === item._id,
355
- 'co-option-list__option--drop-before': this.overKey === item._id && !this.dropAfter,
356
- 'co-option-list__option--drop-after': this.overKey === item._id && this.dropAfter,
357
- }, key: item._id, id: `co-optlist-${index}`, role: "option", "aria-selected": isSelected ? 'true' : 'false', "aria-disabled": item.disabled ? 'true' : 'false', draggable: canDrag && this.armedKey === item._id, onClick: () => !item.disabled && this.pick(item), onMouseEnter: () => { this.activeIndex = index; }, onDragStart: canDrag ? (e) => this.handleRowDragStart(e, item._id) : undefined, onDragOver: canDrag ? (e) => this.handleRowDragOver(e, item._id) : undefined, onDrop: canDrag ? (e) => this.handleRowDrop(e, item._id) : undefined, onDragEnd: canDrag ? this.handleRowDragEnd : undefined, onDragLeave: canDrag ? (e) => this.handleRowDragLeave(e, item._id) : undefined }, canDrag && (h("span", { class: "co-option-list__drag-handle", part: "drag-handle", title: "Drag to reorder", onMouseDown: () => (this.armedKey = item._id), onClick: (e) => e.stopPropagation() }, h("co-icon", { name: "dots-six-vertical", size: 16 }))), this.renderLeading(item), h("div", { class: "co-option-list__text" }, h("span", { class: "co-option-list__title" }, h("span", { class: "co-option-list__label", style: item.labelColor ? { color: item.labelColor, fontWeight: '600' } : undefined }, this.renderLabelText(item.label)), item.suffix && h("span", { class: "co-option-list__suffix" }, "- ", item.suffix), item.badge && (h("span", { class: "co-option-list__badge", style: item.badge.color ? { backgroundColor: item.badge.color, color: 'var(--co-color-base-blanco, #fff)' } : undefined }, item.badge.label))), item.description && h("span", { class: "co-option-list__desc" }, item.description)), isSelected && this.removableItems && this.multiple && (h("button", { class: "co-option-list__row-action", type: "button", tabIndex: -1, "aria-label": `Remove ${item.label}`, onClick: (e) => { e.stopPropagation(); this.coRemoveItem.emit(item._id); } }, h("co-icon", { name: "x-circle", size: 16, weight: "fill" }))), isSelected && !this.removableItems && this.selectedAffordance === 'deselect' && (h("button", { class: "co-option-list__row-action", type: "button", tabIndex: -1, "aria-label": `Deselect ${item.label}`, onClick: (e) => { e.stopPropagation(); this.deselectItem(item); } }, h("co-icon", { name: "x-circle", size: 16, weight: "fill" }))), isSelected && !this.removableItems && this.selectedAffordance === 'check' && (h("co-icon", { name: "check", size: 16, class: "co-option-list__check" }))));
698
+ 'co-option-list__option--dragging': this.listDragActive && this.dragKey === item._id,
699
+ 'co-option-list__option--lifted': !this.listDragActive && this.dragKey === item._id,
700
+ 'co-option-list__option--drop-before': this.listDragActive && this.overKey === item._id && !this.dropAfter,
701
+ 'co-option-list__option--drop-after': this.listDragActive && this.overKey === item._id && this.dropAfter,
702
+ }, key: item._id, id: `co-optlist-${index}`, "data-id": item._id, role: "option", "aria-selected": isSelected ? 'true' : 'false', "aria-disabled": item.disabled ? 'true' : 'false', draggable: listDragRow && this.armedKey === item._id, onClick: () => !item.disabled && this.pick(item), onMouseEnter: () => { this.activeIndex = index; }, onDragStart: listDragRow ? (e) => this.handleRowDragStart(e, item._id) : undefined, onDragOver: listDragRow ? (e) => this.handleRowDragOver(e, item._id) : undefined, onDrop: listDragRow ? (e) => this.handleRowDrop(e, item._id) : undefined, onDragEnd: listDragRow ? this.handleRowDragEnd : undefined, onDragLeave: listDragRow ? (e) => this.handleRowDragLeave(e, item._id) : undefined }, (ptrDragRow || listDragRow) && (h("span", { class: "co-option-list__drag-handle", part: "drag-handle", title: "Drag to reorder", onMouseDown: listDragRow ? () => (this.armedKey = item._id) : undefined, onPointerDown: ptrDragRow ? (e) => this.startPointerDrag(e, item._id) : undefined, onClick: (e) => e.stopPropagation() }, h("co-icon", { name: "dots-six-vertical", size: 16 }))), this.renderLeading(item), h("div", { class: "co-option-list__text" }, h("span", { class: "co-option-list__title" }, h("span", { class: "co-option-list__label", style: item.labelColor ? { color: item.labelColor, fontWeight: '600' } : undefined }, this.renderLabelText(item.label)), item.suffix && h("span", { class: "co-option-list__suffix" }, "- ", item.suffix), item.badge && this.renderBadge(item.badge)), item.description && h("span", { class: "co-option-list__desc" }, item.description)), this.pinnable && (h("button", { class: { 'co-option-list__pin': true, 'co-option-list__pin--active': !!item.pinned }, type: "button", tabIndex: -1, "aria-label": item.pinned ? `Unpin ${item.label}` : `Pin ${item.label}`, "aria-pressed": item.pinned ? 'true' : 'false', onClick: (e) => { e.stopPropagation(); this.coPinToggle.emit({ item }); } }, h("co-icon", { name: "push-pin", size: 16, weight: item.pinned ? 'fill' : 'regular' }))), isSelected && this.removableItems && this.multiple && (h("button", { class: "co-option-list__row-action", type: "button", tabIndex: -1, "aria-label": `Remove ${item.label}`, onClick: (e) => { e.stopPropagation(); this.coRemoveItem.emit(item._id); } }, h("co-icon", { name: "x-circle", size: 16, weight: "fill" }))), isSelected && !this.removableItems && this.selectedAffordance === 'deselect' && (h("button", { class: "co-option-list__row-action", type: "button", tabIndex: -1, "aria-label": `Deselect ${item.label}`, onClick: (e) => { e.stopPropagation(); this.deselectItem(item); } }, h("co-icon", { name: "x-circle", size: 16, weight: "fill" }))), isSelected && !this.removableItems && this.selectedAffordance === 'check' && (h("co-icon", { name: "check", size: 16, class: "co-option-list__check" }))));
358
703
  }
359
704
  renderVirtual(items, selectedIds) {
360
705
  const { totalHeight, startIdx, endIdx, offsetY } = virtualSlice(this.scrollTop, items.length);
@@ -365,11 +710,11 @@ export class CoOptionList {
365
710
  const selectedIds = this.selectedIds;
366
711
  const { hasMore, remaining } = deriveMore(this.parsedItems.length, this.total, this.hasMore);
367
712
  const showClear = !!this.clearOptionLabel && selectedIds.length > 0;
368
- return (h("div", { key: '1002a1993d3a13db23898cba6b8bd14aade3d8ac', class: "co-option-list", onKeyDown: this.onRootKeyDown }, this.searchable && (h("div", { key: 'a3f6d8a19f4dc7d7aac1898b053de0ccabc5ce6d', class: "co-option-list__search", part: "search" }, h("co-icon", { key: 'a3972500879ae7e5941841a13bf03af6dccc10f0', name: "magnifying-glass", size: 16 }), h("input", { key: '37861b77d5848ad9b8d0cfaf7c7ac2699e51000f', class: "co-option-list__search-input", type: "text", placeholder: this.searchPlaceholder, value: this.term, onInput: this.onSearchInput, ref: (el) => (this.searchInputEl = el), role: "combobox", "aria-expanded": "true", "aria-autocomplete": "list" }))), h("div", { key: '652fbbbbb6145c8c6bffc354a1435c09bc3a4e62', class: "co-option-list__options", part: "options", role: "listbox", "aria-multiselectable": this.multiple ? 'true' : 'false', ref: (el) => (this.optionsEl = el), onScroll: this.onNativeScroll }, h("div", { key: 'e0b68873c27f2d08a9edc0196384b3f75bd95e05', class: "co-option-list__inner" }, showClear && (h("button", { key: '7e4716349f9af4980fac732fdfe4013fc81e7b18', class: "co-option-list__clear-row", type: "button", onClick: () => this.coClearSelection.emit() }, h("co-icon", { key: '3d23e2a85e9387f364b0a5c705ca034020c83e43', name: "x-circle", size: 14 }), h("span", { key: '8fcc642763adbba7ca79507d53f18de157c61443' }, this.clearOptionLabel))), this.loading && items.length === 0 && (h("div", { key: '3ea9842f365d5e51338ff5799fccb27ca7bfe466', class: "co-option-list__loading" }, h("co-loader", { key: '306972ee829c41ae32ba69bd02b4dec839842a03', size: "sm" }))), !this.loading && items.length === 0 && (h("div", { key: 'b184393bc7348370fc6fc84ff7a38584a7fc2fd5', class: "co-option-list__empty" }, h("co-icon", { key: '39e9e495a62f285d22bbb5197227d48a52dd5c40', name: "magnifying-glass", size: 20 }), h("span", { key: '6faefea453fbf0ce3083c863b9c822a1902466b3' }, this.emptyMessage))), items.length > 0 && this.virtual
713
+ return (h("div", { key: 'a5754821517230b914fd9f23b024afc523e4ee9d', class: "co-option-list", onKeyDown: this.onRootKeyDown }, this.searchable && (h("div", { key: '9988f2e6834b5c8cf4c4832d609fb6665c9a46cc', class: "co-option-list__search", part: "search" }, h("co-icon", { key: '8b8f2e72fb6f9aa9b498455757aefe943627af80', name: "magnifying-glass", size: 16 }), h("input", { key: 'e434b657655cb855ef77611671db90a7e8f78850', class: "co-option-list__search-input", type: "text", placeholder: this.searchPlaceholder, value: this.term, onInput: this.onSearchInput, ref: (el) => (this.searchInputEl = el), role: "combobox", "aria-expanded": "true", "aria-autocomplete": "list" }))), h("div", { key: '9e3c8ff1cb005274b74cf50b1c8db469958bbfc0', class: "co-option-list__options", part: "options", role: "listbox", "aria-multiselectable": this.multiple ? 'true' : 'false', ref: (el) => (this.optionsEl = el), onScroll: this.onNativeScroll }, h("div", { key: '8087c3de1d857b562918a358f98a7a195cbe66d7', class: "co-option-list__inner" }, showClear && (h("button", { key: 'b067aedd7e0dbb29db12c35d0d217147359bc5f7', class: "co-option-list__clear-row", type: "button", onClick: () => this.coClearSelection.emit() }, h("co-icon", { key: '406e84a7bcc5d8509383527caa0f49d5f93fda53', name: "x-circle", size: 14 }), h("span", { key: '9347b010b58d51363a68aab65781cae7de31cca1' }, this.clearOptionLabel))), this.loading && items.length === 0 && (h("div", { key: '774fcb348a3553a945b70de822621ee24e410808', class: "co-option-list__loading" }, h("co-loader", { key: 'f760bf3ec0b27cfd0c57e2a56a613b8390faa935', size: "sm" }))), !this.loading && items.length === 0 && (h("div", { key: 'f018550513d4057bdbddaf64846ba7d4cd016a45', class: "co-option-list__empty" }, h("co-icon", { key: '7925a8b7c385389b1d59548d5d550a0d7f0d163e', name: "magnifying-glass", size: 20 }), h("span", { key: 'b31e52eef274434599db7ff217a9bfc634ebdf7f' }, this.emptyMessage))), items.length > 0 && this.virtual
369
714
  ? this.renderVirtual(items, selectedIds)
370
715
  : buildRows(items).map((row) => row.kind === 'header'
371
716
  ? h("div", { class: "co-option-list__group", role: "presentation" }, row.label)
372
- : this.renderRow(row.item, row.index, selectedIds)), this.loading && items.length > 0 && (h("div", { key: '9a4cc5cf05196070febf62c6bf309b45fe8f5974', class: "co-option-list__loading-more" }, h("co-loader", { key: '0eb546749b37b5cd83d88bc6c40b34b3b5b04532', size: "sm" }))), !this.loading && hasMore && remaining > 0 && (h("div", { key: '06c4deab21fe6c56dcda175ba9b4f37add4c2e8a', class: "co-option-list__more" }, remaining, " more results")))), h("slot", { key: 'eaa788987749e25086a3be92df591e767c33c65b', name: "footer" })));
717
+ : this.renderRow(row.item, row.index, selectedIds)), this.loading && items.length > 0 && (h("div", { key: '7de231a83a96a2aca0cb240a68c3c9e6ab9b475c', class: "co-option-list__loading-more" }, h("co-loader", { key: '087234fb45c3cbea3bd3f2888957d3b2751753ad', size: "sm" }))), !this.loading && hasMore && remaining > 0 && (h("div", { key: '456bc75bb53a3f0d01f7fd850ca4b8227baf326d', class: "co-option-list__more" }, remaining, " more results")))), h("slot", { key: '2935b1dd65ec2409c18c3f72e0200d5ed1c19323', name: "footer" })));
373
718
  }
374
719
  static get is() { return "co-option-list"; }
375
720
  static get encapsulation() { return "shadow"; }
@@ -559,6 +904,46 @@ export class CoOptionList {
559
904
  "attribute": "reorderable",
560
905
  "defaultValue": "false"
561
906
  },
907
+ "pinnable": {
908
+ "type": "boolean",
909
+ "mutable": false,
910
+ "complexType": {
911
+ "original": "boolean",
912
+ "resolved": "boolean",
913
+ "references": {}
914
+ },
915
+ "required": false,
916
+ "optional": false,
917
+ "docs": {
918
+ "tags": [],
919
+ "text": "Bot\u00F3n push-pin por fila (siempre visible). Emite coPinToggle; el estado\npinned viene en item.pinned \u2014 el componente NO lo muta (controlado)."
920
+ },
921
+ "getter": false,
922
+ "setter": false,
923
+ "reflect": false,
924
+ "attribute": "pinnable",
925
+ "defaultValue": "false"
926
+ },
927
+ "listReorderable": {
928
+ "type": "boolean",
929
+ "mutable": false,
930
+ "complexType": {
931
+ "original": "boolean",
932
+ "resolved": "boolean",
933
+ "references": {}
934
+ },
935
+ "required": false,
936
+ "optional": false,
937
+ "docs": {
938
+ "tags": [],
939
+ "text": "Drag-reorder de la LISTA completa (no del bloque seleccionado): handle en\nfilas no-pineadas, emite coListReorder con el orden visible completo.\nIndependiente de multiple/selectedFirst. No soportado con `virtual`."
940
+ },
941
+ "getter": false,
942
+ "setter": false,
943
+ "reflect": false,
944
+ "attribute": "list-reorderable",
945
+ "defaultValue": "false"
946
+ },
562
947
  "searchable": {
563
948
  "type": "boolean",
564
949
  "mutable": false,
@@ -958,6 +1343,50 @@ export class CoOptionList {
958
1343
  }
959
1344
  }
960
1345
  }
1346
+ }, {
1347
+ "method": "coPinToggle",
1348
+ "name": "coPinToggle",
1349
+ "bubbles": false,
1350
+ "cancelable": true,
1351
+ "composed": false,
1352
+ "docs": {
1353
+ "tags": [],
1354
+ "text": "Toggle de pin de una fila (pinnable)."
1355
+ },
1356
+ "complexType": {
1357
+ "original": "{ item: OptionListItem }",
1358
+ "resolved": "{ item: OptionListItem; }",
1359
+ "references": {
1360
+ "OptionListItem": {
1361
+ "location": "import",
1362
+ "path": "./optionListLogic",
1363
+ "id": "src/components/co-option-list/optionListLogic.ts::OptionListItem",
1364
+ "referenceLocation": "OptionListItem"
1365
+ }
1366
+ }
1367
+ }
1368
+ }, {
1369
+ "method": "coListReorder",
1370
+ "name": "coListReorder",
1371
+ "bubbles": false,
1372
+ "cancelable": true,
1373
+ "composed": false,
1374
+ "docs": {
1375
+ "tags": [],
1376
+ "text": "Drag-reorder de lista completa (listReorderable): orden visible + \u00EDtem movido."
1377
+ },
1378
+ "complexType": {
1379
+ "original": "{ value: string[]; item: OptionListItem }",
1380
+ "resolved": "{ value: string[]; item: OptionListItem; }",
1381
+ "references": {
1382
+ "OptionListItem": {
1383
+ "location": "import",
1384
+ "path": "./optionListLogic",
1385
+ "id": "src/components/co-option-list/optionListLogic.ts::OptionListItem",
1386
+ "referenceLocation": "OptionListItem"
1387
+ }
1388
+ }
1389
+ }
961
1390
  }];
962
1391
  }
963
1392
  static get methods() {
@@ -996,6 +1425,27 @@ export class CoOptionList {
996
1425
  "tags": []
997
1426
  }
998
1427
  },
1428
+ "scrollToSelected": {
1429
+ "complexType": {
1430
+ "signature": "() => Promise<void>",
1431
+ "parameters": [],
1432
+ "references": {
1433
+ "Promise": {
1434
+ "location": "global",
1435
+ "id": "global::Promise"
1436
+ },
1437
+ "HTMLElement": {
1438
+ "location": "global",
1439
+ "id": "global::HTMLElement"
1440
+ }
1441
+ },
1442
+ "return": "Promise<void>"
1443
+ },
1444
+ "docs": {
1445
+ "text": "Ancla la sesi\u00F3n del panel en la selecci\u00F3n: highlight sobre la primera fila\nseleccionada y scroll hasta dejarla visible (paridad resetActiveIndex de\nco-select). El host la llama al ABRIR su panel \u2014 la lista queda montada\nentre aperturas y no sabe cu\u00E1ndo se abre (mismo contrato que\nfocusSearch/snapshotOrder). Espera layout real igual que focusSearch: el\npanel se hace visible frames despu\u00E9s y un scroll sobre subtree oculto se\nclampea a 0 en silencio.",
1446
+ "tags": []
1447
+ }
1448
+ },
999
1449
  "handleKey": {
1000
1450
  "complexType": {
1001
1451
  "signature": "(e: KeyboardEvent) => Promise<boolean>",