@prolibu-suite/cobalt-core 0.11.1 → 0.11.3

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 (103) hide show
  1. package/custom-elements.json +153 -34
  2. package/dist/cjs/co-button.cjs.entry.js +1 -1
  3. package/dist/cjs/co-chip_2.cjs.entry.js +2 -2
  4. package/dist/cjs/co-document-editor.cjs.entry.js +1 -1
  5. package/dist/cjs/co-modal.cjs.entry.js +27 -1
  6. package/dist/cjs/co-overlay.cjs.entry.js +205 -34
  7. package/dist/cjs/co-rich-text-editor.cjs.entry.js +2 -2
  8. package/dist/cjs/co-rich-text-viewer.cjs.entry.js +1 -1
  9. package/dist/cjs/co-toggle-button.cjs.entry.js +1 -1
  10. package/dist/cjs/cobalt.cjs.js +1 -1
  11. package/dist/cjs/{index-oMHzCXm6.js → index-BbSD1Eyw.js} +1 -1
  12. package/dist/cjs/loader.cjs.js +1 -1
  13. package/dist/cjs/{pagination-DV43TRj9.js → pagination-S2sSAgdl.js} +26 -2
  14. package/dist/cobalt/cobalt.esm.js +1 -1
  15. package/dist/cobalt/{p-d6e7c258.entry.js → p-02ff847e.entry.js} +1 -1
  16. package/dist/cobalt/{p-87e62e2b.entry.js → p-12914c0a.entry.js} +1 -1
  17. package/dist/cobalt/p-38eb2615.entry.js +1 -0
  18. package/dist/cobalt/{p-47eca182.entry.js → p-6c7e423c.entry.js} +1 -1
  19. package/dist/cobalt/p-93063876.entry.js +1 -0
  20. package/dist/cobalt/p-9b114836.entry.js +1 -0
  21. package/dist/cobalt/{p-RVQJEYxa.js → p-Ch-Tygdb.js} +1 -1
  22. package/dist/cobalt/p-DGLDAl09.js +1 -0
  23. package/dist/cobalt/{p-3b6efb79.entry.js → p-bb7bbe70.entry.js} +1 -1
  24. package/dist/cobalt/p-e5f0d560.entry.js +1 -0
  25. package/dist/collection/components/co-autocomplete/co-autocomplete.js +1 -1
  26. package/dist/collection/components/co-avatar-group/co-avatar-group.js +1 -1
  27. package/dist/collection/components/co-button/co-button.css +15 -0
  28. package/dist/collection/components/co-checkbox-group/co-checkbox-group.js +1 -1
  29. package/dist/collection/components/co-chip/co-chip.css +16 -11
  30. package/dist/collection/components/co-color-area/co-color-area.js +2 -2
  31. package/dist/collection/components/co-color-slider/co-color-slider.js +1 -1
  32. package/dist/collection/components/co-combobox/co-combobox.js +1 -1
  33. package/dist/collection/components/co-command-search/co-command-search.js +1 -1
  34. package/dist/collection/components/co-data-table/co-data-table.js +1 -1
  35. package/dist/collection/components/co-date-range-picker/co-date-range-picker.js +2 -2
  36. package/dist/collection/components/co-document-editor/co-document-editor.js +5 -5
  37. package/dist/collection/components/co-modal/co-modal.js +68 -1
  38. package/dist/collection/components/co-option-list/co-option-list.css +30 -4
  39. package/dist/collection/components/co-overlay/co-overlay.css +7 -0
  40. package/dist/collection/components/co-overlay/co-overlay.js +130 -26
  41. package/dist/collection/components/co-overlay/focusTrap.js +111 -3
  42. package/dist/collection/components/co-popover/co-popover.js +1 -1
  43. package/dist/collection/components/co-radio-group/co-radio-group.js +1 -1
  44. package/dist/collection/components/co-ref-field/co-ref-field.js +4 -4
  45. package/dist/collection/components/co-segmented-bar/co-segmented-bar.js +1 -1
  46. package/dist/collection/components/co-select/co-select.js +1 -1
  47. package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.js +1 -1
  48. package/dist/collection/components/co-toast/co-toast.js +2 -2
  49. package/dist/collection/components/co-toggle-button/co-toggle-button.css +43 -13
  50. package/dist/collection/components/co-transfer-list/co-transfer-list.js +1 -1
  51. package/dist/collection/components/co-tree-item/co-tree-item.js +2 -2
  52. package/dist/components/co-autocomplete.js +1 -1
  53. package/dist/components/co-button.js +1 -1
  54. package/dist/components/co-chip.js +1 -1
  55. package/dist/components/co-column-picker.js +1 -1
  56. package/dist/components/co-combobox.js +1 -1
  57. package/dist/components/co-command-search.js +1 -1
  58. package/dist/components/co-data-table.js +1 -1
  59. package/dist/components/co-date-picker.js +1 -1
  60. package/dist/components/co-date-range-picker.js +1 -1
  61. package/dist/components/co-date-range.js +1 -1
  62. package/dist/components/co-date-time-picker.js +1 -1
  63. package/dist/components/co-document-editor.js +1 -1
  64. package/dist/components/co-drawer.js +1 -1
  65. package/dist/components/co-modal.js +1 -1
  66. package/dist/components/co-option-list.js +1 -1
  67. package/dist/components/co-overlay.js +1 -1
  68. package/dist/components/co-ref-field.js +1 -1
  69. package/dist/components/co-rich-text-editor.js +1 -1
  70. package/dist/components/co-rich-text-viewer.js +1 -1
  71. package/dist/components/co-toggle-button.js +1 -1
  72. package/dist/components/{p-BVdCvEza.js → p-BI_VaFsx.js} +1 -1
  73. package/dist/components/{p-Cnfd6Zze.js → p-BqFBZ1PT.js} +1 -1
  74. package/dist/components/{p-Du8EpQb-.js → p-C_6szR7t.js} +1 -1
  75. package/dist/components/{p-RVQJEYxa.js → p-Ch-Tygdb.js} +1 -1
  76. package/dist/components/{p-zJ3pjFzW.js → p-DB8DGMc-.js} +1 -1
  77. package/dist/components/p-DGLDAl09.js +1 -0
  78. package/dist/components/{p-Hi57w2_2.js → p-DhPxNA2f.js} +1 -1
  79. package/dist/components/p-wUXcJGdy.js +1 -0
  80. package/dist/esm/co-button.entry.js +1 -1
  81. package/dist/esm/co-chip_2.entry.js +2 -2
  82. package/dist/esm/co-document-editor.entry.js +1 -1
  83. package/dist/esm/co-modal.entry.js +28 -2
  84. package/dist/esm/co-overlay.entry.js +205 -34
  85. package/dist/esm/co-rich-text-editor.entry.js +2 -2
  86. package/dist/esm/co-rich-text-viewer.entry.js +1 -1
  87. package/dist/esm/co-toggle-button.entry.js +1 -1
  88. package/dist/esm/cobalt.js +1 -1
  89. package/dist/esm/{index-Cpo8HTwr.js → index-CgyOJePd.js} +1 -1
  90. package/dist/esm/loader.js +1 -1
  91. package/dist/esm/{pagination-D9OfZUnY.js → pagination-BzrIQtrk.js} +26 -2
  92. package/dist/types/components/co-modal/co-modal.d.ts +23 -0
  93. package/dist/types/components/co-overlay/co-overlay.d.ts +29 -1
  94. package/dist/types/components/co-overlay/focusTrap.d.ts +24 -3
  95. package/dist/types/components.d.ts +21 -2
  96. package/package.json +4 -4
  97. package/dist/cobalt/p-1a5bec8c.entry.js +0 -1
  98. package/dist/cobalt/p-67a024dd.entry.js +0 -1
  99. package/dist/cobalt/p-9ee5bef3.entry.js +0 -1
  100. package/dist/cobalt/p-B1JT7us1.js +0 -1
  101. package/dist/cobalt/p-c4c997f3.entry.js +0 -1
  102. package/dist/components/p-B1JT7us1.js +0 -1
  103. package/dist/components/p-nrwDl_gx.js +0 -1
