@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.
- package/custom-elements.json +375 -25
- package/dist/cjs/co-audio-player.cjs.entry.js +107 -18
- package/dist/cjs/co-avatar_2.cjs.entry.js +7 -31
- package/dist/cjs/co-button.cjs.entry.js +6 -4
- package/dist/cjs/co-calendar-month_2.cjs.entry.js +59 -2
- package/dist/cjs/co-checkbox.cjs.entry.js +10 -4
- package/dist/cjs/co-chip_2.cjs.entry.js +388 -18
- package/dist/cjs/co-color-picker.cjs.entry.js +36 -3
- package/dist/cjs/co-combobox.cjs.entry.js +44 -4
- package/dist/cjs/co-event-popover.cjs.entry.js +5 -2
- package/dist/cjs/co-file-field.cjs.entry.js +12 -6
- package/dist/cjs/co-icon-button.cjs.entry.js +5 -2
- package/dist/cjs/co-icon.cjs.entry.js +17 -1
- package/dist/cjs/co-input.cjs.entry.js +21 -1
- package/dist/cjs/co-loader.cjs.entry.js +1 -1
- package/dist/cjs/co-number-field.cjs.entry.js +22 -2
- package/dist/cjs/co-ref-field.cjs.entry.js +87 -13
- package/dist/cjs/co-select.cjs.entry.js +273 -8
- package/dist/cjs/co-tags-field.cjs.entry.js +1 -1
- package/dist/cjs/cobalt.cjs.js +1 -1
- package/dist/cjs/color-YhUkm10t.js +32 -0
- package/dist/cjs/fieldChip-BLzo9MEV.js +7 -0
- package/dist/cjs/index-DK-2Lzmf.js +4 -4
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cobalt/cobalt.esm.js +1 -1
- package/dist/cobalt/p-0c463d9a.entry.js +1 -0
- package/dist/cobalt/p-0caa059c.entry.js +1 -0
- package/dist/cobalt/{p-3ced4269.entry.js → p-2828ecf6.entry.js} +1 -1
- package/dist/cobalt/p-2f88d151.entry.js +1 -0
- package/dist/cobalt/p-409f28bb.entry.js +1 -0
- package/dist/cobalt/{p-18af9e44.entry.js → p-568cfe8d.entry.js} +1 -1
- package/dist/cobalt/p-6bf814f9.entry.js +1 -0
- package/dist/cobalt/p-7ea87b75.entry.js +1 -0
- package/dist/cobalt/p-8b4b3589.entry.js +1 -0
- package/dist/cobalt/p-93c68029.entry.js +1 -0
- package/dist/cobalt/p-BG4WRR22.js +1 -0
- package/dist/cobalt/p-a2d31248.entry.js +1 -0
- package/dist/cobalt/p-bcedbd73.entry.js +1 -0
- package/dist/cobalt/p-dfd25f1d.entry.js +1 -0
- package/dist/cobalt/p-e364b8a5.entry.js +1 -0
- package/dist/cobalt/p-f00be11f.entry.js +1 -0
- package/dist/cobalt/p-f25967fb.entry.js +1 -0
- package/dist/cobalt/p-f5f1b463.entry.js +1 -0
- package/dist/cobalt/p-fef5db54.entry.js +1 -0
- package/dist/cobalt/p-mAGnZXRn.js +1 -0
- package/dist/collection/components/co-audio-player/co-audio-player.js +81 -17
- package/dist/collection/components/co-audio-player/co-audio-player.utils.js +27 -2
- package/dist/collection/components/co-autocomplete/co-autocomplete.js +1 -1
- package/dist/collection/components/co-avatar/co-avatar.js +5 -1
- package/dist/collection/components/co-avatar-group/co-avatar-group.js +1 -1
- package/dist/collection/components/co-button/co-button.css +7 -0
- package/dist/collection/components/co-button/co-button.js +7 -5
- package/dist/collection/components/co-calendar-month/co-calendar-month.js +59 -2
- package/dist/collection/components/co-checkbox/co-checkbox.css +22 -0
- package/dist/collection/components/co-checkbox/co-checkbox.js +9 -3
- package/dist/collection/components/co-checkbox-group/co-checkbox-group.js +1 -1
- package/dist/collection/components/co-color-picker/co-color-picker.css +7 -0
- package/dist/collection/components/co-color-picker/co-color-picker.js +35 -2
- package/dist/collection/components/co-combobox/co-combobox.css +7 -0
- package/dist/collection/components/co-combobox/co-combobox.js +44 -4
- package/dist/collection/components/co-command-search/co-command-search.js +1 -1
- package/dist/collection/components/co-data-table/co-data-table.js +1 -1
- package/dist/collection/components/co-date-range-picker/co-date-range-picker.js +2 -2
- package/dist/collection/components/co-event-popover/co-event-popover.js +5 -2
- package/dist/collection/components/co-file-field/co-file-field.css +7 -4
- package/dist/collection/components/co-file-field/co-file-field.js +8 -5
- package/dist/collection/components/co-icon/iconLoader.js +17 -1
- package/dist/collection/components/co-icon-button/co-icon-button.css +7 -0
- package/dist/collection/components/co-icon-button/co-icon-button.js +6 -3
- package/dist/collection/components/co-input/co-input.css +13 -0
- package/dist/collection/components/co-input/co-input.js +21 -0
- package/dist/collection/components/co-loader/co-loader.css +5 -3
- package/dist/collection/components/co-number-field/co-number-field.js +23 -2
- package/dist/collection/components/co-option-list/co-option-list.css +45 -2
- package/dist/collection/components/co-option-list/co-option-list.js +468 -18
- package/dist/collection/components/co-option-list/optionListLogic.js +25 -0
- package/dist/collection/components/co-popover/co-popover.js +1 -1
- package/dist/collection/components/co-radio-group/co-radio-group.js +1 -1
- package/dist/collection/components/co-ref-field/co-ref-field.css +49 -0
- package/dist/collection/components/co-ref-field/co-ref-field.js +240 -12
- package/dist/collection/components/co-segmented-bar/co-segmented-bar.js +1 -1
- package/dist/collection/components/co-select/co-select.css +19 -0
- package/dist/collection/components/co-select/co-select.js +275 -9
- package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.js +1 -1
- package/dist/collection/components/co-toast/co-toast.js +2 -2
- package/dist/collection/components/co-transfer-list/co-transfer-list.js +1 -1
- package/dist/collection/utils/fieldChip.js +1 -1
- package/dist/collection/utils/fileI18n.js +3 -0
- package/dist/components/co-accordion.js +1 -1
- package/dist/components/co-action-bar.js +1 -1
- package/dist/components/co-audio-player.js +1 -1
- package/dist/components/co-autocomplete.js +1 -1
- package/dist/components/co-avatar-group.js +1 -1
- package/dist/components/co-avatar.js +1 -1
- package/dist/components/co-breadcrumb-item.js +1 -1
- package/dist/components/co-breadcrumb.js +1 -1
- package/dist/components/co-button.js +1 -1
- package/dist/components/co-calendar-month.js +1 -1
- package/dist/components/co-calendar-timegrid.js +1 -1
- package/dist/components/co-calendar.js +1 -1
- package/dist/components/co-carousel.js +1 -1
- package/dist/components/co-checkbox-group.js +1 -1
- package/dist/components/co-checkbox.js +1 -1
- package/dist/components/co-chip.js +1 -1
- package/dist/components/co-color-picker.js +1 -1
- package/dist/components/co-column-picker.js +1 -1
- package/dist/components/co-combobox.js +1 -1
- package/dist/components/co-command-search.js +1 -1
- package/dist/components/co-data-table-pagination.js +1 -1
- package/dist/components/co-data-table.js +1 -1
- package/dist/components/co-date-field.js +1 -1
- package/dist/components/co-date-picker.js +1 -1
- package/dist/components/co-date-range-picker.js +1 -1
- package/dist/components/co-date-range.js +1 -1
- package/dist/components/co-date-time-picker.js +1 -1
- package/dist/components/co-drawer.js +1 -1
- package/dist/components/co-drive-card.js +1 -1
- package/dist/components/co-drop-zone.js +1 -1
- package/dist/components/co-emoji-picker.js +1 -1
- package/dist/components/co-empty-state.js +1 -1
- package/dist/components/co-event-calendar.js +1 -1
- package/dist/components/co-event-popover.js +1 -1
- package/dist/components/co-fab.js +1 -1
- package/dist/components/co-file-field.js +1 -1
- package/dist/components/co-file-type-tile.js +1 -1
- package/dist/components/co-helper-text.js +1 -1
- package/dist/components/co-icon-button.js +1 -1
- package/dist/components/co-icon.js +1 -1
- package/dist/components/co-input.js +1 -1
- package/dist/components/co-json-field.js +1 -1
- package/dist/components/co-lightbox.js +1 -1
- package/dist/components/co-list-footer.js +1 -1
- package/dist/components/co-list-item.js +1 -1
- package/dist/components/co-loader.js +1 -1
- package/dist/components/co-menu-item.js +1 -1
- package/dist/components/co-modal.js +1 -1
- package/dist/components/co-number-field.js +1 -1
- package/dist/components/co-option-list.js +1 -1
- package/dist/components/co-page-header.js +1 -1
- package/dist/components/co-phone-field.js +1 -1
- package/dist/components/co-radio-group.js +1 -1
- package/dist/components/co-rating.js +1 -1
- package/dist/components/co-ref-field.js +1 -1
- package/dist/components/co-rich-text-editor.js +1 -1
- package/dist/components/co-rich-text-toolbar.js +1 -1
- package/dist/components/co-select.js +1 -1
- package/dist/components/co-sidebar-nav.js +1 -1
- package/dist/components/co-slider.js +1 -1
- package/dist/components/co-switch.js +1 -1
- package/dist/components/co-tab.js +1 -1
- package/dist/components/co-tags-field.js +1 -1
- package/dist/components/co-textarea.js +1 -1
- package/dist/components/co-toast.js +1 -1
- package/dist/components/co-toggle-button.js +1 -1
- package/dist/components/co-transfer-list.js +1 -1
- package/dist/components/co-video.js +1 -1
- package/dist/components/{p-CklsvHeL.js → p-B0Dc-I_C.js} +1 -1
- package/dist/components/{p-DzoNGEDU.js → p-BH184F0X.js} +1 -1
- package/dist/components/{p-BGD3oQ73.js → p-BHYtxTzM.js} +1 -1
- package/dist/components/{p-mom5kiBa.js → p-BTQEg3UO.js} +1 -1
- package/dist/components/p-BZIB4JDs.js +1 -0
- package/dist/components/p-Bbny3WUc.js +1 -0
- package/dist/components/{p-D5QJpmqf.js → p-Bxk96Zgc.js} +1 -1
- package/dist/components/p-C1Kv3zYZ.js +1 -0
- package/dist/components/p-C4U2tbRp.js +1 -0
- package/dist/components/{p-CyMaOb1j.js → p-CA_JAK9s.js} +1 -1
- package/dist/components/{p-AvSaw4Ua.js → p-CR0izsJC.js} +1 -1
- package/dist/components/p-CuZXTvDM.js +1 -0
- package/dist/components/{p-_131DL6m.js → p-D4qzGifz.js} +1 -1
- package/dist/components/{p-BsQQ7Mki.js → p-D5EdMieb.js} +1 -1
- package/dist/components/p-Dabi98BI.js +1 -0
- package/dist/components/p-DbipMAyT.js +1 -0
- package/dist/components/p-DgUBcJIS.js +1 -0
- package/dist/components/p-Dj1EZ5qD.js +1 -0
- package/dist/components/{p-DkmKOF60.js → p-P8wvwhM2.js} +1 -1
- package/dist/components/{p-nwy6X1QT.js → p-hfGFsvaD.js} +1 -1
- package/dist/esm/co-audio-player.entry.js +107 -18
- package/dist/esm/co-avatar_2.entry.js +6 -30
- package/dist/esm/co-button.entry.js +6 -4
- package/dist/esm/co-calendar-month_2.entry.js +59 -2
- package/dist/esm/co-checkbox.entry.js +10 -4
- package/dist/esm/co-chip_2.entry.js +388 -18
- package/dist/esm/co-color-picker.entry.js +36 -3
- package/dist/esm/co-combobox.entry.js +44 -4
- package/dist/esm/co-event-popover.entry.js +5 -2
- package/dist/esm/co-file-field.entry.js +12 -6
- package/dist/esm/co-icon-button.entry.js +5 -2
- package/dist/esm/co-icon.entry.js +17 -1
- package/dist/esm/co-input.entry.js +21 -1
- package/dist/esm/co-loader.entry.js +1 -1
- package/dist/esm/co-number-field.entry.js +22 -2
- package/dist/esm/co-ref-field.entry.js +87 -13
- package/dist/esm/co-select.entry.js +273 -8
- package/dist/esm/co-tags-field.entry.js +1 -1
- package/dist/esm/cobalt.js +1 -1
- package/dist/esm/color-BG4WRR22.js +30 -0
- package/dist/esm/fieldChip-DsAfq1e0.js +5 -0
- package/dist/esm/index-CrtiywTB.js +4 -4
- package/dist/esm/loader.js +1 -1
- package/dist/types/components/co-audio-player/co-audio-player.d.ts +13 -0
- package/dist/types/components/co-audio-player/co-audio-player.utils.d.ts +18 -1
- package/dist/types/components/co-button/co-button.d.ts +3 -1
- package/dist/types/components/co-calendar-month/co-calendar-month.d.ts +7 -0
- package/dist/types/components/co-checkbox/co-checkbox.d.ts +1 -0
- package/dist/types/components/co-color-picker/co-color-picker.d.ts +15 -0
- package/dist/types/components/co-combobox/co-combobox.d.ts +17 -0
- package/dist/types/components/co-icon-button/co-icon-button.d.ts +3 -0
- package/dist/types/components/co-input/co-input.d.ts +9 -0
- package/dist/types/components/co-number-field/co-number-field.d.ts +9 -0
- package/dist/types/components/co-option-list/co-option-list.d.ts +79 -0
- package/dist/types/components/co-option-list/optionListLogic.d.ts +23 -1
- package/dist/types/components/co-ref-field/co-ref-field.d.ts +46 -0
- package/dist/types/components/co-select/co-select.d.ts +67 -0
- package/dist/types/components.d.ts +110 -4
- package/dist/types/utils/fieldChip.d.ts +5 -0
- package/dist/types/utils/fileI18n.d.ts +1 -0
- package/package.json +4 -4
- package/dist/cjs/fieldChip-xNJPEFcS.js +0 -7
- package/dist/cobalt/p-02ac492f.entry.js +0 -1
- package/dist/cobalt/p-0ccb672b.entry.js +0 -1
- package/dist/cobalt/p-2d81b292.entry.js +0 -1
- package/dist/cobalt/p-4a503187.entry.js +0 -1
- package/dist/cobalt/p-55566b37.entry.js +0 -1
- package/dist/cobalt/p-7457aa89.entry.js +0 -1
- package/dist/cobalt/p-77719335.entry.js +0 -1
- package/dist/cobalt/p-8f600512.entry.js +0 -1
- package/dist/cobalt/p-CQAYgqA6.js +0 -1
- package/dist/cobalt/p-a02db338.entry.js +0 -1
- package/dist/cobalt/p-a51d8775.entry.js +0 -1
- package/dist/cobalt/p-a9096b5c.entry.js +0 -1
- package/dist/cobalt/p-aafb9d11.entry.js +0 -1
- package/dist/cobalt/p-b28dc0fe.entry.js +0 -1
- package/dist/cobalt/p-c6b9b9d6.entry.js +0 -1
- package/dist/cobalt/p-d4debd6f.entry.js +0 -1
- package/dist/cobalt/p-d629fb4e.entry.js +0 -1
- package/dist/components/p-B3TkpLNh.js +0 -1
- package/dist/components/p-B7hvddnu.js +0 -1
- package/dist/components/p-BT5tSgZa.js +0 -1
- package/dist/components/p-CXLX8DpD.js +0 -1
- package/dist/components/p-DTvb412h.js +0 -1
- package/dist/components/p-DvhR3H61.js +0 -1
- package/dist/components/p-KWTokD0C.js +0 -1
- package/dist/components/p-Q6caHt79.js +0 -1
- package/dist/components/p-WWlZiln1.js +0 -1
- 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,
|
|
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
|
|
104
|
-
//
|
|
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.
|
|
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.
|
|
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
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
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
|
-
|
|
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--
|
|
356
|
-
'co-option-list__option--drop-
|
|
357
|
-
|
|
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: '
|
|
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: '
|
|
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>",
|