@makolabs/ripple 0.0.1-dev.43 → 0.0.1-dev.47
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.
|
@@ -123,10 +123,21 @@
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function handleClickOutside(event: MouseEvent) {
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
// Check if the click is inside the portal content
|
|
127
|
+
const portalContent = document.querySelector('.ripple-portal .portal-content');
|
|
128
|
+
|
|
129
|
+
// If the click is inside either the label (trigger) or the portal content, don't close
|
|
130
|
+
if (
|
|
131
|
+
(labelRef && labelRef.contains(event.target as Node)) ||
|
|
132
|
+
(portalContent && portalContent.contains(event.target as Node)) ||
|
|
133
|
+
!open
|
|
134
|
+
) {
|
|
135
|
+
return;
|
|
129
136
|
}
|
|
137
|
+
|
|
138
|
+
// Otherwise close the dropdown
|
|
139
|
+
open = false;
|
|
140
|
+
onclose();
|
|
130
141
|
}
|
|
131
142
|
|
|
132
143
|
function handleKeydown(event: KeyboardEvent) {
|
package/dist/index.d.ts
CHANGED
|
@@ -198,11 +198,8 @@ export type SortState = {
|
|
|
198
198
|
export type TableProps<T extends DataRow = any> = {
|
|
199
199
|
data: T[];
|
|
200
200
|
columns: TableColumn<T>[];
|
|
201
|
-
color?: VariantColors;
|
|
202
|
-
size?: VariantSizes;
|
|
203
201
|
bordered?: boolean;
|
|
204
202
|
striped?: boolean;
|
|
205
|
-
emptyStateText?: string;
|
|
206
203
|
pageSize?: number;
|
|
207
204
|
selectable?: boolean;
|
|
208
205
|
selected?: T[];
|
|
@@ -220,6 +217,7 @@ export type TableProps<T extends DataRow = any> = {
|
|
|
220
217
|
onselect?: (selected: T[]) => void;
|
|
221
218
|
rowclass?: (row: T, index: number) => ClassValue;
|
|
222
219
|
loading?: boolean;
|
|
220
|
+
expandedContent?: Snippet<[T]>;
|
|
223
221
|
};
|
|
224
222
|
export type BreadcrumbItem = {
|
|
225
223
|
label: string;
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
import { cn } from '../../helper/cls.js';
|
|
3
3
|
import { table } from './table.js';
|
|
4
4
|
import type { TableProps, SortDirection, SortState } from '../../index.js';
|
|
5
|
+
|
|
5
6
|
let {
|
|
6
7
|
data = [],
|
|
7
8
|
columns = [],
|
|
8
|
-
color = 'default',
|
|
9
|
-
size = 'base',
|
|
10
9
|
bordered = true,
|
|
11
10
|
striped = false,
|
|
12
11
|
pageSize = 10,
|
|
@@ -25,7 +24,8 @@
|
|
|
25
24
|
tdclass: tdClass = '',
|
|
26
25
|
footerclass: footerClass = '',
|
|
27
26
|
rowclass = () => '',
|
|
28
|
-
loading = false
|
|
27
|
+
loading = false,
|
|
28
|
+
expandedContent
|
|
29
29
|
}: TableProps<any> = $props();
|
|
30
30
|
|
|
31
31
|
let sortColumn = $state('');
|
|
@@ -36,38 +36,36 @@
|
|
|
36
36
|
const pagination = $derived(pageSize > 0 && data.length > pageSize);
|
|
37
37
|
|
|
38
38
|
const {
|
|
39
|
-
base,
|
|
40
|
-
wrapper,
|
|
39
|
+
base: baseClass,
|
|
40
|
+
wrapper: wrapperBaseClass,
|
|
41
41
|
table: tableBaseClass,
|
|
42
|
-
thead,
|
|
43
|
-
tbody,
|
|
44
|
-
tr,
|
|
45
|
-
th,
|
|
46
|
-
td,
|
|
47
|
-
footer,
|
|
48
|
-
pagination:
|
|
49
|
-
emptyState,
|
|
50
|
-
sortButton,
|
|
51
|
-
sortIcon
|
|
42
|
+
thead: theadBaseClass,
|
|
43
|
+
tbody: tbodyBaseClass,
|
|
44
|
+
tr: trBaseClass,
|
|
45
|
+
th: thBaseClass,
|
|
46
|
+
td: tdBaseClass,
|
|
47
|
+
footer: footerBaseClass,
|
|
48
|
+
pagination: paginationBaseClass,
|
|
49
|
+
emptyState: emptyStateBaseClass,
|
|
50
|
+
sortButton: sortButtonBaseClass,
|
|
51
|
+
sortIcon: sortIconBaseClass
|
|
52
52
|
} = $derived(
|
|
53
53
|
table({
|
|
54
|
-
size,
|
|
55
|
-
color,
|
|
56
54
|
bordered,
|
|
57
55
|
striped
|
|
58
56
|
})
|
|
59
57
|
);
|
|
60
58
|
|
|
61
|
-
const baseClasses = $derived(cn(
|
|
62
|
-
const wrapperClasses = $derived(cn(
|
|
59
|
+
const baseClasses = $derived(cn(baseClass(), classname));
|
|
60
|
+
const wrapperClasses = $derived(cn(wrapperBaseClass(), wrapperClass));
|
|
63
61
|
const tableClasses = $derived(cn(tableBaseClass(), tableClass));
|
|
64
|
-
const theadClasses = $derived(cn(
|
|
65
|
-
const tbodyClasses = $derived(cn(
|
|
66
|
-
const trClasses = $derived(cn(
|
|
67
|
-
const thClasses = $derived(cn(
|
|
68
|
-
const tdClasses = $derived(cn(
|
|
69
|
-
const footerClasses = $derived(cn(
|
|
70
|
-
const emptyStateClasses = $derived(
|
|
62
|
+
const theadClasses = $derived(cn(theadBaseClass(), theadClass));
|
|
63
|
+
const tbodyClasses = $derived(cn(tbodyBaseClass(), tbodyClass));
|
|
64
|
+
const trClasses = $derived(cn(trBaseClass(), trClass));
|
|
65
|
+
const thClasses = $derived(cn(thBaseClass(), thClass));
|
|
66
|
+
const tdClasses = $derived(cn(tdBaseClass(), tdClass));
|
|
67
|
+
const footerClasses = $derived(cn(footerBaseClass(), footerClass));
|
|
68
|
+
const emptyStateClasses = $derived(emptyStateBaseClass());
|
|
71
69
|
|
|
72
70
|
// Handle pagination
|
|
73
71
|
const totalPages = $derived(Math.ceil(data.length / pageSize));
|
|
@@ -175,12 +173,12 @@
|
|
|
175
173
|
{#if column.sortable}
|
|
176
174
|
<button
|
|
177
175
|
type="button"
|
|
178
|
-
class={
|
|
176
|
+
class={sortButtonBaseClass()}
|
|
179
177
|
onclick={() => toggleSort(column.sortKey || column.key)}
|
|
180
178
|
aria-label={`Sort by ${column.header}`}
|
|
181
179
|
>
|
|
182
180
|
{column.header}
|
|
183
|
-
<span class={
|
|
181
|
+
<span class={sortIconBaseClass()}>
|
|
184
182
|
{#if sortColumn === (column.sortKey || column.key)}
|
|
185
183
|
{#if sortDirection === 'asc'}
|
|
186
184
|
<svg
|
|
@@ -315,6 +313,13 @@
|
|
|
315
313
|
</td>
|
|
316
314
|
{/each}
|
|
317
315
|
</tr>
|
|
316
|
+
{#if expandedContent}
|
|
317
|
+
<tr class="expandedContent-row">
|
|
318
|
+
<td colspan={selectable ? columns.length + 1 : columns.length} class="border-0 p-0">
|
|
319
|
+
{@render expandedContent(row)}
|
|
320
|
+
</td>
|
|
321
|
+
</tr>
|
|
322
|
+
{/if}
|
|
318
323
|
{/each}
|
|
319
324
|
{/if}
|
|
320
325
|
</tbody>
|
|
@@ -323,7 +328,7 @@
|
|
|
323
328
|
|
|
324
329
|
{#if pagination && totalPages > 1}
|
|
325
330
|
<div class={footerClasses}>
|
|
326
|
-
<div class={
|
|
331
|
+
<div class={paginationBaseClass()}>
|
|
327
332
|
<div class="flex items-center gap-2">
|
|
328
333
|
<span class="text-default-500 text-sm">
|
|
329
334
|
Showing {Math.min((currentPage - 1) * pageSize + 1, data.length)}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { ClassValue } from 'tailwind-variants';
|
|
2
|
-
import type { VariantColors, VariantSizes } from '../../index.js';
|
|
3
1
|
export declare const table: import("tailwind-variants").TVReturnType<{
|
|
4
2
|
size: {
|
|
5
3
|
xs: {
|
|
@@ -256,29 +254,3 @@ export declare const table: import("tailwind-variants").TVReturnType<{
|
|
|
256
254
|
sortButton: string;
|
|
257
255
|
sortIcon: string;
|
|
258
256
|
}, undefined, unknown, unknown, undefined>>;
|
|
259
|
-
export type TableProps<T extends DataRow = any> = {
|
|
260
|
-
data: T[];
|
|
261
|
-
columns: TableColumn<T>[];
|
|
262
|
-
color?: VariantColors;
|
|
263
|
-
size?: VariantSizes;
|
|
264
|
-
bordered?: boolean;
|
|
265
|
-
striped?: boolean;
|
|
266
|
-
emptyStateText?: string;
|
|
267
|
-
pageSize?: number;
|
|
268
|
-
selectable?: boolean;
|
|
269
|
-
selected?: T[];
|
|
270
|
-
class?: ClassValue;
|
|
271
|
-
wrapperclass?: ClassValue;
|
|
272
|
-
tableclass?: ClassValue;
|
|
273
|
-
theadclass?: ClassValue;
|
|
274
|
-
tbodyclass?: ClassValue;
|
|
275
|
-
trclass?: ClassValue;
|
|
276
|
-
thclass?: ClassValue;
|
|
277
|
-
tdclass?: ClassValue;
|
|
278
|
-
footerclass?: ClassValue;
|
|
279
|
-
onrowclick?: (row: T, index: number) => void;
|
|
280
|
-
onsort?: (sortState: SortState) => void;
|
|
281
|
-
onselect?: (selected: T[]) => void;
|
|
282
|
-
rowclass?: (row: T, index: number) => ClassValue;
|
|
283
|
-
loading?: boolean;
|
|
284
|
-
};
|
package/dist/utils/Portal.svelte
CHANGED
|
@@ -17,15 +17,17 @@
|
|
|
17
17
|
if (!ref || !target) return;
|
|
18
18
|
|
|
19
19
|
const { top, left, width, height } = target.getBoundingClientRect();
|
|
20
|
+
const scrollY = window.scrollY || document.documentElement.scrollTop;
|
|
21
|
+
const scrollX = window.scrollX || document.documentElement.scrollLeft;
|
|
20
22
|
|
|
21
23
|
// Set instant positioning without transitions for first render
|
|
22
24
|
if (!isPositioned) {
|
|
23
|
-
ref.style.position = '
|
|
25
|
+
ref.style.position = 'absolute';
|
|
24
26
|
ref.style.width = `${width}px`;
|
|
25
|
-
ref.style.
|
|
26
|
-
ref.style.top =
|
|
27
|
-
ref.style.left = '
|
|
28
|
-
ref.style.transform = `translate(${left}px, ${top}px)`;
|
|
27
|
+
ref.style.zIndex = '10000'; // Ensure the highest z-index
|
|
28
|
+
ref.style.top = `${height}px`; // Position below the target
|
|
29
|
+
ref.style.left = '0px';
|
|
30
|
+
ref.style.transform = `translate(${left + scrollX}px, ${top + scrollY}px)`;
|
|
29
31
|
ref.style.visibility = 'hidden'; // Keep hidden until fully positioned
|
|
30
32
|
|
|
31
33
|
// Wait for next frame to ensure positioning is applied before showing
|
|
@@ -39,7 +41,7 @@
|
|
|
39
41
|
});
|
|
40
42
|
} else {
|
|
41
43
|
// For subsequent updates, smoothly transition
|
|
42
|
-
ref.style.transform = `translate(${left}px, ${top}px)`;
|
|
44
|
+
ref.style.transform = `translate(${left + scrollX}px, ${top + scrollY}px)`;
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
|
|
@@ -56,14 +58,23 @@
|
|
|
56
58
|
// Create portal container
|
|
57
59
|
portal = document.createElement('div');
|
|
58
60
|
portal.className = 'ripple-portal';
|
|
61
|
+
portal.style.position = 'fixed';
|
|
62
|
+
portal.style.zIndex = '10000'; // Ensure highest z-index
|
|
63
|
+
portal.style.top = '0';
|
|
64
|
+
portal.style.left = '0';
|
|
65
|
+
portal.style.width = '100%';
|
|
66
|
+
portal.style.pointerEvents = 'none'; // Allow clicking through the container but not its children
|
|
59
67
|
|
|
60
68
|
// Default to document.body if no target is provided
|
|
61
|
-
const targetElement =
|
|
69
|
+
const targetElement = document.body; // Always append to body for best visibility
|
|
62
70
|
targetElement.appendChild(portal);
|
|
63
71
|
|
|
64
72
|
// Move the content to the portal
|
|
65
73
|
portal.appendChild(ref);
|
|
66
74
|
|
|
75
|
+
// Allow pointer events on the content
|
|
76
|
+
ref.style.pointerEvents = 'auto';
|
|
77
|
+
|
|
67
78
|
// Initially hide the content
|
|
68
79
|
ref.style.opacity = '0';
|
|
69
80
|
|
|
@@ -95,4 +106,3 @@
|
|
|
95
106
|
<div class="portal-content" bind:this={ref}>
|
|
96
107
|
{@render children()}
|
|
97
108
|
</div>
|
|
98
|
-
|