@@ -55,20 +55,112 @@ function resolveTabIndex(count, activeIndex, shiftKey) {
55
55
  // Forward: from the last element (or from outside) wrap to the first.
56
56
  return activeIndex === -1 || activeIndex >= count - 1 ? 0 : activeIndex + 1;
57
57
  }
58
+ // ── Recorrido compuesto (QA 2026-09-24, «Generar contrato» de contratos V2) ──
59
+ // El foco nunca entraba ni quedaba atrapado en un co-modal: `getFocusableElements`
60
+ // solo mira el light DOM de co-overlay (el frame del modal: el ✕). El contenido
61
+ // del consumidor llega por DOS <slot> (el de co-overlay y el del frame) y los
62
+ // controles reales viven en el shadow de cada co-* (el <button> de co-button, el
63
+ // <input> de co-input). El recorrido sigue el árbol PLANO: baja por shadowRoots
64
+ // y, en cada <slot>, por sus asignados — o por su contenido por defecto si no
65
+ // tiene. Todo esto corre solo en el navegador (abrir la trampa / cada Tab).
66
+ /** Hijos en el árbol plano: el shadow del host, los asignados de un slot o los hijos. */
67
+ function composedChildren(el) {
68
+ if (el.shadowRoot)
69
+ return Array.from(el.shadowRoot.children);
70
+ if (el.tagName === 'SLOT') {
71
+ const assigned = el.assignedElements({ flatten: true });
72
+ return assigned.length ? assigned : Array.from(el.children);
73
+ }
74
+ return Array.from(el.children);
75
+ }
76
+ /** Subárbol fuera de la trampa entero: oculto a AT o inerte. */
77
+ function isExcludedSubtree(el) {
78
+ return el.getAttribute('aria-hidden') === 'true' || el.hasAttribute('inert');
79
+ }
80
+ /**
81
+ * Parada de Tab: matchea el selector, no está deshabilitado, no se sacó del
82
+ * orden con tabindex negativo (los botones internos de un trigger co-* —clear,
83
+ * chips— van con `tabIndex={-1}`, y `button:not([disabled])` los matchearía
84
+ * igual), tiene caja (offsetParent null = display:none; getClientRects cubre
85
+ * position:fixed) y no es `visibility:hidden`: un acordeón o fieldset colapsado
86
+ * conserva la caja pero el navegador no le da el foco, y la trampa lo elegiría
87
+ * igual → Tab clavado (WCAG 2.1.2). Sin la API (navegador viejo, jsdom) no filtra.
88
+ */
89
+ function isTabStop(el) {
90
+ var _a, _b;
91
+ if (!((_a = el.matches) === null || _a === void 0 ? void 0 : _a.call(el, FOCUSABLE_SELECTOR)) || el.hasAttribute('disabled'))
92
+ return false;
93
+ const tabindex = el.getAttribute('tabindex');
94
+ if (tabindex !== null && Number(tabindex) < 0)
95
+ return false;
96
+ if (el.offsetParent === null && el.getClientRects().length === 0)
97
+ return false;
98
+ return ((_b = el.checkVisibility) === null || _b === void 0 ? void 0 : _b.call(el, { visibilityProperty: true })) !== false;
99
+ }
58
100
  /**
59
- * Collect the tabbable elements slotted into the overlay's light DOM, skipping
60
- * hidden / aria-hidden ones. (Focusables nested inside further shadow roots are
61
- * out of scope — the common dialog/modal content lives in the slotted subtree.)
101
+ * Recorre en orden del árbol plano los descendientes compuestos de `root` (sin
102
+ * incluirlo) hasta que `visit` devuelve true. Poda aria-hidden / inert.
62
103
  */
