@smartnet360/svelte-grid 0.1.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.
@@ -0,0 +1,623 @@
1
+ <script lang="ts" generics="T">
2
+ import { getContext } from 'svelte';
3
+ import type { Snippet } from 'svelte';
4
+ import type { ColumnDefinition, GridEvents, SortDirection, MenuItemDefinition, MenuContext, PopupContext } from '../types.js';
5
+ import { GRID_CONTEXT_KEY, type GridStateManager } from '../state/gridState.svelte.js';
6
+ import Popup from './Popup.svelte';
7
+ import Menu from './Menu.svelte';
8
+
9
+ interface Props {
10
+ column: ColumnDefinition<T>;
11
+ index: number;
12
+ columnWidth?: number;
13
+ onheaderclick?: GridEvents<T>['headerclick'];
14
+ headerCell?: Snippet<[ColumnDefinition<T>]>;
15
+ onsort?: (field: string, direction: SortDirection, multiSort: boolean) => void;
16
+ sortDirection?: SortDirection;
17
+ sortIndex?: number;
18
+ onresizestart?: (field: string, startX: number, startWidth: number) => void;
19
+ frozenPosition?: { side: 'left' | 'right'; offset: number };
20
+ }
21
+
22
+ let {
23
+ column,
24
+ index,
25
+ columnWidth,
26
+ onheaderclick,
27
+ headerCell,
28
+ onsort,
29
+ sortDirection = 'none',
30
+ sortIndex = -1,
31
+ onresizestart,
32
+ frozenPosition
33
+ }: Props = $props();
34
+
35
+ // Get grid state for filtering
36
+ const gridState = getContext<GridStateManager<T>>(GRID_CONTEXT_KEY);
37
+
38
+ // ============================================
39
+ // Menu & Popup State
40
+ // ============================================
41
+
42
+ let menuOpen = $state(false);
43
+ let menuTargetRect = $state<DOMRect | null>(null);
44
+ let menuButtonRef: HTMLButtonElement | undefined = $state();
45
+
46
+ let popupOpen = $state(false);
47
+ let popupTargetRect = $state<DOMRect | null>(null);
48
+ let popupButtonRef: HTMLButtonElement | undefined = $state();
49
+
50
+ // Computed: Does this column have a header menu?
51
+ const hasHeaderMenu = $derived(
52
+ column.headerMenu !== undefined &&
53
+ (Array.isArray(column.headerMenu) ? column.headerMenu.length > 0 : true)
54
+ );
55
+
56
+ // Computed: Does this column have a header popup?
57
+ const hasHeaderPopup = $derived(column.headerPopup !== undefined);
58
+ const showPopupIcon = $derived(column.headerPopupIcon !== undefined && column.headerPopupIcon !== false);
59
+
60
+ // Get menu items (resolve function if needed)
61
+ const menuItems = $derived.by((): MenuItemDefinition<T>[] => {
62
+ if (!column.headerMenu) return [];
63
+ if (typeof column.headerMenu === 'function') {
64
+ return column.headerMenu(column);
65
+ }
66
+ return column.headerMenu;
67
+ });
68
+
69
+ // Menu context
70
+ const menuContext = $derived<MenuContext<T>>({
71
+ column,
72
+ closeMenu: () => {
73
+ menuOpen = false;
74
+ }
75
+ });
76
+
77
+ // Popup context
78
+ const popupContext = $derived<PopupContext<T>>({
79
+ column,
80
+ closePopup: () => {
81
+ popupOpen = false;
82
+ }
83
+ });
84
+
85
+ // Get popup icon
86
+ const popupIcon = $derived.by(() => {
87
+ if (typeof column.headerPopupIcon === 'string') {
88
+ return column.headerPopupIcon;
89
+ }
90
+ // Default filter icon
91
+ return '⚙';
92
+ });
93
+
94
+ // ============================================
95
+ // Menu/Popup Handlers
96
+ // ============================================
97
+
98
+ function handleMenuClick(event: MouseEvent) {
99
+ event.stopPropagation();
100
+ if (menuButtonRef) {
101
+ menuTargetRect = menuButtonRef.getBoundingClientRect();
102
+ }
103
+ menuOpen = !menuOpen;
104
+ popupOpen = false; // Close popup if open
105
+ }
106
+
107
+ function handlePopupClick(event: MouseEvent) {
108
+ event.stopPropagation();
109
+ if (popupButtonRef) {
110
+ popupTargetRect = popupButtonRef.getBoundingClientRect();
111
+ }
112
+ popupOpen = !popupOpen;
113
+ menuOpen = false; // Close menu if open
114
+ }
115
+
116
+ function closeMenu() {
117
+ menuOpen = false;
118
+ }
119
+
120
+ function closePopup() {
121
+ popupOpen = false;
122
+ }
123
+
124
+ // ============================================
125
+ // Popup Content Rendering
126
+ // ============================================
127
+
128
+ function getPopupContent(): string | null {
129
+ if (!column.headerPopup) return null;
130
+ if (typeof column.headerPopup === 'string') {
131
+ return column.headerPopup;
132
+ }
133
+ if (typeof column.headerPopup === 'function') {
134
+ const result = column.headerPopup(popupContext);
135
+ return typeof result === 'string' ? result : null;
136
+ }
137
+ return null;
138
+ }
139
+
140
+ const isSnippetPopup = $derived(
141
+ column.headerPopup !== undefined &&
142
+ typeof column.headerPopup !== 'string' &&
143
+ typeof column.headerPopup !== 'function'
144
+ );
145
+
146
+ // ============================================
147
+ // Computed
148
+ // ============================================
149
+
150
+ const cellStyle = $derived.by(() => {
151
+ const styles: string[] = [];
152
+
153
+ // Use columnWidth (from resize) if available, else column.width
154
+ const width = columnWidth ?? column.width;
155
+
156
+ if (width) {
157
+ const w = typeof width === 'number' ? `${width}px` : width;
158
+ styles.push(`width: ${w}`);
159
+ styles.push(`min-width: ${w}`);
160
+ } else {
161
+ styles.push('flex: 1');
162
+ styles.push('min-width: 100px');
163
+ }
164
+
165
+ if (column.minWidth && !columnWidth) {
166
+ styles.push(`min-width: ${column.minWidth}px`);
167
+ }
168
+
169
+ if (column.maxWidth) {
170
+ styles.push(`max-width: ${column.maxWidth}px`);
171
+ }
172
+
173
+ // Frozen column positioning
174
+ if (frozenPosition) {
175
+ styles.push('position: sticky');
176
+ styles.push(`${frozenPosition.side}: ${frozenPosition.offset}px`);
177
+ styles.push('z-index: 2');
178
+ }
179
+
180
+ return styles.join('; ');
181
+ });
182
+
183
+ const isFrozen = $derived(!!frozenPosition);
184
+
185
+ const alignClass = $derived.by(() => {
186
+ if (column.hAlign === 'center') return 'sg-align-center';
187
+ if (column.hAlign === 'right') return 'sg-align-right';
188
+ return 'sg-align-left';
189
+ });
190
+
191
+ const sortable = $derived(column.sortable === true);
192
+ const filterable = $derived(column.headerFilter === true);
193
+
194
+ const ariaSort = $derived.by(() => {
195
+ if (sortDirection === 'asc') return 'ascending';
196
+ if (sortDirection === 'desc') return 'descending';
197
+ return 'none';
198
+ });
199
+
200
+ // ============================================
201
+ // Event Handlers
202
+ // ============================================
203
+
204
+ function handleClick(event: MouseEvent) {
205
+ // Don't trigger sort if clicking on filter input
206
+ if ((event.target as HTMLElement).closest('.sg-header-filter')) {
207
+ return;
208
+ }
209
+
210
+ // Don't trigger sort if clicking on menu/popup buttons
211
+ if ((event.target as HTMLElement).closest('.sg-header-menu-btn, .sg-header-popup-btn')) {
212
+ return;
213
+ }
214
+
215
+ // Don't trigger sort if clicking near the resize handle area (right 12px)
216
+ if (onresizestart) {
217
+ const rect = (event.currentTarget as HTMLElement).getBoundingClientRect();
218
+ const clickX = event.clientX - rect.left;
219
+ const rightEdgeZone = rect.width - 12; // 12px dead zone for resize
220
+ if (clickX > rightEdgeZone) {
221
+ return;
222
+ }
223
+ }
224
+
225
+ if (sortable) {
226
+ const multiSort = event.shiftKey;
227
+ onsort?.(column.field, sortDirection, multiSort);
228
+ }
229
+
230
+ onheaderclick?.(column, event);
231
+ }
232
+
233
+ function handleKeydown(event: KeyboardEvent) {
234
+ if (event.key === 'Enter' || event.key === ' ') {
235
+ event.preventDefault();
236
+ if (sortable) {
237
+ const multiSort = event.shiftKey;
238
+ onsort?.(column.field, sortDirection, multiSort);
239
+ }
240
+ onheaderclick?.(column, event as unknown as MouseEvent);
241
+ }
242
+ }
243
+
244
+ function handleFilterInput(event: Event) {
245
+ const value = (event.target as HTMLInputElement).value;
246
+ gridState?.setHeaderFilter(column.field, value);
247
+ }
248
+
249
+ function handleResizeMouseDown(event: MouseEvent) {
250
+ event.preventDefault();
251
+ event.stopPropagation();
252
+ const currentWidth = columnWidth ?? (typeof column.width === 'number' ? column.width : 150);
253
+ onresizestart?.(column.field, event.clientX, currentWidth);
254
+ }
255
+
256
+ function handleResizeDblClick(event: MouseEvent) {
257
+ event.preventDefault();
258
+ event.stopPropagation();
259
+ // Auto-fit column width on double-click
260
+ gridState?.autoFitColumn(column.field);
261
+ }
262
+ </script>
263
+
264
+ <div
265
+ class="sg-header-cell {alignClass} {column.cssClass ?? ''}"
266
+ class:sg-sortable={sortable}
267
+ class:sg-sorted={sortDirection !== 'none'}
268
+ class:sg-frozen={isFrozen}
269
+ class:sg-frozen-left={frozenPosition?.side === 'left'}
270
+ class:sg-frozen-right={frozenPosition?.side === 'right'}
271
+ style={cellStyle}
272
+ role="columnheader"
273
+ aria-colindex={index + 1}
274
+ aria-sort={ariaSort}
275
+ tabindex={sortable ? 0 : -1}
276
+ title={column.headerTooltip ?? column.title}
277
+ onclick={handleClick}
278
+ onkeydown={handleKeydown}
279
+ >
280
+ <div class="sg-header-cell-main">
281
+ {#if headerCell}
282
+ {@render headerCell(column)}
283
+ {:else}
284
+ <span class="sg-header-cell-content">
285
+ {column.title}
286
+ </span>
287
+ {/if}
288
+
289
+ <!-- Sort indicator -->
290
+ {#if sortable}
291
+ <span class="sg-sort-indicator" class:sg-sort-active={sortDirection !== 'none'}>
292
+ {#if sortDirection === 'asc'}
293
+ <svg class="sg-sort-icon" viewBox="0 0 24 24" fill="currentColor">
294
+ <path d="M7 14l5-5 5 5H7z" />
295
+ </svg>
296
+ {:else if sortDirection === 'desc'}
297
+ <svg class="sg-sort-icon" viewBox="0 0 24 24" fill="currentColor">
298
+ <path d="M7 10l5 5 5-5H7z" />
299
+ </svg>
300
+ {:else}
301
+ <svg class="sg-sort-icon sg-sort-icon-inactive" viewBox="0 0 24 24" fill="currentColor">
302
+ <path d="M7 10l5-5 5 5H7z M7 14l5 5 5-5H7z" />
303
+ </svg>
304
+ {/if}
305
+ {#if sortIndex >= 0}
306
+ <span class="sg-sort-index">{sortIndex + 1}</span>
307
+ {/if}
308
+ </span>
309
+ {/if}
310
+
311
+ <!-- Header popup icon -->
312
+ {#if showPopupIcon && hasHeaderPopup}
313
+ <button
314
+ bind:this={popupButtonRef}
315
+ class="sg-header-popup-btn"
316
+ class:sg-popup-open={popupOpen}
317
+ onclick={handlePopupClick}
318
+ title="Open popup"
319
+ aria-label="Open column popup"
320
+ aria-expanded={popupOpen}
321
+ >
322
+ {popupIcon}
323
+ </button>
324
+ {/if}
325
+
326
+ <!-- Header menu button -->
327
+ {#if hasHeaderMenu}
328
+ <button
329
+ bind:this={menuButtonRef}
330
+ class="sg-header-menu-btn"
331
+ class:sg-menu-open={menuOpen}
332
+ onclick={handleMenuClick}
333
+ title="Open menu"
334
+ aria-label="Open column menu"
335
+ aria-haspopup="menu"
336
+ aria-expanded={menuOpen}
337
+ >
338
+ <svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14">
339
+ <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
340
+ </svg>
341
+ </button>
342
+ {/if}
343
+ </div>
344
+
345
+ <!-- Header menu popup -->
346
+ {#if hasHeaderMenu && menuOpen}
347
+ <Popup open={menuOpen} targetRect={menuTargetRect} position="bottom-end" onclose={closeMenu}>
348
+ <Menu items={menuItems} context={menuContext} />
349
+ </Popup>
350
+ {/if}
351
+
352
+ <!-- Header popup -->
353
+ {#if hasHeaderPopup && popupOpen}
354
+ <Popup open={popupOpen} targetRect={popupTargetRect} position="bottom-start" onclose={closePopup}>
355
+ <div class="sg-header-popup-content">
356
+ {#if isSnippetPopup && column.headerPopup}
357
+ {@render (column.headerPopup as import('svelte').Snippet<[PopupContext<T>]>)(popupContext)}
358
+ {:else}
359
+ {@html getPopupContent() ?? ''}
360
+ {/if}
361
+ </div>
362
+ </Popup>
363
+ {/if}
364
+
365
+ <!-- Header filter input -->
366
+ {#if filterable}
367
+ <div class="sg-header-filter">
368
+ <input
369
+ type="text"
370
+ class="sg-header-filter-input"
371
+ placeholder="Filter..."
372
+ value={gridState?.getHeaderFilter(column.field) ?? ''}
373
+ oninput={handleFilterInput}
374
+ onclick={(e) => e.stopPropagation()}
375
+ />
376
+ </div>
377
+ {/if}
378
+
379
+ <!-- Resize handle -->
380
+ {#if onresizestart}
381
+ <div
382
+ class="sg-resize-handle"
383
+ onmousedown={handleResizeMouseDown}
384
+ ondblclick={handleResizeDblClick}
385
+ role="separator"
386
+ aria-orientation="vertical"
387
+ title="Drag to resize, double-click to auto-fit"
388
+ ></div>
389
+ {/if}
390
+ </div>
391
+
392
+ <style>
393
+ .sg-header-cell {
394
+ display: flex;
395
+ flex-direction: column;
396
+ justify-content: center;
397
+ padding: var(--sg-cell-padding-y) var(--sg-cell-padding-x);
398
+ font-weight: var(--sg-header-font-weight, 600);
399
+ font-size: var(--sg-header-font-size, 12px);
400
+ letter-spacing: var(--sg-header-letter-spacing, 0.025em);
401
+ text-transform: uppercase;
402
+ color: var(--sg-header-color, #475569);
403
+ user-select: none;
404
+ overflow: hidden;
405
+ box-sizing: border-box;
406
+ position: relative;
407
+ transition: background-color var(--sg-transition-fast, 0.1s ease);
408
+ }
409
+
410
+ .sg-header-cell.sg-sortable {
411
+ cursor: pointer;
412
+ }
413
+
414
+ .sg-header-cell.sg-sortable:hover {
415
+ background-color: var(--sg-header-hover-bg, rgba(0, 0, 0, 0.04));
416
+ }
417
+
418
+ .sg-header-cell.sg-sorted {
419
+ background-color: var(--sg-header-sorted-bg, rgba(59, 130, 246, 0.08));
420
+ }
421
+
422
+ .sg-header-cell:focus {
423
+ outline: 2px solid var(--sg-primary-color, #3b82f6);
424
+ outline-offset: -2px;
425
+ }
426
+
427
+ .sg-header-cell-main {
428
+ display: flex;
429
+ align-items: center;
430
+ gap: 6px;
431
+ min-height: 24px;
432
+ }
433
+
434
+ .sg-header-cell-content {
435
+ overflow: hidden;
436
+ text-overflow: ellipsis;
437
+ white-space: nowrap;
438
+ flex: 1;
439
+ }
440
+
441
+ /* Alignment */
442
+ .sg-align-left .sg-header-cell-main {
443
+ justify-content: flex-start;
444
+ text-align: left;
445
+ }
446
+
447
+ .sg-align-center .sg-header-cell-main {
448
+ justify-content: center;
449
+ text-align: center;
450
+ }
451
+
452
+ .sg-align-right .sg-header-cell-main {
453
+ justify-content: flex-end;
454
+ text-align: right;
455
+ }
456
+
457
+ /* Sort indicator */
458
+ .sg-sort-indicator {
459
+ display: flex;
460
+ align-items: center;
461
+ gap: 2px;
462
+ flex-shrink: 0;
463
+ opacity: 0.4;
464
+ transition: opacity 0.15s ease;
465
+ }
466
+
467
+ .sg-sortable:hover .sg-sort-indicator {
468
+ opacity: 0.7;
469
+ }
470
+
471
+ .sg-sort-indicator.sg-sort-active {
472
+ opacity: 1;
473
+ color: var(--sg-primary-color, #3b82f6);
474
+ }
475
+
476
+ .sg-sort-icon {
477
+ width: 16px;
478
+ height: 16px;
479
+ }
480
+
481
+ .sg-sort-icon-inactive {
482
+ opacity: 0.5;
483
+ }
484
+
485
+ .sg-sort-index {
486
+ font-size: 10px;
487
+ font-weight: 700;
488
+ color: var(--sg-primary-color, #3b82f6);
489
+ }
490
+
491
+ /* Header filter */
492
+ .sg-header-filter {
493
+ margin-top: 4px;
494
+ }
495
+
496
+ .sg-header-filter-input {
497
+ width: 100%;
498
+ padding: 4px 8px;
499
+ font-size: 12px;
500
+ border: 1px solid var(--sg-border-color, #e2e8f0);
501
+ border-radius: 4px;
502
+ background: var(--sg-filter-input-bg, #fff);
503
+ color: var(--sg-text-color, #1e293b);
504
+ box-sizing: border-box;
505
+ }
506
+
507
+ .sg-header-filter-input:focus {
508
+ outline: none;
509
+ border-color: var(--sg-primary-color, #3b82f6);
510
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
511
+ }
512
+
513
+ .sg-header-filter-input::placeholder {
514
+ color: var(--sg-placeholder-color, #94a3b8);
515
+ }
516
+
517
+ /* Resize handle */
518
+ .sg-resize-handle {
519
+ position: absolute;
520
+ top: 0;
521
+ right: 0;
522
+ width: 10px;
523
+ height: 100%;
524
+ cursor: col-resize;
525
+ background: transparent;
526
+ transition: background-color 0.15s ease;
527
+ }
528
+
529
+ .sg-resize-handle:hover {
530
+ background-color: var(--sg-primary-color, #3b82f6);
531
+ }
532
+
533
+ .sg-resize-handle:active {
534
+ background-color: var(--sg-primary-color, #3b82f6);
535
+ }
536
+
537
+ /* Frozen column styles */
538
+ .sg-frozen {
539
+ background: var(--sg-header-bg, #f8fafc);
540
+ }
541
+
542
+ .sg-frozen-left {
543
+ border-right: 2px solid var(--sg-frozen-border-color, #cbd5e1);
544
+ box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
545
+ }
546
+
547
+ .sg-frozen-right {
548
+ border-left: 2px solid var(--sg-frozen-border-color, #cbd5e1);
549
+ box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1);
550
+ }
551
+
552
+ /* Header menu button */
553
+ .sg-header-menu-btn {
554
+ display: flex;
555
+ align-items: center;
556
+ justify-content: center;
557
+ width: 20px;
558
+ height: 20px;
559
+ padding: 0;
560
+ border: none;
561
+ background: transparent;
562
+ color: var(--sg-header-icon-color, #64748b);
563
+ cursor: pointer;
564
+ border-radius: 4px;
565
+ flex-shrink: 0;
566
+ opacity: 0;
567
+ transition: opacity 0.15s ease, background-color 0.15s ease;
568
+ }
569
+
570
+ .sg-header-cell:hover .sg-header-menu-btn,
571
+ .sg-header-menu-btn.sg-menu-open {
572
+ opacity: 1;
573
+ }
574
+
575
+ .sg-header-menu-btn:hover {
576
+ background: var(--sg-header-icon-hover-bg, rgba(0, 0, 0, 0.1));
577
+ }
578
+
579
+ .sg-header-menu-btn.sg-menu-open {
580
+ background: var(--sg-header-icon-active-bg, rgba(59, 130, 246, 0.2));
581
+ color: var(--sg-primary-color, #3b82f6);
582
+ }
583
+
584
+ /* Header popup button */
585
+ .sg-header-popup-btn {
586
+ display: flex;
587
+ align-items: center;
588
+ justify-content: center;
589
+ width: 20px;
590
+ height: 20px;
591
+ padding: 0;
592
+ border: none;
593
+ background: transparent;
594
+ color: var(--sg-header-icon-color, #64748b);
595
+ cursor: pointer;
596
+ border-radius: 4px;
597
+ flex-shrink: 0;
598
+ font-size: 12px;
599
+ opacity: 0;
600
+ transition: opacity 0.15s ease, background-color 0.15s ease;
601
+ }
602
+
603
+ .sg-header-cell:hover .sg-header-popup-btn,
604
+ .sg-header-popup-btn.sg-popup-open {
605
+ opacity: 1;
606
+ }
607
+
608
+ .sg-header-popup-btn:hover {
609
+ background: var(--sg-header-icon-hover-bg, rgba(0, 0, 0, 0.1));
610
+ }
611
+
612
+ .sg-header-popup-btn.sg-popup-open {
613
+ background: var(--sg-header-icon-active-bg, rgba(59, 130, 246, 0.2));
614
+ color: var(--sg-primary-color, #3b82f6);
615
+ }
616
+
617
+ /* Header popup content */
618
+ .sg-header-popup-content {
619
+ padding: 12px;
620
+ font-size: 13px;
621
+ font-weight: normal;
622
+ }
623
+ </style>
@@ -0,0 +1,40 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ColumnDefinition, GridEvents, SortDirection } from '../types.js';
3
+ declare function $$render<T>(): {
4
+ props: {
5
+ column: ColumnDefinition<T>;
6
+ index: number;
7
+ columnWidth?: number;
8
+ onheaderclick?: GridEvents<T>["headerclick"];
9
+ headerCell?: Snippet<[ColumnDefinition<T>]>;
10
+ onsort?: (field: string, direction: SortDirection, multiSort: boolean) => void;
11
+ sortDirection?: SortDirection;
12
+ sortIndex?: number;
13
+ onresizestart?: (field: string, startX: number, startWidth: number) => void;
14
+ frozenPosition?: {
15
+ side: "left" | "right";
16
+ offset: number;
17
+ };
18
+ };
19
+ exports: {};
20
+ bindings: "";
21
+ slots: {};
22
+ events: {};
23
+ };
24
+ declare class __sveltets_Render<T> {
25
+ props(): ReturnType<typeof $$render<T>>['props'];
26
+ events(): ReturnType<typeof $$render<T>>['events'];
27
+ slots(): ReturnType<typeof $$render<T>>['slots'];
28
+ bindings(): "";
29
+ exports(): {};
30
+ }
31
+ interface $$IsomorphicComponent {
32
+ 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']>> & {
33
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
34
+ } & ReturnType<__sveltets_Render<T>['exports']>;
35
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
36
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
37
+ }
38
+ declare const HeaderCell: $$IsomorphicComponent;
39
+ type HeaderCell<T> = InstanceType<typeof HeaderCell<T>>;
40
+ export default HeaderCell;