flowbite-svelte 1.24.0 → 1.25.0

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.
@@ -194,7 +194,7 @@
194
194
  @component
195
195
  [Go to docs](https://flowbite-svelte.com/)
196
196
  ## Type
197
- [CommandPaletteProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L2189)
197
+ [CommandPaletteProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L2190)
198
198
  ## Props
199
199
  @prop open = $bindable(false)
200
200
  @prop items = []
@@ -2,7 +2,7 @@ import type { CommandPaletteProps } from "../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [CommandPaletteProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L2189)
5
+ * [CommandPaletteProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L2190)
6
6
  * ## Props
7
7
  * @prop open = $bindable(false)
8
8
  * @prop items = []
package/dist/index.d.ts CHANGED
@@ -84,3 +84,4 @@ export * from "./kanban";
84
84
  export * from "./split-pane";
85
85
  export * from "./tour";
86
86
  export * from "./scroll-spy";
87
+ export * from "./virtual-masonry";
package/dist/index.js CHANGED
@@ -90,3 +90,4 @@ export * from "./kanban";
90
90
  export * from "./split-pane";
91
91
  export * from "./tour";
92
92
  export * from "./scroll-spy";
93
+ export * from "./virtual-masonry";
@@ -255,7 +255,7 @@
255
255
  @component
256
256
  [Go to docs](https://flowbite-svelte.com/)
257
257
  ## Type
258
- [ScrollSpyProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L2204)
258
+ [ScrollSpyProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L2205)
259
259
  ## Props
260
260
  @prop items
261
261
  @prop position = "top"
@@ -2,7 +2,7 @@ import type { ScrollSpyProps } from "../types";
2
2
  /**
3
3
  * [Go to docs](https://flowbite-svelte.com/)
4
4
  * ## Type
5
- * [ScrollSpyProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L2204)
5
+ * [ScrollSpyProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts#L2205)
6
6
  * ## Props
7
7
  * @prop items
8
8
  * @prop position = "top"
@@ -3,8 +3,9 @@
3
3
  import { divider, dividerHitArea } from "./theme";
4
4
  import { getTheme } from "../theme/themeUtils";
5
5
  import clsx from "clsx";
6
+ import { nonPassiveTouch } from "../utils/nonPassiveTouch";
6
7
 
7
- let { direction, index, onMouseDown, onKeyDown, isDragging, currentSize, class: className = "" }: DividerProps = $props();
8
+ let { direction, index, onMouseDown, onTouchStart, onKeyDown, isDragging, currentSize, class: className = "" }: DividerProps = $props();
8
9
 
9
10
  const themePane = getTheme("divider");
10
11
  const themeDividerHitArea = getTheme("dividerHitArea");
@@ -26,6 +27,7 @@
26
27
  aria-valuetext={`${roundedSize} percent`}
27
28
  class={divider({ direction, isDragging, class: clsx(themePane, className) })}
28
29
  onmousedown={(e) => onMouseDown(e, index)}
30
+ use:nonPassiveTouch={(e) => onTouchStart(e, index)}
29
31
  onkeydown={(e) => onKeyDown(e, index)}
30
32
  >
31
33
  <div class={dividerHitArea({ direction, class: clsx(themeDividerHitArea, className) })}></div>
@@ -40,6 +42,7 @@
40
42
  @prop direction
41
43
  @prop index
42
44
  @prop onMouseDown
45
+ @prop onTouchStart
43
46
  @prop onKeyDown
44
47
  @prop isDragging
45
48
  @prop currentSize
@@ -7,6 +7,7 @@ import type { DividerProps } from "../types";
7
7
  * @prop direction
8
8
  * @prop index
9
9
  * @prop onMouseDown
10
+ * @prop onTouchStart
10
11
  * @prop onKeyDown
11
12
  * @prop isDragging
12
13
  * @prop currentSize
@@ -32,7 +32,15 @@
32
32
  </div>
33
33
 
34
34
  {#if showDivider && context}
35
- <Divider {direction} index={paneIndex} {isDragging} currentSize={context.getPaneSize(paneIndex)} onMouseDown={context.onMouseDown} onKeyDown={context.onKeyDown} />
35
+ <Divider
36
+ {direction}
37
+ index={paneIndex}
38
+ {isDragging}
39
+ currentSize={context.getPaneSize(paneIndex)}
40
+ onMouseDown={context.onMouseDown}
41
+ onTouchStart={context.onTouchStart}
42
+ onKeyDown={context.onKeyDown}
43
+ />
36
44
  {/if}
37
45
 
38
46
  <!--
@@ -11,6 +11,7 @@
11
11
  getDirection: () => "horizontal" | "vertical";
12
12
  getIsDragging: () => boolean;
13
13
  onMouseDown: (e: MouseEvent, index: number) => void;
14
+ onTouchStart: (e: TouchEvent, index: number) => void;
14
15
  onKeyDown: (e: KeyboardEvent, index: number) => void;
15
16
  }
16
17
 
@@ -106,6 +107,7 @@
106
107
  getDirection: () => currentDirection,
107
108
  getIsDragging: () => isDragging,
108
109
  onMouseDown: startResize,
110
+ onTouchStart: startTouchResize,
109
111
  onKeyDown: handleKeyResize
110
112
  });
111
113
 
@@ -281,48 +283,74 @@
281
283
  document.body.style.userSelect = "";
282
284
  }
283
285
 
284
- function resize(e: MouseEvent, index: number) {
285
- if (!isDragging || !container) return;
286
- if (index < 0 || index + 1 >= sizes.length) return;
287
-
288
- const currentPos = currentDirection === "horizontal" ? e.clientX : e.clientY;
289
- const delta = currentPos - startPos;
286
+ function startTouchResize(e: TouchEvent, index: number) {
287
+ e.preventDefault();
288
+ isDragging = true;
289
+ transition = false;
290
290
 
291
- if (Math.abs(delta) < MIN_DELTA) return; // Ignore very small movements
291
+ const touch = e.touches[0];
292
+ startPos = currentDirection === "horizontal" ? touch.clientX : touch.clientY;
292
293
 
293
- const containerSize = currentDirection === "horizontal" ? container.offsetWidth : container.offsetHeight;
294
+ const moveHandler = (ev: TouchEvent) => resizeTouch(ev, index);
295
+ const endHandler = () => stopTouchResize(moveHandler, endHandler);
294
296
 
295
- // Bail out if container has zero or near-zero dimensions
296
- if (containerSize < 1) return;
297
+ window.addEventListener("touchmove", moveHandler, { passive: false });
298
+ window.addEventListener("touchend", endHandler);
299
+ window.addEventListener("touchcancel", endHandler);
297
300
 
298
- const deltaPercent = (delta / containerSize) * 100;
301
+ document.body.style.userSelect = "none";
302
+ }
299
303
 
300
- // Calculate min as percentage based on current container size
301
- const minPercent = (minSize / containerSize) * 100;
304
+ function stopTouchResize(moveHandler: (e: TouchEvent) => void, endHandler: () => void) {
305
+ isDragging = false;
306
+ transition = transitionProp;
307
+ window.removeEventListener("touchmove", moveHandler);
308
+ window.removeEventListener("touchend", endHandler);
309
+ window.removeEventListener("touchcancel", endHandler);
302
310
 
303
- // Store original sizes
304
- const oldSize1 = sizes[index];
305
- const oldSize2 = sizes[index + 1];
306
- const totalSize = oldSize1 + oldSize2;
311
+ document.body.style.userSelect = "";
312
+ }
307
313
 
308
- // Calculate desired new sizes
309
- let newSize1 = oldSize1 + deltaPercent;
310
- let newSize2 = oldSize2 - deltaPercent;
314
+ function clampPaneSizes(index: number, targetSize: number, minPercent: number, total: number): boolean {
315
+ if (index < 0 || index + 1 >= sizes.length) return false;
311
316
 
312
- // Apply minimum constraints - clamp to valid range
313
- newSize1 = Math.max(minPercent, newSize1);
314
- newSize2 = totalSize - newSize1;
317
+ let newSize1 = Math.min(total - minPercent, Math.max(minPercent, targetSize));
318
+ let newSize2 = total - newSize1;
315
319
 
316
- // Check if second pane violates minimum constraint after first pane clamping
317
320
  if (newSize2 < minPercent) {
318
321
  newSize2 = minPercent;
319
- newSize1 = totalSize - newSize2;
322
+ newSize1 = total - newSize2;
320
323
  }
321
324
 
322
- // Only update if changed significantly
323
- if (Math.abs(newSize1 - oldSize1) > MIN_CHANGE_THRESHOLD) {
325
+ if (Math.abs(newSize1 - sizes[index]) > MIN_CHANGE_THRESHOLD) {
324
326
  sizes[index] = newSize1;
325
327
  sizes[index + 1] = newSize2;
328
+ return true;
329
+ }
330
+
331
+ return false;
332
+ }
333
+
334
+ function applyResize(currentPos: number, index: number) {
335
+ if (!isDragging || !container) return;
336
+ if (index < 0 || index + 1 >= sizes.length) return;
337
+
338
+ const delta = currentPos - startPos;
339
+ if (Math.abs(delta) < MIN_DELTA) return;
340
+
341
+ const currentContainerSize = currentDirection === "horizontal" ? container.offsetWidth : container.offsetHeight;
342
+ if (currentContainerSize < 1) return;
343
+
344
+ const deltaPercent = (delta / currentContainerSize) * 100;
345
+ const minPercent = (minSize / currentContainerSize) * 100;
346
+
347
+ const oldSize1 = sizes[index];
348
+ const oldSize2 = sizes[index + 1];
349
+ const totalSize = oldSize1 + oldSize2;
350
+
351
+ const targetSize = oldSize1 + deltaPercent;
352
+
353
+ if (clampPaneSizes(index, targetSize, minPercent, totalSize)) {
326
354
  startPos = currentPos;
327
355
  }
328
356
  }
@@ -331,41 +359,24 @@
331
359
  if (!container) return;
332
360
  if (index < 0 || index + 1 >= sizes.length) return;
333
361
 
334
- const step = keyboardStep;
335
- let handled = false;
336
-
337
362
  const isHorizontal = currentDirection === "horizontal";
338
363
  const increaseKeys = isHorizontal ? ["ArrowRight"] : ["ArrowDown"];
339
364
  const decreaseKeys = isHorizontal ? ["ArrowLeft"] : ["ArrowUp"];
340
365
 
341
366
  const containerSize = isHorizontal ? container.offsetWidth : container.offsetHeight;
342
- // Bail out if container has zero or near-zero dimensions
343
367
  if (containerSize < 1) return;
344
368
 
345
369
  const minPercent = (minSize / containerSize) * 100;
346
-
347
370
  const total = sizes[index] + sizes[index + 1];
348
371
 
349
- const applyClamp = (target: number) => {
350
- let newSize1 = Math.min(total - minPercent, Math.max(minPercent, target));
351
- let newSize2 = total - newSize1;
352
-
353
- if (newSize2 < minPercent) {
354
- newSize2 = minPercent;
355
- newSize1 = total - newSize2;
356
- }
357
-
358
- if (Math.abs(newSize1 - sizes[index]) > MIN_CHANGE_THRESHOLD) {
359
- sizes[index] = newSize1;
360
- sizes[index + 1] = newSize2;
361
- handled = true;
362
- }
363
- };
372
+ let handled = false;
364
373
 
365
374
  if (increaseKeys.includes(e.key)) {
366
- applyClamp(sizes[index] + step);
375
+ const targetSize = sizes[index] + keyboardStep;
376
+ handled = clampPaneSizes(index, targetSize, minPercent, total);
367
377
  } else if (decreaseKeys.includes(e.key)) {
368
- applyClamp(sizes[index] - step);
378
+ const targetSize = sizes[index] - keyboardStep;
379
+ handled = clampPaneSizes(index, targetSize, minPercent, total);
369
380
  } else if (e.key === "Enter" || e.key === " ") {
370
381
  // Reset to equal sizes
371
382
  const equal = 100 / registeredPanes;
@@ -377,6 +388,18 @@
377
388
  e.preventDefault();
378
389
  }
379
390
  }
391
+
392
+ function resize(e: MouseEvent, index: number) {
393
+ const currentPos = currentDirection === "horizontal" ? e.clientX : e.clientY;
394
+ applyResize(currentPos, index);
395
+ }
396
+
397
+ function resizeTouch(e: TouchEvent, index: number) {
398
+ e.preventDefault(); // Prevent scrolling while dragging
399
+ const touch = e.touches[0];
400
+ const currentPos = currentDirection === "horizontal" ? touch.clientX : touch.clientY;
401
+ applyResize(currentPos, index);
402
+ }
380
403
  </script>
381
404
 
382
405
  <div bind:this={container} class={splitpane({ direction: currentDirection, class: clsx(theme, className) })}>
@@ -6,6 +6,7 @@ interface SplitPaneContext {
6
6
  getDirection: () => "horizontal" | "vertical";
7
7
  getIsDragging: () => boolean;
8
8
  onMouseDown: (e: MouseEvent, index: number) => void;
9
+ onTouchStart: (e: TouchEvent, index: number) => void;
9
10
  onKeyDown: (e: KeyboardEvent, index: number) => void;
10
11
  }
11
12
  export declare function setSplitPaneContext(ctx: SplitPaneContext): void;
@@ -74,3 +74,4 @@ export { kanbanBoard, kanbanCard } from "../kanban/theme";
74
74
  export { splitpane, pane, divider, dividerHitArea } from "../split-pane/theme";
75
75
  export { tour } from "../tour/theme";
76
76
  export { scrollspy } from "../scroll-spy/theme";
77
+ export { virtualMasonry } from "../virtual-masonry/theme";
@@ -81,3 +81,4 @@ export { kanbanBoard, kanbanCard } from "../kanban/theme";
81
81
  export { splitpane, pane, divider, dividerHitArea } from "../split-pane/theme";
82
82
  export { tour } from "../tour/theme";
83
83
  export { scrollspy } from "../scroll-spy/theme";
84
+ export { virtualMasonry } from "../virtual-masonry/theme";
package/dist/types.d.ts CHANGED
@@ -1815,6 +1815,7 @@ export interface DividerProps {
1815
1815
  direction: "horizontal" | "vertical";
1816
1816
  index: number;
1817
1817
  onMouseDown: (e: MouseEvent, index: number) => void;
1818
+ onTouchStart: (e: TouchEvent, index: number) => void;
1818
1819
  onKeyDown: (e: KeyboardEvent, index: number) => void;
1819
1820
  isDragging: boolean;
1820
1821
  class?: string;
@@ -1882,3 +1883,17 @@ export interface ScrollSpyProps extends ScrollSpyVariants, HTMLAttributes<HTMLEl
1882
1883
  /** Callback when navigation item is clicked */
1883
1884
  onNavigate?: (itemId: string) => void;
1884
1885
  }
1886
+ import type { VirtualMasonryVariants } from "./virtual-masonry/theme";
1887
+ export interface VirtualMasonryProps<T = unknown> extends VirtualMasonryVariants, Omit<HTMLAttributes<HTMLDivElement>, "children"> {
1888
+ children: Snippet<[item: T, index: number]>;
1889
+ items?: T[];
1890
+ columns?: number;
1891
+ gap?: number;
1892
+ height?: number;
1893
+ overscan?: number;
1894
+ getItemHeight?: (item: T, index: number) => number;
1895
+ scrollToIndex?: (fn: (index: number) => void) => void;
1896
+ contained?: boolean;
1897
+ ariaLabel?: string;
1898
+ class?: ClassValue | null;
1899
+ }
@@ -0,0 +1,3 @@
1
+ export declare function nonPassiveTouch(node: HTMLElement, handler: (event: TouchEvent) => void): {
2
+ destroy(): void;
3
+ };
@@ -0,0 +1,8 @@
1
+ export function nonPassiveTouch(node, handler) {
2
+ node.addEventListener("touchstart", handler, { passive: false });
3
+ return {
4
+ destroy() {
5
+ node.removeEventListener("touchstart", handler);
6
+ }
7
+ };
8
+ }
@@ -0,0 +1,185 @@
1
+ <script lang="ts" generics="T">
2
+ import type { VirtualMasonryProps } from "../types";
3
+ import { virtualMasonry } from "./theme";
4
+ import clsx from "clsx";
5
+ import { getTheme } from "../theme/themeUtils";
6
+
7
+ let {
8
+ items = [],
9
+ columns = 3,
10
+ gap = 16,
11
+ height = 600,
12
+ overscan = 200,
13
+ getItemHeight,
14
+ scrollToIndex,
15
+ children,
16
+ ariaLabel = "Virtual masonry grid",
17
+ class: className,
18
+ classes,
19
+ contained = false
20
+ }: VirtualMasonryProps<T> = $props();
21
+
22
+ const theme = getTheme("virtualMasonry");
23
+
24
+ let container: HTMLDivElement | undefined;
25
+ let containerWidth = $state(0);
26
+ let scrollTop = $state(0);
27
+ let rafId: number | undefined;
28
+
29
+ const styles = virtualMasonry({ contained });
30
+
31
+ const containStyle = $derived.by(() => {
32
+ if (!contained) return "";
33
+ const itemClasses = clsx(classes?.item);
34
+ const hasCustomContain = /\[contain:[^\]]+\]/.test(itemClasses);
35
+ return hasCustomContain ? "" : "contain: layout style paint;";
36
+ });
37
+
38
+ // Calculate column width based on container width
39
+ const columnWidth = $derived.by(() => {
40
+ if (containerWidth === 0) return 0;
41
+ return (containerWidth - gap * (columns - 1)) / columns;
42
+ });
43
+
44
+ // Position items in columns
45
+ interface PositionedItem {
46
+ item: T;
47
+ index: number;
48
+ x: number;
49
+ y: number;
50
+ height: number;
51
+ column: number;
52
+ }
53
+
54
+ const positionedItems = $derived.by((): PositionedItem[] => {
55
+ if (columnWidth === 0) return [];
56
+
57
+ const columnHeights = new Array(columns).fill(0);
58
+ const positioned: PositionedItem[] = [];
59
+
60
+ for (let i = 0; i < items.length; i++) {
61
+ // Find shortest column
62
+ const shortestColumn = columnHeights.indexOf(Math.min(...columnHeights));
63
+ const itemHeight = getItemHeight ? getItemHeight(items[i], i) : 200;
64
+
65
+ positioned.push({
66
+ item: items[i],
67
+ index: i,
68
+ x: shortestColumn * (columnWidth + gap),
69
+ y: columnHeights[shortestColumn],
70
+ height: itemHeight,
71
+ column: shortestColumn
72
+ });
73
+
74
+ columnHeights[shortestColumn] += itemHeight + gap;
75
+ }
76
+
77
+ return positioned;
78
+ });
79
+
80
+ // Total height is the tallest column
81
+ const totalHeight = $derived.by(() => {
82
+ if (positionedItems.length === 0) return 0;
83
+ return Math.max(...positionedItems.map((item) => item.y + item.height));
84
+ });
85
+
86
+ // Visible items based on scroll position with overscan
87
+ const visibleItems = $derived.by(() => {
88
+ const viewportTop = scrollTop - overscan;
89
+ const viewportBottom = scrollTop + height + overscan;
90
+
91
+ return positionedItems.filter((item) => {
92
+ const itemTop = item.y;
93
+ const itemBottom = item.y + item.height;
94
+ return itemBottom >= viewportTop && itemTop <= viewportBottom;
95
+ });
96
+ });
97
+
98
+ // Performance optimized scroll handler using RAF
99
+ function handleScroll() {
100
+ if (rafId) cancelAnimationFrame(rafId);
101
+ rafId = requestAnimationFrame(() => {
102
+ if (container) scrollTop = container.scrollTop;
103
+ });
104
+ }
105
+
106
+ // Scroll to specific index
107
+ function scrollToIndexImpl(index: number) {
108
+ if (!container || index < 0 || index >= items.length) return;
109
+ const item = positionedItems[index];
110
+ if (item) {
111
+ container.scrollTop = item.y;
112
+ }
113
+ }
114
+
115
+ // Bind scrollToIndex function to parent component
116
+ $effect(() => {
117
+ if (scrollToIndex) {
118
+ scrollToIndex(scrollToIndexImpl);
119
+ }
120
+ });
121
+
122
+ // Measure container width on mount and resize
123
+ $effect(() => {
124
+ if (!container) return;
125
+
126
+ const resizeObserver = new ResizeObserver((entries) => {
127
+ for (const entry of entries) {
128
+ containerWidth = entry.contentRect.width;
129
+ }
130
+ });
131
+
132
+ resizeObserver.observe(container);
133
+
134
+ return () => {
135
+ resizeObserver.disconnect();
136
+ if (rafId) cancelAnimationFrame(rafId);
137
+ };
138
+ });
139
+ </script>
140
+
141
+ <div
142
+ bind:this={container}
143
+ onscroll={handleScroll}
144
+ role="list"
145
+ aria-label={ariaLabel}
146
+ class={styles.container({ class: clsx(theme?.container, className) })}
147
+ style={`height:${height}px; position:relative;`}
148
+ >
149
+ <div class={styles.spacer({ class: clsx(theme?.spacer, classes?.spacer) })} style={`height:${totalHeight}px;`}>
150
+ <div class={styles.content({ class: clsx(theme?.content, classes?.content) })}>
151
+ {#each visibleItems as { item, index, x, y, height: itemHeight } (index)}
152
+ <div
153
+ role="listitem"
154
+ aria-setsize={items.length}
155
+ aria-posinset={index + 1}
156
+ class={styles.item({ class: clsx(theme?.item, classes?.item) })}
157
+ style={`position:absolute; left:${x}px; top:${y}px; width:${columnWidth}px; height:${itemHeight}px; ${containStyle}`}
158
+ >
159
+ {@render children?.(item, index)}
160
+ </div>
161
+ {/each}
162
+ </div>
163
+ </div>
164
+ </div>
165
+
166
+ <!--
167
+ @component
168
+ VirtualMasonry - Virtualized masonry/pinterest layout for efficient rendering of large image grids
169
+ [Go to docs](https://flowbite-svelte.com/)
170
+ ## Type
171
+ [VirtualMasonryProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts)
172
+ ## Props
173
+ @prop items = []
174
+ @prop columns = 3
175
+ @prop gap = 16
176
+ @prop height = 600
177
+ @prop overscan = 200
178
+ @prop getItemHeight
179
+ @prop scrollToIndex
180
+ @prop children
181
+ @prop ariaLabel = "Virtual masonry grid"
182
+ @prop contained = false
183
+ @prop class: className
184
+ @prop classes
185
+ -->
@@ -0,0 +1,44 @@
1
+ import type { VirtualMasonryProps } from "../types";
2
+ declare function $$render<T>(): {
3
+ props: VirtualMasonryProps<T>;
4
+ exports: {};
5
+ bindings: "";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<T> {
10
+ props(): ReturnType<typeof $$render<T>>['props'];
11
+ events(): ReturnType<typeof $$render<T>>['events'];
12
+ slots(): ReturnType<typeof $$render<T>>['slots'];
13
+ bindings(): "";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<T>['exports']>;
20
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ /**
24
+ * VirtualMasonry - Virtualized masonry/pinterest layout for efficient rendering of large image grids
25
+ * [Go to docs](https://flowbite-svelte.com/)
26
+ * ## Type
27
+ * [VirtualMasonryProps](https://github.com/themesberg/flowbite-svelte/blob/main/src/lib/types.ts)
28
+ * ## Props
29
+ * @prop items = []
30
+ * @prop columns = 3
31
+ * @prop gap = 16
32
+ * @prop height = 600
33
+ * @prop overscan = 200
34
+ * @prop getItemHeight
35
+ * @prop scrollToIndex
36
+ * @prop children
37
+ * @prop ariaLabel = "Virtual masonry grid"
38
+ * @prop contained = false
39
+ * @prop class: className
40
+ * @prop classes
41
+ */
42
+ declare const VirtualMasonry: $$IsomorphicComponent;
43
+ type VirtualMasonry<T> = InstanceType<typeof VirtualMasonry<T>>;
44
+ export default VirtualMasonry;
@@ -0,0 +1,3 @@
1
+ export { default as VirtualMasonry } from "./VirtualMasonry.svelte";
2
+ export type { VirtualMasonryVariants } from "./theme";
3
+ export { virtualMasonry } from "./theme";
@@ -0,0 +1,2 @@
1
+ export { default as VirtualMasonry } from "./VirtualMasonry.svelte";
2
+ export { virtualMasonry } from "./theme";
@@ -0,0 +1,40 @@
1
+ import { type VariantProps } from "tailwind-variants";
2
+ import type { Classes } from "../theme/themeUtils";
3
+ export declare const virtualMasonry: import("tailwind-variants").TVReturnType<{
4
+ contained: {
5
+ true: {
6
+ item: string;
7
+ };
8
+ false: {};
9
+ };
10
+ }, {
11
+ container: string;
12
+ spacer: string;
13
+ content: string;
14
+ item: string;
15
+ }, undefined, {
16
+ contained: {
17
+ true: {
18
+ item: string;
19
+ };
20
+ false: {};
21
+ };
22
+ }, {
23
+ container: string;
24
+ spacer: string;
25
+ content: string;
26
+ item: string;
27
+ }, import("tailwind-variants").TVReturnType<{
28
+ contained: {
29
+ true: {
30
+ item: string;
31
+ };
32
+ false: {};
33
+ };
34
+ }, {
35
+ container: string;
36
+ spacer: string;
37
+ content: string;
38
+ item: string;
39
+ }, undefined, unknown, unknown, undefined>>;
40
+ export type VirtualMasonryVariants = VariantProps<typeof virtualMasonry> & Classes<typeof virtualMasonry>;
@@ -0,0 +1,18 @@
1
+ import { tv } from "tailwind-variants";
2
+ export const virtualMasonry = tv({
3
+ slots: {
4
+ container: "overflow-y-auto scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-transparent",
5
+ spacer: "relative",
6
+ content: "relative w-full",
7
+ item: ""
8
+ },
9
+ variants: {
10
+ contained: {
11
+ true: { item: "[contain:layout_style_paint]" },
12
+ false: {}
13
+ }
14
+ },
15
+ defaultVariants: {
16
+ contained: false
17
+ }
18
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowbite-svelte",
3
- "version": "1.24.0",
3
+ "version": "1.25.0",
4
4
  "description": "Flowbite components for Svelte",
5
5
  "main": "dist/index.js",
6
6
  "author": {
@@ -861,6 +861,10 @@
861
861
  "types": "./dist/video/Video.svelte.d.ts",
862
862
  "svelte": "./dist/video/Video.svelte"
863
863
  },
864
+ "./VirtualMasonry.svelte": {
865
+ "types": "./dist/virtual-masonry/VirtualMasonry.svelte.d.ts",
866
+ "svelte": "./dist/virtual-masonry/VirtualMasonry.svelte"
867
+ },
864
868
  "./VirtualList.svelte": {
865
869
  "types": "./dist/virtuallist/VirtualList.svelte.d.ts",
866
870
  "svelte": "./dist/virtuallist/VirtualList.svelte"