@r2digisolutions/ui 0.24.5 → 0.24.7

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.
@@ -124,23 +124,19 @@
124
124
  ) {
125
125
  e.preventDefault();
126
126
  const columnIndex = columnId ? manager.state.visibleColumns.indexOf(columnId) : null;
127
- // Always set fresh coordinates and ensure menu is closed before reopening
128
- if (rightMenu.open) {
129
- rightMenu = { open: false, x: 0, y: 0 };
130
- setTimeout(() => {
131
- rightMenu = { open: true, x: e.clientX, y: e.clientY };
132
- }, 0);
133
- } else {
127
+ // Reset menu state and set new coordinates
128
+ rightMenu = { open: false, x: 0, y: 0 };
129
+ tick().then(() => {
134
130
  rightMenu = { open: true, x: e.clientX, y: e.clientY };
135
- }
136
- rightClickContext = {
137
- row,
138
- rowIndex,
139
- columnId,
140
- columnIndex,
141
- event: e,
142
- column: columnId ? manager.getColumn(columnId) : null
143
- } as TDataTableCellContext<T>;
131
+ rightClickContext = {
132
+ row,
133
+ rowIndex,
134
+ columnId,
135
+ columnIndex,
136
+ event: e,
137
+ column: columnId ? manager.getColumn(columnId) : null
138
+ } as TDataTableCellContext<T>;
139
+ });
144
140
  }
145
141
 
146
142
  function selectedRows(): T[] {
@@ -148,7 +144,6 @@
148
144
  return manager.state.items.filter((r) => ids.has(rowId(r)));
149
145
  }
150
146
 
151
- // Tracks
152
147
  function colTrack(cId: string, measuring: boolean) {
153
148
  if (measuring) return 'max-content';
154
149
  const c = manager.getColumn(cId);
@@ -291,7 +286,7 @@
291
286
  data-dt-cell="1"
292
287
  data-col-id={cid}
293
288
  data-row-index={i}
294
- class="px-3"
289
+ class="flex h-full w-full items-center px-3"
295
290
  onclick={() => onRowClick?.(row)}
296
291
  oncontextmenu={(e) => onCellContext(e, row, cid, i)}
297
292
  >
@@ -5,14 +5,19 @@
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
- if (!node.parentNode) return { destroy: () => {} };
9
- node.parentNode.insertBefore(placeholder, node);
8
+ if (node.parentNode) {
9
+ node.parentNode.insertBefore(placeholder, node);
10
+ }
11
+ // Remove any existing menu instances
12
+ const existingMenus = document.querySelectorAll('.context-menu-portal');
13
+ existingMenus.forEach((menu) => menu.remove());
14
+ // Add class for identification
15
+ node.classList.add('context-menu-portal');
10
16
  tgt.appendChild(node);
11
17
  return {
12
18
  destroy() {
13
19
  if (node.isConnected) node.remove();
14
20
  if (placeholder.isConnected && placeholder.parentNode) {
15
- placeholder.parentNode.insertBefore(node, placeholder);
16
21
  placeholder.remove();
17
22
  }
18
23
  }
@@ -65,6 +70,12 @@
65
70
  q = '';
66
71
  x = 0;
67
72
  y = 0;
73
+ if (menuEl) {
74
+ menuEl.style.left = '0px';
75
+ menuEl.style.top = '0px';
76
+ menuEl.remove();
77
+ menuEl = null;
78
+ }
68
79
  }
69
80
 
70
81
  function hasChildren(it: TContextMenuEntry) {
@@ -170,40 +181,21 @@
170
181
  };
171
182
  });
172
183
 
173
- // Clamp de posición tras abrir o cambiar coords
184
+ // Aplicar posición tras abrir o cambiar coords
174
185
  $effect(() => {
175
186
  if (!open || !menuEl) return;
176
- requestAnimationFrame(() => {
177
- if (!menuEl) return;
178
- const rect = menuEl.getBoundingClientRect();
179
- const { x: nx, y: ny } = clampToViewport(x, y, rect.width, rect.height, 8);
180
- if (nx !== x || ny !== y) {
181
- x = nx;
182
- y = ny;
183
- }
184
- });
187
+ const rect = menuEl.getBoundingClientRect();
188
+ const { x: nx, y: ny } = clampToViewport(x, y, rect.width, rect.height, 8);
189
+ menuEl.style.left = `${nx}px`;
190
+ menuEl.style.top = `${ny}px`;
185
191
  });
186
192
  </script>
187
193
 
