@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,215 @@
1
+ <script lang="ts" generics="T">
2
+ import type { MenuItemDefinition, MenuContext, MenuItemAction } from '../types.js';
3
+ import Menu from './Menu.svelte';
4
+
5
+ interface Props {
6
+ /** Menu items */
7
+ items: MenuItemDefinition<T>[];
8
+ /** Context passed to menu actions */
9
+ context: MenuContext<T>;
10
+ /** CSS class */
11
+ class?: string;
12
+ }
13
+
14
+ let { items, context, class: className = '' }: Props = $props();
15
+
16
+ // ============================================
17
+ // Submenu State
18
+ // ============================================
19
+
20
+ let activeSubmenuIndex = $state<number | null>(null);
21
+ let submenuRect = $state<DOMRect | null>(null);
22
+ let menuItemRefs: (HTMLDivElement | undefined)[] = $state([]);
23
+
24
+ // ============================================
25
+ // Event Handlers
26
+ // ============================================
27
+
28
+ // Type guard for action items
29
+ function isActionItem(item: MenuItemDefinition<T>): item is MenuItemAction<T> {
30
+ return !item.separator;
31
+ }
32
+
33
+ function handleItemClick(item: MenuItemAction<T>, event: MouseEvent) {
34
+ event.stopPropagation();
35
+
36
+ // Check if disabled
37
+ const disabled =
38
+ typeof item.disabled === 'function' ? item.disabled(context) : item.disabled;
39
+
40
+ if (disabled) return;
41
+
42
+ // If has submenu, toggle it
43
+ if (item.menu && item.menu.length > 0) {
44
+ return;
45
+ }
46
+
47
+ // Execute action and close
48
+ item.action?.(context);
49
+ context.closeMenu();
50
+ }
51
+
52
+ function handleItemMouseEnter(index: number, item: MenuItemAction<T>) {
53
+ if (item.menu && item.menu.length > 0) {
54
+ activeSubmenuIndex = index;
55
+ const ref = menuItemRefs[index];
56
+ if (ref) {
57
+ submenuRect = ref.getBoundingClientRect();
58
+ }
59
+ } else {
60
+ activeSubmenuIndex = null;
61
+ }
62
+ }
63
+
64
+ function handleItemMouseLeave() {
65
+ // Keep submenu open when hovering over it
66
+ }
67
+
68
+ function handleKeydown(event: KeyboardEvent, item: MenuItemAction<T>, index: number) {
69
+ if (event.key === 'Enter' || event.key === ' ') {
70
+ event.preventDefault();
71
+ handleItemClick(item, event as unknown as MouseEvent);
72
+ } else if (event.key === 'ArrowRight' && item.menu) {
73
+ event.preventDefault();
74
+ activeSubmenuIndex = index;
75
+ const ref = menuItemRefs[index];
76
+ if (ref) {
77
+ submenuRect = ref.getBoundingClientRect();
78
+ }
79
+ } else if (event.key === 'ArrowLeft' && activeSubmenuIndex !== null) {
80
+ event.preventDefault();
81
+ activeSubmenuIndex = null;
82
+ }
83
+ }
84
+
85
+ // ============================================
86
+ // Computed
87
+ // ============================================
88
+
89
+ function isDisabled(item: MenuItemAction<T>): boolean {
90
+ if (typeof item.disabled === 'function') {
91
+ return item.disabled(context);
92
+ }
93
+ return item.disabled === true;
94
+ }
95
+ </script>
96
+
97
+ <div class="sg-menu {className}" role="menu">
98
+ {#each items as item, index (index)}
99
+ {#if item.separator}
100
+ <div class="sg-menu-separator" role="separator"></div>
101
+ {:else if isActionItem(item)}
102
+ {@const disabled = isDisabled(item)}
103
+ <div
104
+ bind:this={menuItemRefs[index]}
105
+ class="sg-menu-item {item.cssClass ?? ''}"
106
+ class:sg-menu-item-disabled={disabled}
107
+ class:sg-menu-item-has-submenu={item.menu && item.menu.length > 0}
108
+ class:sg-menu-item-active={activeSubmenuIndex === index}
109
+ role="menuitem"
110
+ tabindex={disabled ? -1 : 0}
111
+ aria-disabled={disabled}
112
+ onclick={(e) => handleItemClick(item, e)}
113
+ onmouseenter={() => handleItemMouseEnter(index, item)}
114
+ onmouseleave={handleItemMouseLeave}
115
+ onkeydown={(e) => handleKeydown(e, item, index)}
116
+ >
117
+ {#if item.icon}
118
+ <span class="sg-menu-item-icon">{@html item.icon}</span>
119
+ {/if}
120
+ <span class="sg-menu-item-label">{item.label}</span>
121
+ {#if item.menu && item.menu.length > 0}
122
+ <span class="sg-menu-item-arrow">›</span>
123
+ {/if}
124
+ </div>
125
+
126
+ <!-- Submenu -->
127
+ {#if item.menu && item.menu.length > 0 && activeSubmenuIndex === index && submenuRect}
128
+ <div
129
+ class="sg-submenu"
130
+ role="menu"
131
+ tabindex="-1"
132
+ style="top: {submenuRect.top}px; left: {submenuRect.right}px;"
133
+ onmouseenter={() => (activeSubmenuIndex = index)}
134
+ onmouseleave={() => (activeSubmenuIndex = null)}
135
+ >
136
+ <Menu items={item.menu} {context} />
137
+ </div>
138
+ {/if}
139
+ {/if}
140
+ {/each}
141
+ </div>
142
+
143
+ <style>
144
+ .sg-menu {
145
+ padding: 4px 0;
146
+ min-width: 160px;
147
+ }
148
+
149
+ .sg-menu-item {
150
+ display: flex;
151
+ align-items: center;
152
+ gap: 8px;
153
+ padding: 8px 12px;
154
+ cursor: pointer;
155
+ font-size: 14px;
156
+ color: var(--sg-menu-text, #1e293b);
157
+ transition: background-color 0.1s ease;
158
+ }
159
+
160
+ .sg-menu-item:hover:not(.sg-menu-item-disabled) {
161
+ background: var(--sg-menu-hover-bg, #f1f5f9);
162
+ }
163
+
164
+ .sg-menu-item:focus {
165
+ outline: none;
166
+ background: var(--sg-menu-focus-bg, #e2e8f0);
167
+ }
168
+
169
+ .sg-menu-item-active {
170
+ background: var(--sg-menu-hover-bg, #f1f5f9);
171
+ }
172
+
173
+ .sg-menu-item-disabled {
174
+ opacity: 0.5;
175
+ cursor: not-allowed;
176
+ }
177
+
178
+ .sg-menu-item-icon {
179
+ display: flex;
180
+ align-items: center;
181
+ justify-content: center;
182
+ width: 16px;
183
+ height: 16px;
184
+ flex-shrink: 0;
185
+ }
186
+
187
+ .sg-menu-item-label {
188
+ flex: 1;
189
+ overflow: hidden;
190
+ text-overflow: ellipsis;
191
+ white-space: nowrap;
192
+ }
193
+
194
+ .sg-menu-item-arrow {
195
+ color: var(--sg-menu-arrow, #94a3b8);
196
+ font-size: 16px;
197
+ margin-left: auto;
198
+ }
199
+
200
+ .sg-menu-separator {
201
+ height: 1px;
202
+ background: var(--sg-menu-separator, #e2e8f0);
203
+ margin: 4px 0;
204
+ }
205
+
206
+ .sg-submenu {
207
+ position: fixed;
208
+ z-index: 1001;
209
+ background: var(--sg-popup-bg, #ffffff);
210
+ border: 1px solid var(--sg-popup-border, #e2e8f0);
211
+ border-radius: 6px;
212
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
213
+ min-width: 160px;
214
+ }
215
+ </style>
@@ -0,0 +1,33 @@
1
+ import type { MenuItemDefinition, MenuContext } from '../types.js';
2
+ import Menu from './Menu.svelte';
3
+ declare function $$render<T>(): {
4
+ props: {
5
+ /** Menu items */
6
+ items: MenuItemDefinition<T>[];
7
+ /** Context passed to menu actions */
8
+ context: MenuContext<T>;
9
+ /** CSS class */
10
+ class?: string;
11
+ };
12
+ exports: {};
13
+ bindings: "";
14
+ slots: {};
15
+ events: {};
16
+ };
17
+ declare class __sveltets_Render<T> {
18
+ props(): ReturnType<typeof $$render<T>>['props'];
19
+ events(): ReturnType<typeof $$render<T>>['events'];
20
+ slots(): ReturnType<typeof $$render<T>>['slots'];
21
+ bindings(): "";
22
+ exports(): {};
23
+ }
24
+ interface $$IsomorphicComponent {
25
+ 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']>> & {
26
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
27
+ } & ReturnType<__sveltets_Render<T>['exports']>;
28
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
29
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
30
+ }
31
+ declare const Menu: $$IsomorphicComponent;
32
+ type Menu<T> = InstanceType<typeof Menu<T>>;
33
+ export default Menu;
@@ -0,0 +1,189 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ interface Props {
6
+ /** Whether the popup is visible */
7
+ open: boolean;
8
+ /** Target element to position relative to */
9
+ targetRect: DOMRect | null;
10
+ /** Preferred position relative to target */
11
+ position?: 'bottom' | 'top' | 'left' | 'right' | 'bottom-start' | 'bottom-end';
12
+ /** Close callback */
13
+ onclose?: () => void;
14
+ /** CSS class for the popup */
15
+ class?: string;
16
+ /** Popup content */
17
+ children: Snippet;
18
+ }
19
+
20
+ let {
21
+ open,
22
+ targetRect,
23
+ position = 'bottom-start',
24
+ onclose,
25
+ class: className = '',
26
+ children
27
+ }: Props = $props();
28
+
29
+ let popupRef: HTMLDivElement | undefined = $state();
30
+ let popupStyle = $state('');
31
+
32
+ // ============================================
33
+ // Positioning
34
+ // ============================================
35
+
36
+ function updatePosition() {
37
+ if (!popupRef || !targetRect || !open) return;
38
+
39
+ const popupRect = popupRef.getBoundingClientRect();
40
+ const viewportWidth = window.innerWidth;
41
+ const viewportHeight = window.innerHeight;
42
+ const scrollX = window.scrollX;
43
+ const scrollY = window.scrollY;
44
+
45
+ let top = 0;
46
+ let left = 0;
47
+
48
+ // Calculate base position
49
+ switch (position) {
50
+ case 'bottom':
51
+ top = targetRect.bottom + scrollY;
52
+ left = targetRect.left + scrollX + (targetRect.width - popupRect.width) / 2;
53
+ break;
54
+ case 'bottom-start':
55
+ top = targetRect.bottom + scrollY;
56
+ left = targetRect.left + scrollX;
57
+ break;
58
+ case 'bottom-end':
59
+ top = targetRect.bottom + scrollY;
60
+ left = targetRect.right + scrollX - popupRect.width;
61
+ break;
62
+ case 'top':
63
+ top = targetRect.top + scrollY - popupRect.height;
64
+ left = targetRect.left + scrollX + (targetRect.width - popupRect.width) / 2;
65
+ break;
66
+ case 'left':
67
+ top = targetRect.top + scrollY + (targetRect.height - popupRect.height) / 2;
68
+ left = targetRect.left + scrollX - popupRect.width;
69
+ break;
70
+ case 'right':
71
+ top = targetRect.top + scrollY + (targetRect.height - popupRect.height) / 2;
72
+ left = targetRect.right + scrollX;
73
+ break;
74
+ }
75
+
76
+ // Viewport collision detection - flip if needed
77
+ if (left + popupRect.width > viewportWidth + scrollX) {
78
+ left = viewportWidth + scrollX - popupRect.width - 8;
79
+ }
80
+ if (left < scrollX) {
81
+ left = scrollX + 8;
82
+ }
83
+ if (top + popupRect.height > viewportHeight + scrollY) {
84
+ // Flip to top
85
+ top = targetRect.top + scrollY - popupRect.height;
86
+ }
87
+ if (top < scrollY) {
88
+ top = scrollY + 8;
89
+ }
90
+
91
+ popupStyle = `top: ${top}px; left: ${left}px;`;
92
+ }
93
+
94
+ // ============================================
95
+ // Effects
96
+ // ============================================
97
+
98
+ $effect(() => {
99
+ if (open && targetRect && popupRef) {
100
+ // Use requestAnimationFrame to ensure DOM is updated
101
+ requestAnimationFrame(updatePosition);
102
+ }
103
+ });
104
+
105
+ // ============================================
106
+ // Event Handlers
107
+ // ============================================
108
+
109
+ function handleClickOutside(event: MouseEvent) {
110
+ if (!open || !popupRef) return;
111
+
112
+ const target = event.target as Node;
113
+ if (!popupRef.contains(target)) {
114
+ onclose?.();
115
+ }
116
+ }
117
+
118
+ function handleKeydown(event: KeyboardEvent) {
119
+ if (!open) return;
120
+
121
+ if (event.key === 'Escape') {
122
+ event.preventDefault();
123
+ onclose?.();
124
+ }
125
+ }
126
+
127
+ function handleScroll() {
128
+ if (open) {
129
+ onclose?.();
130
+ }
131
+ }
132
+
133
+ // ============================================
134
+ // Lifecycle
135
+ // ============================================
136
+
137
+ onMount(() => {
138
+ // Delay to avoid immediate close from the click that opened it
139
+ setTimeout(() => {
140
+ document.addEventListener('mousedown', handleClickOutside);
141
+ }, 0);
142
+ document.addEventListener('keydown', handleKeydown);
143
+ window.addEventListener('scroll', handleScroll, true);
144
+ });
145
+
146
+ onDestroy(() => {
147
+ document.removeEventListener('mousedown', handleClickOutside);
148
+ document.removeEventListener('keydown', handleKeydown);
149
+ window.removeEventListener('scroll', handleScroll, true);
150
+ });
151
+ </script>
152
+
153
+ {#if open}
154
+ <div
155
+ bind:this={popupRef}
156
+ class="sg-popup {className}"
157
+ style={popupStyle}
158
+ role="dialog"
159
+ aria-modal="true"
160
+ >
161
+ {@render children()}
162
+ </div>
163
+ {/if}
164
+
165
+ <style>
166
+ .sg-popup {
167
+ position: fixed;
168
+ z-index: 1000;
169
+ background: var(--sg-popup-bg, #ffffff);
170
+ border: 1px solid var(--sg-popup-border, #e2e8f0);
171
+ border-radius: 6px;
172
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
173
+ min-width: 120px;
174
+ max-width: 320px;
175
+ overflow: hidden;
176
+ animation: sg-popup-fade-in 0.15s ease-out;
177
+ }
178
+
179
+ @keyframes sg-popup-fade-in {
180
+ from {
181
+ opacity: 0;
182
+ transform: translateY(-4px);
183
+ }
184
+ to {
185
+ opacity: 1;
186
+ transform: translateY(0);
187
+ }
188
+ }
189
+ </style>
@@ -0,0 +1,18 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ /** Whether the popup is visible */
4
+ open: boolean;
5
+ /** Target element to position relative to */
6
+ targetRect: DOMRect | null;
7
+ /** Preferred position relative to target */
8
+ position?: 'bottom' | 'top' | 'left' | 'right' | 'bottom-start' | 'bottom-end';
9
+ /** Close callback */
10
+ onclose?: () => void;
11
+ /** CSS class for the popup */
12
+ class?: string;
13
+ /** Popup content */
14
+ children: Snippet;
15
+ }
16
+ declare const Popup: import("svelte").Component<Props, {}, "">;
17
+ type Popup = ReturnType<typeof Popup>;
18
+ export default Popup;
@@ -0,0 +1,115 @@
1
+ <script lang="ts" generics="T">
2
+ import { getContext } from 'svelte';
3
+ import type { Snippet } from 'svelte';
4
+ import type { ColumnDefinition, CellContext, GridEvents } from '../types.js';
5
+ import { GRID_CONTEXT_KEY, type GridStateManager } from '../state/gridState.svelte.js';
6
+ import Cell from './Cell.svelte';
7
+
8
+ interface Props {
9
+ row: T;
10
+ columns: ColumnDefinition<T>[];
11
+ rowIndex: number;
12
+ rowHeight: number;
13
+ onrowclick?: GridEvents<T>['rowclick'];
14
+ onrowdblclick?: GridEvents<T>['rowdblclick'];
15
+ oncellclick?: GridEvents<T>['cellclick'];
16
+ cell?: Snippet<[CellContext<T>]>;
17
+ onrowcontextmenu?: (row: T, rowIndex: number, event: MouseEvent) => void;
18
+ }
19
+
20
+ let {
21
+ row,
22
+ columns,
23
+ rowIndex,
24
+ rowHeight,
25
+ onrowclick,
26
+ onrowdblclick,
27
+ oncellclick,
28
+ cell,
29
+ onrowcontextmenu
30
+ }: Props = $props();
31
+
32
+ // Get grid state for column widths
33
+ const gridState = getContext<GridStateManager<T>>(GRID_CONTEXT_KEY);
34
+
35
+ // ============================================
36
+ // Event Handlers
37
+ // ============================================
38
+
39
+ function handleClick(event: MouseEvent) {
40
+ onrowclick?.(row, rowIndex, event);
41
+ }
42
+
43
+ function handleDblClick(event: MouseEvent) {
44
+ onrowdblclick?.(row, rowIndex, event);
45
+ }
46
+
47
+ function handleKeydown(event: KeyboardEvent) {
48
+ if (event.key === 'Enter') {
49
+ onrowclick?.(row, rowIndex, event as unknown as MouseEvent);
50
+ }
51
+ }
52
+
53
+ function handleContextMenu(event: MouseEvent) {
54
+ onrowcontextmenu?.(row, rowIndex, event);
55
+ }
56
+ </script>
57
+
58
+ <div
59
+ class="sg-row"
60
+ role="row"
61
+ aria-rowindex={rowIndex + 1}
62
+ tabindex="0"
63
+ style="height: {rowHeight}px;"
64
+ onclick={handleClick}
65
+ ondblclick={handleDblClick}
66
+ onkeydown={handleKeydown}
67
+ oncontextmenu={onrowcontextmenu ? handleContextMenu : undefined}
68
+ >
69
+ {#each columns as column, columnIndex (column.field)}
70
+ {@const frozenLeft = column.frozen === true || column.frozen === 'left'}
71
+ {@const frozenRight = column.frozen === 'right'}
72
+ {@const frozenPosition = frozenLeft
73
+ ? { side: 'left' as const, offset: gridState?.getFrozenLeftPosition(column.field) ?? 0 }
74
+ : frozenRight
75
+ ? { side: 'right' as const, offset: gridState?.getFrozenRightPosition(column.field) ?? 0 }
76
+ : undefined}
77
+ <Cell
78
+ value={(row as Record<string, unknown>)[column.field]}
79
+ {row}
80
+ {column}
81
+ {rowIndex}
82
+ {columnIndex}
83
+ columnWidth={gridState?.getColumnWidth(column.field)}
84
+ {oncellclick}
85
+ {cell}
86
+ {frozenPosition}
87
+ />
88
+ {/each}
89
+ </div>
90
+
91
+ <style>
92
+ .sg-row {
93
+ display: flex;
94
+ min-width: 100%;
95
+ background: var(--sg-row-bg, #ffffff);
96
+ box-sizing: border-box;
97
+ transition: background-color var(--sg-transition-fast, 0.1s ease);
98
+ }
99
+
100
+ .sg-row:focus {
101
+ outline: 2px solid var(--sg-primary-color, #3b82f6);
102
+ outline-offset: -2px;
103
+ z-index: 1;
104
+ }
105
+
106
+ /* Striped rows (applied via parent) */
107
+ :global(.sg-striped) .sg-row:nth-child(even) {
108
+ background: var(--sg-row-alt-bg, #f8fafc);
109
+ }
110
+
111
+ /* Hover state (applied via parent) */
112
+ :global(.sg-row-hover) .sg-row:hover {
113
+ background: var(--sg-row-hover-bg, #f1f5f9);
114
+ }
115
+ </style>
@@ -0,0 +1,36 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ColumnDefinition, CellContext, GridEvents } from '../types.js';
3
+ declare function $$render<T>(): {
4
+ props: {
5
+ row: T;
6
+ columns: ColumnDefinition<T>[];
7
+ rowIndex: number;
8
+ rowHeight: number;
9
+ onrowclick?: GridEvents<T>["rowclick"];
10
+ onrowdblclick?: GridEvents<T>["rowdblclick"];
11
+ oncellclick?: GridEvents<T>["cellclick"];
12
+ cell?: Snippet<[CellContext<T>]>;
13
+ onrowcontextmenu?: (row: T, rowIndex: number, event: MouseEvent) => void;
14
+ };
15
+ exports: {};
16
+ bindings: "";
17
+ slots: {};
18
+ events: {};
19
+ };
20
+ declare class __sveltets_Render<T> {
21
+ props(): ReturnType<typeof $$render<T>>['props'];
22
+ events(): ReturnType<typeof $$render<T>>['events'];
23
+ slots(): ReturnType<typeof $$render<T>>['slots'];
24
+ bindings(): "";
25
+ exports(): {};
26
+ }
27
+ interface $$IsomorphicComponent {
28
+ 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']>> & {
29
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
30
+ } & ReturnType<__sveltets_Render<T>['exports']>;
31
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
32
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
33
+ }
34
+ declare const Row: $$IsomorphicComponent;
35
+ type Row<T> = InstanceType<typeof Row<T>>;
36
+ export default Row;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * svelte-grid - A Svelte 5 table/grid library
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export { default as Grid } from './components/Grid.svelte';
7
+ export { default as GridHeader } from './components/GridHeader.svelte';
8
+ export { default as GridBody } from './components/GridBody.svelte';
9
+ export { default as HeaderCell } from './components/HeaderCell.svelte';
10
+ export { default as Row } from './components/Row.svelte';
11
+ export { default as Cell } from './components/Cell.svelte';
12
+ export { default as Popup } from './components/Popup.svelte';
13
+ export { default as Menu } from './components/Menu.svelte';
14
+ export { default as GroupHeader } from './components/GroupHeader.svelte';
15
+ export { createGridState, GridStateManager, GRID_CONTEXT_KEY } from './state/gridState.svelte.js';
16
+ export { themes, defaultTheme, tailwindBlue, tailwindEmerald, tailwindRose, tailwindAmber, tailwindSlate, darkTheme, themeToStyle, createTheme } from './themes.js';
17
+ export type { GridTheme, ThemeName } from './themes.js';
18
+ export type { RowData, ColumnDefinition, FormatterType, FormatterFunction, CellContext, RowContext, GridOptions, GridState, TablePlugin, PluginContext, PluginInstance, GridEvents, GridSnippets, MenuItemDefinition, MenuItemAction, MenuItemSeparator, MenuAction, MenuContext, PopupContent, PopupContext, GroupBy, GroupConfig, GroupInfo, GroupAggregates, DisplayRow } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * svelte-grid - A Svelte 5 table/grid library
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ // Main Grid Component
7
+ export { default as Grid } from './components/Grid.svelte';
8
+ // Individual components (for advanced use cases)
9
+ export { default as GridHeader } from './components/GridHeader.svelte';
10
+ export { default as GridBody } from './components/GridBody.svelte';
11
+ export { default as HeaderCell } from './components/HeaderCell.svelte';
12
+ export { default as Row } from './components/Row.svelte';
13
+ export { default as Cell } from './components/Cell.svelte';
14
+ export { default as Popup } from './components/Popup.svelte';
15
+ export { default as Menu } from './components/Menu.svelte';
16
+ export { default as GroupHeader } from './components/GroupHeader.svelte';
17
+ // State Management
18
+ export { createGridState, GridStateManager, GRID_CONTEXT_KEY } from './state/gridState.svelte.js';
19
+ // Theming
20
+ export { themes, defaultTheme, tailwindBlue, tailwindEmerald, tailwindRose, tailwindAmber, tailwindSlate, darkTheme, themeToStyle, createTheme } from './themes.js';