@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.
- package/dist/components/Cell.svelte +249 -0
- package/dist/components/Cell.svelte.d.ts +39 -0
- package/dist/components/Grid.svelte +504 -0
- package/dist/components/Grid.svelte.d.ts +80 -0
- package/dist/components/GridBody.svelte +194 -0
- package/dist/components/GridBody.svelte.d.ts +49 -0
- package/dist/components/GridHeader.svelte +99 -0
- package/dist/components/GridHeader.svelte.d.ts +31 -0
- package/dist/components/GroupHeader.svelte +192 -0
- package/dist/components/GroupHeader.svelte.d.ts +35 -0
- package/dist/components/HeaderCell.svelte +623 -0
- package/dist/components/HeaderCell.svelte.d.ts +40 -0
- package/dist/components/Menu.svelte +215 -0
- package/dist/components/Menu.svelte.d.ts +33 -0
- package/dist/components/Popup.svelte +189 -0
- package/dist/components/Popup.svelte.d.ts +18 -0
- package/dist/components/Row.svelte +115 -0
- package/dist/components/Row.svelte.d.ts +36 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +20 -0
- package/dist/state/gridState.svelte.d.ts +299 -0
- package/dist/state/gridState.svelte.js +1025 -0
- package/dist/themes.d.ts +61 -0
- package/dist/themes.js +192 -0
- package/dist/types.d.ts +291 -0
- package/dist/types.js +4 -0
- package/package.json +66 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ColumnDefinition, CellContext, GridEvents } from '../types.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
value: unknown;
|
|
7
|
+
row: T;
|
|
8
|
+
column: ColumnDefinition<T>;
|
|
9
|
+
rowIndex: number;
|
|
10
|
+
columnIndex: number;
|
|
11
|
+
columnWidth?: number;
|
|
12
|
+
oncellclick?: GridEvents<T>['cellclick'];
|
|
13
|
+
cell?: Snippet<[CellContext<T>]>;
|
|
14
|
+
frozenPosition?: { side: 'left' | 'right'; offset: number };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let { value, row, column, rowIndex, columnIndex, columnWidth, oncellclick, cell, frozenPosition }: Props =
|
|
18
|
+
$props();
|
|
19
|
+
|
|
20
|
+
// ============================================
|
|
21
|
+
// Cell Context for custom renderers
|
|
22
|
+
// ============================================
|
|
23
|
+
|
|
24
|
+
const cellContext = $derived<CellContext<T>>({
|
|
25
|
+
value,
|
|
26
|
+
row,
|
|
27
|
+
column,
|
|
28
|
+
rowIndex,
|
|
29
|
+
columnIndex
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ============================================
|
|
33
|
+
// Computed Styles
|
|
34
|
+
// ============================================
|
|
35
|
+
|
|
36
|
+
const cellStyle = $derived.by(() => {
|
|
37
|
+
const styles: string[] = [];
|
|
38
|
+
|
|
39
|
+
// Use columnWidth (from resize) if available, else column.width
|
|
40
|
+
const width = columnWidth ?? column.width;
|
|
41
|
+
|
|
42
|
+
if (width) {
|
|
43
|
+
const w = typeof width === 'number' ? `${width}px` : width;
|
|
44
|
+
styles.push(`width: ${w}`);
|
|
45
|
+
styles.push(`min-width: ${w}`);
|
|
46
|
+
} else {
|
|
47
|
+
styles.push('flex: 1');
|
|
48
|
+
styles.push('min-width: 100px');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (column.minWidth && !columnWidth) {
|
|
52
|
+
styles.push(`min-width: ${column.minWidth}px`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (column.maxWidth) {
|
|
56
|
+
styles.push(`max-width: ${column.maxWidth}px`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Frozen column positioning
|
|
60
|
+
if (frozenPosition) {
|
|
61
|
+
styles.push('position: sticky');
|
|
62
|
+
styles.push(`${frozenPosition.side}: ${frozenPosition.offset}px`);
|
|
63
|
+
styles.push('z-index: 1');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return styles.join('; ');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const isFrozen = $derived(!!frozenPosition);
|
|
70
|
+
|
|
71
|
+
const alignClass = $derived.by(() => {
|
|
72
|
+
if (column.hAlign === 'center') return 'sg-align-center';
|
|
73
|
+
if (column.hAlign === 'right') return 'sg-align-right';
|
|
74
|
+
return 'sg-align-left';
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const vAlignClass = $derived.by(() => {
|
|
78
|
+
if (column.vAlign === 'top') return 'sg-valign-top';
|
|
79
|
+
if (column.vAlign === 'bottom') return 'sg-valign-bottom';
|
|
80
|
+
return 'sg-valign-middle';
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// ============================================
|
|
84
|
+
// Formatting
|
|
85
|
+
// ============================================
|
|
86
|
+
|
|
87
|
+
const formattedValue = $derived.by(() => {
|
|
88
|
+
if (value === null || value === undefined) {
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Custom formatter function
|
|
93
|
+
if (typeof column.formatter === 'function') {
|
|
94
|
+
return column.formatter(cellContext);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Built-in formatters
|
|
98
|
+
switch (column.formatter) {
|
|
99
|
+
case 'number':
|
|
100
|
+
return typeof value === 'number' ? value.toLocaleString() : String(value);
|
|
101
|
+
|
|
102
|
+
case 'money':
|
|
103
|
+
return typeof value === 'number'
|
|
104
|
+
? value.toLocaleString(undefined, { style: 'currency', currency: 'USD' })
|
|
105
|
+
: String(value);
|
|
106
|
+
|
|
107
|
+
case 'date':
|
|
108
|
+
if (value instanceof Date) {
|
|
109
|
+
return value.toLocaleDateString();
|
|
110
|
+
}
|
|
111
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
112
|
+
return new Date(value).toLocaleDateString();
|
|
113
|
+
}
|
|
114
|
+
return String(value);
|
|
115
|
+
|
|
116
|
+
case 'datetime':
|
|
117
|
+
if (value instanceof Date) {
|
|
118
|
+
return value.toLocaleString();
|
|
119
|
+
}
|
|
120
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
121
|
+
return new Date(value).toLocaleString();
|
|
122
|
+
}
|
|
123
|
+
return String(value);
|
|
124
|
+
|
|
125
|
+
case 'boolean':
|
|
126
|
+
return value ? '✓' : '✗';
|
|
127
|
+
|
|
128
|
+
case 'text':
|
|
129
|
+
default:
|
|
130
|
+
return String(value);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// ============================================
|
|
135
|
+
// Tooltip
|
|
136
|
+
// ============================================
|
|
137
|
+
|
|
138
|
+
const tooltipText = $derived.by(() => {
|
|
139
|
+
if (!column.tooltip) return undefined;
|
|
140
|
+
|
|
141
|
+
if (typeof column.tooltip === 'function') {
|
|
142
|
+
return column.tooltip(cellContext);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return column.tooltip;
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// ============================================
|
|
149
|
+
// Event Handlers
|
|
150
|
+
// ============================================
|
|
151
|
+
|
|
152
|
+
function handleClick(event: MouseEvent) {
|
|
153
|
+
event.stopPropagation(); // Prevent row click
|
|
154
|
+
oncellclick?.(cellContext, event);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
158
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
159
|
+
event.preventDefault();
|
|
160
|
+
oncellclick?.(cellContext, event as unknown as MouseEvent);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
</script>
|
|
164
|
+
|
|
165
|
+
<div
|
|
166
|
+
class="sg-cell {alignClass} {vAlignClass} {column.cssClass ?? ''}"
|
|
167
|
+
class:sg-frozen={isFrozen}
|
|
168
|
+
class:sg-frozen-left={frozenPosition?.side === 'left'}
|
|
169
|
+
class:sg-frozen-right={frozenPosition?.side === 'right'}
|
|
170
|
+
style={cellStyle}
|
|
171
|
+
role="gridcell"
|
|
172
|
+
aria-colindex={columnIndex + 1}
|
|
173
|
+
tabindex="-1"
|
|
174
|
+
title={tooltipText}
|
|
175
|
+
onclick={handleClick}
|
|
176
|
+
onkeydown={handleKeydown}
|
|
177
|
+
>
|
|
178
|
+
{#if cell}
|
|
179
|
+
{@render cell(cellContext)}
|
|
180
|
+
{:else}
|
|
181
|
+
<span class="sg-cell-content">
|
|
182
|
+
{formattedValue}
|
|
183
|
+
</span>
|
|
184
|
+
{/if}
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<style>
|
|
188
|
+
.sg-cell {
|
|
189
|
+
display: flex;
|
|
190
|
+
padding: var(--sg-cell-padding-y) var(--sg-cell-padding-x);
|
|
191
|
+
overflow: hidden;
|
|
192
|
+
box-sizing: border-box;
|
|
193
|
+
border-bottom: 1px solid var(--sg-border-color, #f1f5f9);
|
|
194
|
+
font-feature-settings: 'tnum' 1; /* Tabular numbers for data */
|
|
195
|
+
transition: background-color var(--sg-transition-fast, 0.1s ease);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.sg-cell-content {
|
|
199
|
+
overflow: hidden;
|
|
200
|
+
text-overflow: ellipsis;
|
|
201
|
+
white-space: nowrap;
|
|
202
|
+
width: 100%;
|
|
203
|
+
color: #334155;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* Horizontal Alignment */
|
|
207
|
+
.sg-align-left {
|
|
208
|
+
justify-content: flex-start;
|
|
209
|
+
text-align: left;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.sg-align-center {
|
|
213
|
+
justify-content: center;
|
|
214
|
+
text-align: center;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.sg-align-right {
|
|
218
|
+
justify-content: flex-end;
|
|
219
|
+
text-align: right;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* Vertical Alignment */
|
|
223
|
+
.sg-valign-top {
|
|
224
|
+
align-items: flex-start;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.sg-valign-middle {
|
|
228
|
+
align-items: center;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.sg-valign-bottom {
|
|
232
|
+
align-items: flex-end;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Frozen column styles */
|
|
236
|
+
.sg-frozen {
|
|
237
|
+
background: inherit;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.sg-frozen-left {
|
|
241
|
+
border-right: 2px solid var(--sg-frozen-border-color, #cbd5e1);
|
|
242
|
+
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.sg-frozen-right {
|
|
246
|
+
border-left: 2px solid var(--sg-frozen-border-color, #cbd5e1);
|
|
247
|
+
box-shadow: -2px 0 4px rgba(0, 0, 0, 0.05);
|
|
248
|
+
}
|
|
249
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ColumnDefinition, CellContext, GridEvents } from '../types.js';
|
|
3
|
+
declare function $$render<T>(): {
|
|
4
|
+
props: {
|
|
5
|
+
value: unknown;
|
|
6
|
+
row: T;
|
|
7
|
+
column: ColumnDefinition<T>;
|
|
8
|
+
rowIndex: number;
|
|
9
|
+
columnIndex: number;
|
|
10
|
+
columnWidth?: number;
|
|
11
|
+
oncellclick?: GridEvents<T>["cellclick"];
|
|
12
|
+
cell?: Snippet<[CellContext<T>]>;
|
|
13
|
+
frozenPosition?: {
|
|
14
|
+
side: "left" | "right";
|
|
15
|
+
offset: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
exports: {};
|
|
19
|
+
bindings: "";
|
|
20
|
+
slots: {};
|
|
21
|
+
events: {};
|
|
22
|
+
};
|
|
23
|
+
declare class __sveltets_Render<T> {
|
|
24
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
25
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
26
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
27
|
+
bindings(): "";
|
|
28
|
+
exports(): {};
|
|
29
|
+
}
|
|
30
|
+
interface $$IsomorphicComponent {
|
|
31
|
+
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']>> & {
|
|
32
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
33
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
34
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
35
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
36
|
+
}
|
|
37
|
+
declare const Cell: $$IsomorphicComponent;
|
|
38
|
+
type Cell<T> = InstanceType<typeof Cell<T>>;
|
|
39
|
+
export default Cell;
|