188
194
  {#if open}
189
- <!-- BACKDROP -->
190
- <div
191
- use:portal={portalTarget}
192
- role="dialog"
193
- class="fixed inset-0 z-[2147483646]"
194
- onclick={() => close()}
195
- oncontextmenu={(e) => e.preventDefault()}
196
- aria-modal="true"
197
- tabindex="0"
198
- style="pointer-events:auto"
199
- />
200
-
201
- <!-- MENÚ -->
202
195
  <div
203
196
  bind:this={menuEl}
204
197
  use:portal={portalTarget}
205
- class="fixed z-[2147483647] w-72 rounded-2xl bg-white p-2 shadow-xl ring-1 ring-black/5 dark:bg-gray-900"
206
- style={`left:${x}px; top:${y}px`}
198
+ class="context-menu-portal fixed z-[2147483647] w-72 rounded-2xl bg-white p-2 shadow-xl ring-1 ring-black/5 dark:bg-gray-900"
207
199
  oncontextmenu={(e) => e.preventDefault()}
208
200
  >
209
201
  <div class="flex items-center gap-1 px-1 py-1">
@@ -241,42 +233,46 @@
241
233
  <div
242
234
  class="max-h-72 overflow-auto rounded-xl border border-gray-200 p-1 dark:border-gray-800 dark:bg-gray-950"
243
235
  >
244
- {#each filtered as it}
245
- {#if it.kind === 'divider'}
246
- <div class="my-1 border-t border-gray-200 dark:border-gray-800"></div>
247
- {:else if it.kind === 'label'}
248
- <div class="px-3 py-1 text-[11px] tracking-wide uppercase opacity-60">{it.label}</div>
249
- {:else}
250
- <button
251
- class="flex w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm hover:bg-gray-100 disabled:opacity-50 dark:hover:bg-gray-800"
252
- role="dialog"
253
- disabled={it.disabled}
254
- onclick={() => clickItem(it)}
255
- >
256
- <span class="truncate">{it.label}</span>
257
- <span class="flex items-center gap-2">
258
- {#if it.shortcut}
259
- <kbd class="rounded bg-gray-100 px-1 text-[10px] dark:bg-gray-800"
260
- >{it.shortcut}</kbd
261
- >
262
- {/if}
263
- {#if hasChildren(it)}
264
- <svg
265
- width="14"
266
- height="14"
267
- viewBox="0 0 24 24"
268
- class="opacity-60"
269
- fill="none"
270
- stroke="currentColor"
271
- stroke-width="2"
272
- stroke-linecap="round"
273
- stroke-linejoin="round"><polyline points="9 18 15 12 9 6" /></svg
274
- >
275
- {/if}
276
- </span>
277
- </button>
278
- {/if}
279
- {/each}
236
+ {#if filtered.length}
237
+ {#each filtered as it}
238
+ {#if it.kind === 'divider'}
239
+ <div class="my-1 border-t border-gray-200 dark:border-gray-800"></div>
240
+ {:else if it.kind === 'label'}
241
+ <div class="px-3 py-1 text-[11px] tracking-wide uppercase opacity-60">{it.label}</div>
242
+ {:else}
243
+ <button
244
+ class="flex w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm hover:bg-gray-100 disabled:opacity-50 dark:hover:bg-gray-800"
245
+ role="dialog"
246
+ disabled={it.disabled}
247
+ onclick={() => clickItem(it)}
248
+ >
249
+ <span class="truncate">{it.label}</span>
250
+ <span class="flex items-center gap-2">
251
+ {#if it.shortcut}
252
+ <kbd class="rounded bg-gray-100 px-1 text-[10px] dark:bg-gray-800"
253
+ >{it.shortcut}</kbd
254
+ >
255
+ {/if}
256
+ {#if hasChildren(it)}
257
+ <svg
258
+ width="14"
259
+ height="14"
260
+ viewBox="0 0 24 24"
261
+ class="opacity-60"
262
+ fill="none"
263
+ stroke="currentColor"
264
+ stroke-width="2"
265
+ stroke-linecap="round"
266
+ stroke-linejoin="round"><polyline points="9 18 15 12 9 6" /></svg
267
+ >
268
+ {/if}
269
+ </span>
270
+ </button>
271
+ {/if}
272
+ {/each}
273
+ {:else}
274
+ <div class="my-1 border-t border-gray-200 dark:border-gray-800">No hay resultados</div>
275
+ {/if}
280
276
  </div>
281
277
  </div>
282
278
  {/if}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@r2digisolutions/ui",
3
- "version": "0.24.5",
3
+ "version": "0.24.7",
4
4
  "private": false,
5
5
  "packageManager": "bun@1.2.23",
6
6
  "publishConfig": {