@r2digisolutions/ui 0.24.2 → 0.24.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.
@@ -71,7 +71,7 @@
71
71
  manager.setReservedWidth(reserved);
72
72
  });
73
73
 
74
- // reflow ancho
74
+ // Reflow ancho
75
75
  $effect(() => {
76
76
  if (!container) return;
77
77
  const ro = new ResizeObserver((entries) => {
@@ -82,7 +82,7 @@
82
82
  return () => ro.disconnect();
83
83
  });
84
84
 
85
- // medir DOM
85
+ // Medir DOM
86
86
  const SAMPLE_ROWS = 10;
87
87
  async function measureColumns() {
88
88
  await tick();
@@ -124,7 +124,14 @@
124
124
  ) {
125
125
  e.preventDefault();
126
126
  const columnIndex = columnId ? manager.state.visibleColumns.indexOf(columnId) : null;
127
- rightMenu = { open: true, x: e.clientX, y: e.clientY };
127
+ if (rightMenu.open) {
128
+ rightMenu = { open: false, x: 0, y: 0 };
129
+ setTimeout(() => {
130
+ rightMenu = { open: true, x: e.clientX, y: e.clientY };
131
+ }, 0);
132
+ } else {
133
+ rightMenu = { open: true, x: e.clientX, y: e.clientY };
134
+ }
128
135
  rightClickContext = {
129
136
  row,
130
137
  rowIndex,
@@ -140,13 +147,13 @@
140
147
  return manager.state.items.filter((r) => ids.has(rowId(r)));
141
148
  }
142
149
 
143
- // tracks
144
150
  function colTrack(cId: string, measuring: boolean) {
145
151
  if (measuring) return 'max-content';
146
152
  const c = manager.getColumn(cId);
147
153
  const w = manager.measured[cId] ?? c.width ?? c.minWidth ?? 160;
148
154
  return `${Math.max(40, Math.ceil(Number(w)))}px`;
149
155
  }
156
+
150
157
  function headerTemplateCols(visible: string[], endExtras: boolean) {
151
158
  const tracks = [
152
159
  `${CHECK_W}px`,
@@ -282,7 +289,7 @@
282
289
  data-dt-cell="1"
283
290
  data-col-id={cid}
284
291
  data-row-index={i}
285
- class="px-3"
292
+ class="flex h-full w-full items-center px-3"
286
293
  onclick={() => onRowClick?.(row)}
287
294
  oncontextmenu={(e) => onCellContext(e, row, cid, i)}
288
295
  >
@@ -1,22 +1,25 @@
1
1
  <script lang="ts">
2
2
  import type { TContextMenuEntry } from '../core/types.js';
3
3
 
4
- // --- Action portal (interna al componente) ---
4
+ // --- Action portal ---
5
5
  function portal(node: HTMLElement, target: HTMLElement | null = null) {
6
6
  const tgt = target ?? document.body;
7
7
  const placeholder = document.createComment('portal-placeholder');
8
- node.parentNode?.insertBefore(placeholder, node);
8
+ if (!node.parentNode) return { destroy: () => {} };
9
+ node.parentNode.insertBefore(placeholder, node);
9
10
  tgt.appendChild(node);
10
11
  return {
11
12
  destroy() {
12
- node.remove();
13
- placeholder.parentNode?.insertBefore(node, placeholder);
14
- placeholder.remove();
13
+ if (node.isConnected) node.remove();
14
+ if (placeholder.isConnected && placeholder.parentNode) {
15
+ placeholder.parentNode.insertBefore(node, placeholder);
16
+ placeholder.remove();
17
+ }
15
18
  }
16
19
  };
17
20
  }
18
21
 
19
- // --- Util para clamping a viewport (interna) ---
22
+ // --- Util para clamping a viewport ---
20
23
  function clampToViewport(x: number, y: number, menuW: number, menuH: number, padding = 8) {
21
24
  const vw = document.documentElement.clientWidth;
22
25
  const vh = document.documentElement.clientHeight;
@@ -54,12 +57,14 @@
54
57
  let q = $state('');
55
58
  const current = $derived(stack.length ? stack[stack.length - 1] : { label: title, items });
56
59
 
60
+ let menuEl: HTMLDivElement | null = $state(null);
61
+
57
62
  function close() {
58
63
  open = false;
59
64
  stack = [];
60
65
  q = '';
61
- // opcional si quieres limpiar coords:
62
- // x = 0; y = 0;
66
+ x = 0;
67
+ y = 0;
63
68
  }
64
69
 
65
70
  function hasChildren(it: TContextMenuEntry) {
@@ -91,8 +96,6 @@
91
96
  const list = current.items ?? [];
92
97
  const query = q.trim().toLowerCase();
93
98
  let arr = query ? list.filter((it) => matches(it, query)) : list.slice();
94
-
95
- // limpiar divisores consecutivos y extremos
96
99
  const out: TContextMenuEntry[] = [];
97
100
  let prevDiv = false;
98
101
  for (const it of arr) {
@@ -125,9 +128,6 @@
125
128
  }
126
129
  }
127
130
 
128
- // --- Ref al elemento del menú para detectar click-fuera ---
129
- let menuEl: HTMLDivElement | null = $state(null);
130
-
131
131
  // Teclado (Escape / Backspace)
132
132
  $effect(() => {
133
133
  if (!open) return;
@@ -136,30 +136,34 @@
136
136
  return () => document.removeEventListener('keydown', handler);
137
137
  });
138
138
 
139
- // Cierres robustos: click-fuera en capture, scroll/resize, y bloqueo de menú nativo
139
+ // Cierres robustos: click-fuera, scroll/resize, y bloqueo de menú nativo
140
140
  $effect(() => {
141
- if (!open) return;
141
+ if (!open || !menuEl) return;
142
142
 
143
- const onPointerDownCapture = (ev: PointerEvent) => {
144
- if (!menuEl) return;
145
- if (!menuEl.contains(ev.target as Node)) {
146
- close();
147
- }
143
+ const onPointerDown = (ev: PointerEvent) => {
144
+ if (!menuEl || menuEl.contains(ev.target as Node)) return;
145
+ close();
148
146
  };
149
147
 
150
148
  const onNativeCtx = (ev: MouseEvent) => {
149
+ if (!menuEl || menuEl.contains(ev.target as Node)) return;
151
150
  ev.preventDefault();
152
151
  };
153
152
 
154
- const onScrollOrResize = () => close();
153
+ let timeout: NodeJS.Timeout;
154
+ const onScrollOrResize = () => {
155
+ clearTimeout(timeout);
156
+ timeout = setTimeout(() => close(), 100);
157
+ };
155
158
 
156
- document.addEventListener('pointerdown', onPointerDownCapture, true);
159
+ document.addEventListener('pointerdown', onPointerDown);
157
160
  document.addEventListener('contextmenu', onNativeCtx);
158
161
  window.addEventListener('scroll', onScrollOrResize, true);
159
162
  window.addEventListener('resize', onScrollOrResize, true);
160
163
 
161
164
  return () => {
162
- document.removeEventListener('pointerdown', onPointerDownCapture, true);
165
+ clearTimeout(timeout);
166
+ document.removeEventListener('pointerdown', onPointerDown);
163
167
  document.removeEventListener('contextmenu', onNativeCtx);
164
168
  window.removeEventListener('scroll', onScrollOrResize, true);
165
169
  window.removeEventListener('resize', onScrollOrResize, true);
@@ -182,7 +186,7 @@
182
186
  </script>
183
187
 
184
188
  {#if open}
185
- <!-- BACKDROP (portaleado al body) -->
189
+ <!-- BACKDROP -->
186
190
  <div
187
191
  use:portal={portalTarget}
188
192
  role="dialog"
@@ -194,7 +198,7 @@
194
198
  style="pointer-events:auto"
195
199
  />
196
200
 
197
- <!-- MENÚ (portaleado al body) -->
201
+ <!-- MENÚ -->
198
202
  <div
199
203
  bind:this={menuEl}
200
204
  use:portal={portalTarget}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@r2digisolutions/ui",
3
- "version": "0.24.2",
3
+ "version": "0.24.4",
4
4
  "private": false,
5
5
  "packageManager": "bun@1.2.23",
6
6
  "publishConfig": {