63
- function getFocusableElements(root) {
64
- const nodes = Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR));
65
- return nodes.filter((el) => !el.hasAttribute('disabled') &&
66
- el.getAttribute('aria-hidden') !== 'true' &&
67
- // offsetParent is null for display:none; getClientRects covers position:fixed.
68
- (el.offsetParent !== null || el.getClientRects().length > 0));
104
+ function walkComposed(root, visit) {
105
+ const step = (node) => {
106
+ if (isExcludedSubtree(node))
107
+ return false;
108
+ if (visit(node))
109
+ return true;
110
+ return composedChildren(node).some(step);
111
+ };
112
+ composedChildren(root).some(step);
113
+ }
114
+ /** Primer descendiente compuesto que cumple `match`, en orden del árbol plano. */
115
+ function findComposed(root, match) {
116
+ let found = null;
117
+ walkComposed(root, (el) => {
118
+ if (!match(el))
119
+ return false;
120
+ found = el;
121
+ return true;
122
+ });
123
+ return found;
124
+ }
125
+ /**
126
+ * Paradas de Tab dentro de `root` en el árbol COMPUESTO (shadowRoots + slots
127
+ * asignados), con las mismas exclusiones que `getFocusableElements`.
128
+ */
129
+ function getComposedFocusables(root) {
130
+ const out = [];
131
+ walkComposed(root, (el) => {
132
+ if (isTabStop(el))
133
+ out.push(el);
134
+ return false;
135
+ });
136
+ return out;
137
+ }
138
+ /**
139
+ * Dónde cae el foco al abrir la trampa: el primer `[autofocus]` del recorrido
140
+ * compuesto —si es un host con shadow (`<co-input autofocus>`), su primer
141
+ * enfocable compuesto—; si no hay, la primera parada de Tab. `null` = nada
142
+ * enfocable (el llamador cae al contenedor).
143
+ */
144
+ function resolveInitialFocus(root) {
145
+ const autofocus = findComposed(root, (el) => el.hasAttribute('autofocus'));
146
+ if (autofocus) {
147
+ if (isTabStop(autofocus))
148
+ return autofocus;
149
+ const inner = autofocus.shadowRoot ? getComposedFocusables(autofocus)[0] : undefined;
150
+ if (inner)
151
+ return inner;
152
+ }
153
+ return findComposed(root, isTabStop);
154
+ }
155
+ /**
156
+ * Con dos trampas abiertas (un confirm sobre un modal, un modal anidado) las dos
157
+ * escuchan el keydown de document: solo la capa MÁS RECIENTE maneja Tab.
158
+ */
159
+ function isTopTrap(stack, id) {
160
+ return stack.length > 0 && stack[stack.length - 1] === id;
69
161
  }
70
162
 
71
- const coOverlayCss = () => `:host{display:contents}.co-overlay{position:fixed;inset:0;z-index:1000;margin:0;border:0;padding:0;width:auto;height:auto;max-width:none;max-height:none;overflow:visible;display:flex;align-items:center;justify-content:center;background:var(--co-overlay-bg, rgba(0, 0, 0, 0.4));-webkit-backdrop-filter:blur(var(--co-overlay-blur, 2px));backdrop-filter:blur(var(--co-overlay-blur, 2px));opacity:0;pointer-events:none;transition:opacity var(--co-motion-duration-fast) var(--co-motion-ease-in)}.co-overlay--open{opacity:1;pointer-events:auto;transition:opacity var(--co-motion-duration-base) var(--co-motion-ease-out)}`;
163
+ const coOverlayCss = () => `:host{display:contents}.co-overlay{position:fixed;inset:0;z-index:1000;margin:0;border:0;padding:0;width:auto;height:auto;max-width:none;max-height:none;overflow:visible;display:flex;align-items:center;justify-content:center;background:var(--co-overlay-bg, rgba(0, 0, 0, 0.4));-webkit-backdrop-filter:blur(var(--co-overlay-blur, 2px));backdrop-filter:blur(var(--co-overlay-blur, 2px));opacity:0;pointer-events:none;transition:opacity var(--co-motion-duration-fast) var(--co-motion-ease-in)}.co-overlay--open{opacity:1;pointer-events:auto;transition:opacity var(--co-motion-duration-base) var(--co-motion-ease-out)}.co-overlay--refront{transition:none !important}`;
72
164
 
73
165
  /**
74
166
  * Module-level body-scroll lock shared by every overlay instance.
@@ -96,6 +188,16 @@ function unlockBodyScroll() {
96
188
  document.body.style.overflow = savedOverflow;
97
189
  }
98
190
  }
191
+ /**
192
+ * Pila de trampas de foco ABIERTAS, compartida por todas las instancias (como el
193
+ * scroll lock). Todas escuchan el keydown de document: con un confirm encima de
194
+ * un modal, las dos movían el foco en el mismo Tab. Solo la capa más reciente
195
+ * (`isTopTrap`) maneja Tab y el foco inicial.
196
+ */
197
+ const trapStack = [];
198
+ let trapSeq = 0;
199
+ /** Clase del div mientras dura el re-apilado de `bringToFront()` (ver co-overlay.css). */
200
+ const REFRONT_CLASS = 'co-overlay--refront';
99
201
  function nextFrame(cb) {
100
202
  if (typeof requestAnimationFrame === 'function')
101
203
  requestAnimationFrame(cb);
@@ -115,6 +217,11 @@ const CoOverlay = class {
115
217
  * previously-focused element, moves focus into the overlay, cycles Tab /
116
218
  * Shift+Tab within the slotted content, and restores focus on close.
117
219
  * Default false → existing consumers are unchanged.
220
+ *
221
+ * The walk is COMPOSED (shadow roots + assigned slots): it reaches the
222
+ * consumer's content projected through a host's slots and the inner control
223
+ * of every co-* (a co-button's `<button>`). With several traps open, only the
224
+ * most recent one handles Tab.
118
225
  */
119
226
  this.trapFocus = false;
120
227
  /**
@@ -124,6 +231,10 @@ const CoOverlay = class {
124
231
  this.closeOnEscape = false;
125
232
  /** Whether THIS instance currently holds a scroll lock (prevents double-count). */
126
233
  this.hasLock = false;
234
+ /** Identidad de esta instancia en `trapStack`. */
235
+ this.trapId = `co-overlay-trap-${++trapSeq}`;
236
+ /** Whether THIS instance is currently in `trapStack` (prevents double push). */
237
+ this.trapping = false;
127
238
  // Origen de la pulsación en curso (ver isBackdropDismiss): un drag que
128
239
  // empieza dentro del contenido y suelta en el fondo NO es un cierre —el
129
240
  // navegador despacha ese `click` al ancestro común, el propio scrim—, ni
@@ -165,27 +276,55 @@ const CoOverlay = class {
165
276
  else
166
277
  this.releaseLock();
167
278
  this.syncPopover();
168
- if (this.trapFocus) {
169
- if (isOpen)
170
- this.captureAndFocus();
171
- else
172
- this.restoreFocus();
173
- }
279
+ this.syncTrap();
280
+ }
281
+ onTrapFocusChange() {
282
+ this.syncTrap();
174
283
  }
175
284
  componentDidLoad() {
176
285
  // Handle the case where the overlay mounts already open.
177
286
  if (this.open)
178
287
  this.acquireLock();
179
288
  this.syncPopover();
180
- if (this.open && this.trapFocus)
181
- this.captureAndFocus();
289
+ this.syncTrap();
182
290
  }
183
291
  disconnectedCallback() {
184
292
  // Safety: never leave the body locked if removed while open.
185
293
  this.releaseLock();
186
- // Safety: return focus if we were removed while trapping.
187
- if (this.trapFocus)
188
- this.restoreFocus();
294
+ // Safety: leave the trap stack and return focus if removed while trapping.
295
+ this.releaseTrap();
296
+ }
297
+ /**
298
+ * Re-promueve el scrim al TOPE del top layer (QA 2026-09-24, «Generar
299
+ * contrato»): un drawer abierto DESPUÉS de un modal pintaba encima, porque en
300
+ * el top layer gana el último promovido y no hay z-index que lo corrija.
301
+ * `hidePopover()` + `showPopover()` lo vuelven a meter último.
302
+ *
303
+ * No es un cierre: no emite `coClose` / `coAfterClose` / `coAfterOpen`, no
304
+ * toca `open` ni el scroll lock, y no re-anima la entrada (la clase
305
+ * `co-overlay--refront` anula la transición durante el re-show y se retira en
306
+ * el frame siguiente). Tampoco mueve el foco: si el re-show dispara los
307
+ * «popover focusing steps» (un `[autofocus]` adentro), se devuelve a donde
308
+ * estaba. No-op cerrado, sin Popover API o fuera del top layer.
309
+ */
310
+ async bringToFront() {
311
+ const el = this.overlayEl;
312
+ if (!this.open || !el || typeof el.showPopover !== 'function')
313
+ return;
314
+ if (!el.matches(':popover-open'))
315
+ return;
316
+ const active = this.deepActiveElement();
317
+ el.classList.add(REFRONT_CLASS);
318
+ try {
319
+ el.hidePopover();
320
+ el.showPopover();
321
+ }
322
+ catch (_a) {
323
+ /* desconectado entre medio: no hay nada que re-apilar */
324
+ }
325
+ if (active && active.isConnected && this.deepActiveElement() !== active)
326
+ active.focus({ preventScroll: true });
327
+ nextFrame(() => el.classList.remove(REFRONT_CLASS));
189
328
  }
190
329
  acquireLock() {
191
330
  if (this.hasLock)
@@ -223,19 +362,43 @@ const CoOverlay = class {
223
362
  /* not connected yet, or already in the desired state */
224
363
  }
225
364
  }
226
- /** Record the current focus and move it into the overlay (guarded by trapFocus). */
365
+ /** La trampa está activa exactamente mientras el overlay está abierto con `trapFocus`. */
366
+ syncTrap() {
367
+ if (this.open && this.trapFocus)
368
+ this.engageTrap();
369
+ else
370
+ this.releaseTrap();
371
+ }
372
+ engageTrap() {
373
+ if (this.trapping)
374
+ return;
375
+ this.trapping = true;
376
+ trapStack.push(this.trapId);
377
+ this.captureAndFocus();
378
+ }
379
+ releaseTrap() {
380
+ if (!this.trapping)
381
+ return;
382
+ this.trapping = false;
383
+ const i = trapStack.indexOf(this.trapId);
384
+ if (i >= 0)
385
+ trapStack.splice(i, 1);
386
+ this.restoreFocus();
387
+ }
388
+ /** Record the current focus and move it into the overlay (only while trapping). */
227
389
  captureAndFocus() {
228
- if (typeof document !== 'undefined') {
229
- this.returnFocusEl = document.activeElement;
230
- }
390
+ // El activo PROFUNDO: `document.activeElement` se queda en el host de un
391
+ // co-* (co-button), cuyo focus() no llega al <button> interno.
392
+ this.returnFocusEl = this.deepActiveElement();
231
393
  // Defer so slotted content / the open transition is ready to take focus.
232
394
  nextFrame(() => {
233
395
  var _a;
234
- if (!this.open)
396
+ // Una trampa abierta en el mismo frame por ENCIMA (confirm) se queda el foco.
397
+ if (!this.open || !this.trapping || !isTopTrap(trapStack, this.trapId))
235
398
  return;
236
- const focusables = getFocusableElements(this.el);
237
- if (focusables.length > 0)
238
- focusables[0].focus();
399
+ const target = resolveInitialFocus(this.el);
400
+ if (target)
401
+ target.focus();
239
402
  else
240
403
  (_a = this.overlayEl) === null || _a === void 0 ? void 0 : _a.focus();
241
404
  });
@@ -244,8 +407,9 @@ const CoOverlay = class {
244
407
  restoreFocus() {
245
408
  const target = this.returnFocusEl;
246
409
  this.returnFocusEl = null;
247
- if (target && typeof target.focus === 'function')
248
- target.focus();
410
+ // Desmontado mientras el overlay estaba abierto (el paso de un wizard): no hay adónde volver.
411
+ if (target && target.isConnected && typeof target.focus === 'function')
412
+ target.focus({ preventScroll: true });
249
413
  }
250
414
  /** Deepest active element, descending through nested shadow roots. */
251
415
  deepActiveElement() {
@@ -264,12 +428,16 @@ const CoOverlay = class {
264
428
  this.coClose.emit();
265
429
  return;
266
430
  }
267
- if (this.trapFocus && e.key === 'Tab')
431
+ if (this.trapping && e.key === 'Tab' && isTopTrap(trapStack, this.trapId))
268
432
  this.trapTab(e);
269
433
  }
270
434
  trapTab(e) {
271
435
  var _a;
272
- const focusables = getFocusableElements(this.el);
436
+ // Tab ya manejado por un control de adentro (co-tags-field agrega el tag, las listas de co-rich-text y
437
+ // CodeMirror indentan): el listener de document corre DESPUÉS y no le roba el foco.
438
+ if (e.defaultPrevented)
439
+ return;
440
+ const focusables = getComposedFocusables(this.el);
273
441
  if (focusables.length === 0) {
274
442
  // Nothing to move to — keep focus pinned to the overlay container.
275
443
  e.preventDefault();
@@ -284,12 +452,15 @@ const CoOverlay = class {
284
452
  focusables[nextIndex].focus();
285
453
  }
286
454
  render() {
287
- return (h("div", { key: '1edc956747aa0c79bcc7863fd3530c4f64fd6746', class: { 'co-overlay': true, 'co-overlay--open': this.open }, part: "overlay", popover: "manual", tabindex: this.trapFocus ? -1 : undefined, ref: (el) => (this.overlayEl = el), onPointerDown: this.handlePointerDown, onPointerUp: this.handlePointerUp, onClick: this.handleClick, onTransitionEnd: this.handleTransitionEnd }, h("slot", { key: 'b17930138f924657b21511b95bd152e90a53a04a' })));
455
+ return (h("div", { key: 'e18d7b0e3ebd4933a78a9f2d39af6058ce429105', class: { 'co-overlay': true, 'co-overlay--open': this.open }, part: "overlay", popover: "manual", tabindex: this.trapFocus ? -1 : undefined, ref: (el) => (this.overlayEl = el), onPointerDown: this.handlePointerDown, onPointerUp: this.handlePointerUp, onClick: this.handleClick, onTransitionEnd: this.handleTransitionEnd }, h("slot", { key: '2f29233d44de8a0cc3100cfa08233cdc10ebf352' })));
288
456
  }
289
457
  get el() { return getElement(this); }
290
458
  static get watchers() { return {
291
459
  "open": [{
292
460
  "onOpenChange": 0
461
+ }],
462
+ "trapFocus": [{
463
+ "onTrapFocusChange": 0
293
464
  }]
294
465
  }; }
295
466
  };
@@ -1,8 +1,8 @@
1
1
  import { r as registerInstance, c as createEvent, h, a as getElement } from './index-DJkaRtbb.js';
2
- import { R as RichText } from './index-Cpo8HTwr.js';
2
+ import { R as RichText } from './index-CgyOJePd.js';
3
3
  import { g as getRichTextStrings } from './richTextI18n-xnrKkNWQ.js';
4
4
  import { E as EchoGuard, p as parseEditorValue, a as applyExternalValue, b as parseFeatures, c as buildOutput, s as syncToolbarEditor, d as syncImageLayouts } from './rich-text-host-BmdKHBZP.js';
5
- import './pagination-D9OfZUnY.js';
5
+ import './pagination-BzrIQtrk.js';
6
6
  import './purify.es-B2QLgWrz.js';
7
7
  import './toolbar-config-CRxTFT_z.js';
8
8
 
@@ -133,7 +133,7 @@ const CoRichTextViewer = class {
133
133
  // JSON mode — lazily import the serializer (pulls Tiptap on demand only).
134
134
  try {
135
135
  const doc = JSON.parse(this.value);
136
- const rt = await import('./index-Cpo8HTwr.js').then(function (n) { return n.R; });
136
+ const rt = await import('./index-CgyOJePd.js').then(function (n) { return n.R; });
137
137
  this.html = rt.jsonToHtml(doc, this.preset);
138
138
  }
139
139
  catch (_a) {
@@ -1,6 +1,6 @@
1
1
  import { r as registerInstance, c as createEvent, h, a as getElement } from './index-DJkaRtbb.js';
2
2
 
3
- const coToggleButtonCss = () => `:host{display:inline-flex;--co-toggle-button-radius:var(--co-border-radius-sm)}:host([size='l']){--co-toggle-button-radius:var(--co-border-radius-lg)}:host([size='m']){--co-toggle-button-radius:var(--co-border-radius-sm)}:host([size='s']){--co-toggle-button-radius:var(--co-border-radius-xs)}:host([size='xs']){--co-toggle-button-radius:var(--co-border-radius-xs)}.co-toggle-button{display:inline-flex;width:var(--co-toggle-button-width, auto);align-items:center;justify-content:center;gap:var(--co-spacing-sm2);border:1px solid var(--co-semantic-border-subtle);border-top-left-radius:var(--co-tbr-tl, var(--co-toggle-button-radius));border-top-right-radius:var(--co-tbr-tr, var(--co-toggle-button-radius));border-bottom-right-radius:var(--co-tbr-br, var(--co-toggle-button-radius));border-bottom-left-radius:var(--co-tbr-bl, var(--co-toggle-button-radius));background:color-mix(in srgb, var(--co-semantic-surface-secondary) 35%, transparent);-webkit-backdrop-filter:var(--co-glass-filter, blur(var(--co-glass-blur)) saturate(var(--co-glass-saturate)));backdrop-filter:var(--co-glass-filter, blur(var(--co-glass-blur)) saturate(var(--co-glass-saturate)));color:var(--co-semantic-text-default);font-family:var(--co-font-family-primary);font-weight:500;cursor:pointer;transition:background var(--co-motion-duration-fast) var(--co-motion-ease-out), border-color var(--co-motion-duration-fast) var(--co-motion-ease-out), color var(--co-motion-duration-fast) var(--co-motion-ease-out);white-space:nowrap;box-sizing:border-box;line-height:1}.co-toggle-button--l{height:48px;padding:0 var(--co-spacing-lg);font-size:var(--co-font-size-16)}.co-toggle-button--m{height:40px;padding:0 var(--co-spacing-md);font-size:var(--co-font-size-14)}.co-toggle-button--s{height:32px;padding:0 var(--co-spacing-sm2);font-size:var(--co-font-size-14)}.co-toggle-button--xs{height:24px;padding:0 var(--co-spacing-sm);font-size:var(--co-font-size-12)}.co-toggle-button--icon-only.co-toggle-button--l{width:48px;padding:0}.co-toggle-button--icon-only.co-toggle-button--m{width:40px;padding:0}.co-toggle-button--icon-only.co-toggle-button--s{width:32px;padding:0}.co-toggle-button--icon-only.co-toggle-button--xs{width:24px;padding:0}.co-toggle-button:hover:not(:disabled){background:var(--co-semantic-surface-hover)}.co-toggle-button--selected{background:var(--co-color-base-negro, #1f1c1b);color:var(--co-color-base-blanco, #fff);border-color:var(--co-color-base-negro, #1f1c1b)}.co-toggle-button--selected:hover:not(:disabled){background:var(--co-color-gray-800, #0a0a0a);border-color:var(--co-color-gray-800, #0a0a0a)}.co-toggle-button--disabled{opacity:0.4;cursor:not-allowed}.co-toggle-button:focus-visible{outline:2px solid var(--co-semantic-text-default);outline-offset:-3px}.co-toggle-button--selected:focus-visible{outline-color:currentColor}.co-toggle-button__label{line-height:1}@supports not (background: color-mix(in srgb, red, transparent)){.co-toggle-button{background:var(--co-semantic-surface-secondary)}}:host([variant='track']) .co-toggle-button{height:var(--co-toggle-pill-height, 30px);border-radius:var(--co-toggle-pill-radius, 8px);border-color:transparent;background:transparent;color:var(--co-semantic-text-secondary);box-shadow:none;padding:0 12px;-webkit-backdrop-filter:none;backdrop-filter:none}:host([variant='track']) .co-toggle-button.co-toggle-button--icon-only{width:34px;padding:0}:host([variant='track']) .co-toggle-button:hover:not(:disabled){background:var(--co-semantic-surface-hover);color:var(--co-semantic-text-default)}:host([variant='track']) .co-toggle-button--selected{background:var(--co-semantic-surface-page);color:var(--co-semantic-text-default);border-color:var(--co-toggle-pill-border, var(--co-semantic-border-default));box-shadow:var(--co-toggle-pill-shadow, var(--co-shadow-sm, 0 1px 2px 0 rgba(26, 26, 26, 0.04)))}:host([variant='track']) .co-toggle-button--selected:hover:not(:disabled){background:var(--co-semantic-surface-page);border-color:var(--co-toggle-pill-border, var(--co-semantic-border-default))}:host([variant='track'][size='xs']) .co-toggle-button{height:var(--co-toggle-pill-height, 20px);border-radius:var(--co-toggle-pill-radius, var(--co-border-radius-xxs))}:host([variant='track'][size='xs']) .co-toggle-button:not(.co-toggle-button--selected){color:var(--co-semantic-text-default)}:host([variant='track'][size='xs']) .co-toggle-button.co-toggle-button--icon-only{width:20px}:host([variant='track'][size='xs']) .co-toggle-button--selected{box-shadow:var(--co-toggle-pill-shadow, none)}:host([variant='soft']) .co-toggle-button{height:24px;border-radius:var(--co-border-radius-xxs);border-color:transparent;background:var(--co-semantic-surface-control, #f6f6f6);color:var(--co-semantic-text-default);font-size:var(--co-font-size-12);font-weight:var(--co-font-weight-regular);padding:0 calc(var(--co-spacing-sm2) - 1px);gap:var(--co-spacing-sm2);-webkit-backdrop-filter:none;backdrop-filter:none}:host([variant='soft']) .co-toggle-button:hover:not(:disabled){background:var(--co-semantic-surface-control, #f6f6f6)}:host([variant='soft']) .co-toggle-button--selected{background:var(--co-color-celeste-100);color:var(--co-color-primary-azul);border-color:transparent}:host([variant='soft']) .co-toggle-button--selected:hover:not(:disabled){background:var(--co-color-celeste-100)}`;
3
+ const coToggleButtonCss = () => `:host{display:inline-flex;--co-toggle-button-radius:var(--co-border-radius-sm)}:host([size='l']){--co-toggle-button-radius:var(--co-border-radius-lg)}:host([size='m']){--co-toggle-button-radius:var(--co-border-radius-sm)}:host([size='s']){--co-toggle-button-radius:var(--co-border-radius-xs)}:host([size='xs']){--co-toggle-button-radius:var(--co-border-radius-xs)}.co-toggle-button{display:inline-flex;width:var(--co-toggle-button-width, auto);align-items:center;justify-content:center;gap:var(--co-spacing-sm2);border:1px solid var(--co-semantic-border-subtle);border-top-left-radius:var(--co-tbr-tl, var(--co-toggle-button-radius));border-top-right-radius:var(--co-tbr-tr, var(--co-toggle-button-radius));border-bottom-right-radius:var(--co-tbr-br, var(--co-toggle-button-radius));border-bottom-left-radius:var(--co-tbr-bl, var(--co-toggle-button-radius));background:color-mix(in srgb, var(--co-semantic-surface-secondary) 35%, transparent);-webkit-backdrop-filter:var(--co-glass-filter, blur(var(--co-glass-blur)) saturate(var(--co-glass-saturate)));backdrop-filter:var(--co-glass-filter, blur(var(--co-glass-blur)) saturate(var(--co-glass-saturate)));color:var(--co-toggle-button-color, var(--co-semantic-text-default));font-family:var(--co-font-family-primary);font-weight:500;cursor:pointer;transition:background var(--co-motion-duration-fast) var(--co-motion-ease-out), border-color var(--co-motion-duration-fast) var(--co-motion-ease-out), color var(--co-motion-duration-fast) var(--co-motion-ease-out);white-space:nowrap;box-sizing:border-box;line-height:1}.co-toggle-button--l{height:48px;padding:0 var(--co-spacing-lg);font-size:var(--co-toggle-button-font-size, var(--co-font-size-16))}.co-toggle-button--m{height:40px;padding:0 var(--co-spacing-md);font-size:var(--co-toggle-button-font-size, var(--co-font-size-14))}.co-toggle-button--s{height:32px;padding:0 var(--co-spacing-sm2);font-size:var(--co-toggle-button-font-size, var(--co-font-size-14))}.co-toggle-button--xs{height:24px;padding:0 var(--co-spacing-sm);font-size:var(--co-toggle-button-font-size, var(--co-font-size-12))}.co-toggle-button--icon-only.co-toggle-button--l{width:48px;padding:0}.co-toggle-button--icon-only.co-toggle-button--m{width:40px;padding:0}.co-toggle-button--icon-only.co-toggle-button--s{width:32px;padding:0}.co-toggle-button--icon-only.co-toggle-button--xs{width:24px;padding:0}.co-toggle-button:hover:not(:disabled){background:var(--co-semantic-surface-hover)}.co-toggle-button--selected{background:var(--co-color-base-negro, #1f1c1b);color:var(--co-toggle-button-color-selected, var(--co-color-base-blanco, #fff));border-color:var(--co-color-base-negro, #1f1c1b)}.co-toggle-button--selected:hover:not(:disabled){background:var(--co-color-gray-800, #0a0a0a);border-color:var(--co-color-gray-800, #0a0a0a)}.co-toggle-button--disabled{opacity:0.4;cursor:not-allowed}.co-toggle-button:focus-visible{outline:2px solid var(--co-semantic-text-default);outline-offset:-3px}.co-toggle-button--selected:focus-visible{outline-color:currentColor}.co-toggle-button__label{line-height:1}@supports not (background: color-mix(in srgb, red, transparent)){.co-toggle-button{background:var(--co-semantic-surface-secondary)}}:host([variant='track']) .co-toggle-button{height:var(--co-toggle-pill-height, 30px);border-radius:var(--co-toggle-pill-radius, 8px);border-color:transparent;background:transparent;color:var(--co-toggle-button-color, var(--co-semantic-text-secondary));box-shadow:none;padding:0 12px;-webkit-backdrop-filter:none;backdrop-filter:none}:host([variant='track']) .co-toggle-button.co-toggle-button--icon-only{width:34px;padding:0}:host([variant='track']) .co-toggle-button:hover:not(:disabled){background:var(--co-semantic-surface-hover);color:var(--co-toggle-button-color-hover, var(--co-semantic-text-default))}:host([variant='track']) .co-toggle-button--selected{background:var(--co-semantic-surface-page);color:var(--co-toggle-button-color-selected, var(--co-semantic-text-default));border-color:var(--co-toggle-pill-border, var(--co-semantic-border-default));box-shadow:var(--co-toggle-pill-shadow, var(--co-shadow-sm, 0 1px 2px 0 rgba(26, 26, 26, 0.04)))}:host([variant='track']) .co-toggle-button--selected:hover:not(:disabled){background:var(--co-semantic-surface-page);color:var(--co-toggle-button-color-selected, var(--co-semantic-text-default));border-color:var(--co-toggle-pill-border, var(--co-semantic-border-default))}:host([variant='track'][size='xs']) .co-toggle-button{height:var(--co-toggle-pill-height, 20px);border-radius:var(--co-toggle-pill-radius, var(--co-border-radius-xxs))}:host([variant='track'][size='xs']) .co-toggle-button:not(.co-toggle-button--selected){color:var(--co-toggle-button-color, var(--co-semantic-text-default))}:host([variant='track'][size='xs']) .co-toggle-button:not(.co-toggle-button--selected):hover:not(:disabled){color:var(--co-toggle-button-color-hover, var(--co-semantic-text-default))}:host([variant='track'][size='xs']) .co-toggle-button.co-toggle-button--icon-only{width:20px}:host([variant='track'][size='xs']) .co-toggle-button--selected{box-shadow:var(--co-toggle-pill-shadow, none)}:host([variant='soft']) .co-toggle-button{height:24px;border-radius:var(--co-border-radius-xxs);border-color:transparent;background:var(--co-semantic-surface-control, #f6f6f6);color:var(--co-toggle-button-color, var(--co-semantic-text-default));font-size:var(--co-font-size-12);font-weight:var(--co-font-weight-regular);padding:0 calc(var(--co-spacing-sm2) - 1px);gap:var(--co-spacing-sm2);-webkit-backdrop-filter:none;backdrop-filter:none}:host([variant='soft']) .co-toggle-button:hover:not(:disabled){background:var(--co-semantic-surface-control, #f6f6f6)}:host([variant='soft']) .co-toggle-button--selected{background:var(--co-color-celeste-100);color:var(--co-toggle-button-color-selected, var(--co-color-primary-azul));border-color:transparent}:host([variant='soft']) .co-toggle-button--selected:hover:not(:disabled){background:var(--co-color-celeste-100)}`;
4
4
 
5
5
  /** Tallas que entiende este botón. El grupo puede traer una fuera de esta
6
6
  * lista (el host usa `<co-toggle-button-group size="sm">`): nunca se adopta. */