@shotleybuilder/svelte-gridlite-kit 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.
Files changed (43) hide show
  1. package/README.md +260 -0
  2. package/dist/GridLite.svelte +1361 -0
  3. package/dist/GridLite.svelte.d.ts +42 -0
  4. package/dist/components/CellContextMenu.svelte +209 -0
  5. package/dist/components/CellContextMenu.svelte.d.ts +28 -0
  6. package/dist/components/ColumnMenu.svelte +234 -0
  7. package/dist/components/ColumnMenu.svelte.d.ts +29 -0
  8. package/dist/components/ColumnPicker.svelte +403 -0
  9. package/dist/components/ColumnPicker.svelte.d.ts +29 -0
  10. package/dist/components/FilterBar.svelte +390 -0
  11. package/dist/components/FilterBar.svelte.d.ts +38 -0
  12. package/dist/components/FilterCondition.svelte +643 -0
  13. package/dist/components/FilterCondition.svelte.d.ts +35 -0
  14. package/dist/components/GroupBar.svelte +463 -0
  15. package/dist/components/GroupBar.svelte.d.ts +33 -0
  16. package/dist/components/RowDetailModal.svelte +213 -0
  17. package/dist/components/RowDetailModal.svelte.d.ts +25 -0
  18. package/dist/components/SortBar.svelte +232 -0
  19. package/dist/components/SortBar.svelte.d.ts +30 -0
  20. package/dist/components/SortCondition.svelte +129 -0
  21. package/dist/components/SortCondition.svelte.d.ts +30 -0
  22. package/dist/index.d.ts +23 -0
  23. package/dist/index.js +29 -0
  24. package/dist/query/builder.d.ts +160 -0
  25. package/dist/query/builder.js +432 -0
  26. package/dist/query/live.d.ts +50 -0
  27. package/dist/query/live.js +118 -0
  28. package/dist/query/schema.d.ts +30 -0
  29. package/dist/query/schema.js +75 -0
  30. package/dist/state/migrations.d.ts +29 -0
  31. package/dist/state/migrations.js +113 -0
  32. package/dist/state/views.d.ts +54 -0
  33. package/dist/state/views.js +130 -0
  34. package/dist/styles/gridlite.css +966 -0
  35. package/dist/types.d.ts +164 -0
  36. package/dist/types.js +2 -0
  37. package/dist/utils/filters.d.ts +14 -0
  38. package/dist/utils/filters.js +49 -0
  39. package/dist/utils/formatters.d.ts +16 -0
  40. package/dist/utils/formatters.js +39 -0
  41. package/dist/utils/fuzzy.d.ts +47 -0
  42. package/dist/utils/fuzzy.js +142 -0
  43. package/package.json +76 -0
@@ -0,0 +1,164 @@
1
+ import type { PGlite } from "@electric-sql/pglite";
2
+ export interface GridLiteProps {
3
+ /** PGLite database instance */
4
+ db: PGlite;
5
+ /** Table name to query (mutually exclusive with `query`) */
6
+ table?: string;
7
+ /** Raw SQL query (mutually exclusive with `table`) */
8
+ query?: string;
9
+ /** Grid configuration */
10
+ config?: GridConfig;
11
+ /** Feature flags */
12
+ features?: GridFeatures;
13
+ /** Styling */
14
+ classNames?: Partial<ClassNameMap>;
15
+ rowHeight?: RowHeight;
16
+ columnSpacing?: ColumnSpacing;
17
+ /** Callbacks */
18
+ onRowClick?: (row: Record<string, unknown>) => void;
19
+ onStateChange?: (state: GridState) => void;
20
+ }
21
+ export interface GridFeatures {
22
+ columnVisibility?: boolean;
23
+ columnResizing?: boolean;
24
+ columnReordering?: boolean;
25
+ filtering?: boolean;
26
+ sorting?: boolean;
27
+ sortingMode?: "header" | "control";
28
+ pagination?: boolean;
29
+ grouping?: boolean;
30
+ globalSearch?: boolean;
31
+ rowDetail?: boolean;
32
+ rowDetailMode?: "modal" | "drawer" | "inline";
33
+ }
34
+ export interface GridConfig {
35
+ /** Unique identifier for this grid instance (used for state persistence) */
36
+ id: string;
37
+ /** Column configuration overrides */
38
+ columns?: ColumnConfig[];
39
+ /** Default visible columns (by column name) */
40
+ defaultVisibleColumns?: string[];
41
+ /** Default column order (by column name) */
42
+ defaultColumnOrder?: string[];
43
+ /** Default column sizing */
44
+ defaultColumnSizing?: Record<string, number>;
45
+ /** Default filters applied on load */
46
+ defaultFilters?: FilterCondition[];
47
+ /** Default filter logic */
48
+ filterLogic?: FilterLogic;
49
+ /** Default sorting applied on load */
50
+ defaultSorting?: SortConfig[];
51
+ /** Default grouping applied on load */
52
+ defaultGrouping?: GroupConfig[];
53
+ /** Pagination config */
54
+ pagination?: {
55
+ pageSize: number;
56
+ pageSizeOptions?: number[];
57
+ };
58
+ /** Saved view presets */
59
+ presets?: ViewPreset[];
60
+ }
61
+ export interface ColumnConfig {
62
+ /** Column name (must match database column) */
63
+ name: string;
64
+ /** Display label (defaults to column name) */
65
+ label?: string;
66
+ /** Data type override (auto-detected from schema if not set) */
67
+ dataType?: ColumnDataType;
68
+ /** Options for 'select' type columns */
69
+ selectOptions?: {
70
+ value: string;
71
+ label: string;
72
+ }[];
73
+ /** Custom cell formatter */
74
+ format?: (value: unknown) => string;
75
+ /** Whether column is visible by default */
76
+ visible?: boolean;
77
+ /** Column width in pixels */
78
+ width?: number;
79
+ /** Minimum column width */
80
+ minWidth?: number;
81
+ /** Maximum column width */
82
+ maxWidth?: number;
83
+ }
84
+ /** Column data type — drives filter operator selection and value input rendering */
85
+ export type ColumnDataType = "text" | "number" | "date" | "boolean" | "select";
86
+ /** Schema-introspected column metadata (internal, from information_schema) */
87
+ export interface ColumnMetadata {
88
+ name: string;
89
+ dataType: ColumnDataType;
90
+ postgresType: string;
91
+ nullable: boolean;
92
+ hasDefault: boolean;
93
+ }
94
+ export interface FilterCondition {
95
+ id: string;
96
+ field: string;
97
+ operator: FilterOperator;
98
+ value: unknown;
99
+ }
100
+ export type FilterOperator = "equals" | "not_equals" | "contains" | "not_contains" | "starts_with" | "ends_with" | "is_empty" | "is_not_empty" | "greater_than" | "less_than" | "greater_or_equal" | "less_or_equal" | "is_before" | "is_after";
101
+ export type FilterLogic = "and" | "or";
102
+ export interface SortConfig {
103
+ column: string;
104
+ direction: "asc" | "desc";
105
+ }
106
+ export interface GroupConfig {
107
+ column: string;
108
+ aggregations?: AggregationConfig[];
109
+ }
110
+ export interface AggregationConfig {
111
+ column: string;
112
+ function: AggregateFunction;
113
+ alias?: string;
114
+ }
115
+ export type AggregateFunction = "count" | "sum" | "avg" | "min" | "max";
116
+ export interface ViewPreset {
117
+ id: string;
118
+ name: string;
119
+ description?: string;
120
+ filters?: FilterCondition[];
121
+ filterLogic?: FilterLogic;
122
+ sorting?: SortConfig[];
123
+ grouping?: GroupConfig[];
124
+ columnVisibility?: Record<string, boolean>;
125
+ columnOrder?: string[];
126
+ }
127
+ export interface GridState {
128
+ columnVisibility: Record<string, boolean>;
129
+ columnOrder: string[];
130
+ columnSizing: Record<string, number>;
131
+ filters: FilterCondition[];
132
+ filterLogic: FilterLogic;
133
+ sorting: SortConfig[];
134
+ grouping: GroupConfig[];
135
+ globalFilter: string;
136
+ pagination: {
137
+ page: number;
138
+ pageSize: number;
139
+ totalRows: number;
140
+ totalPages: number;
141
+ };
142
+ }
143
+ export type RowHeight = "short" | "medium" | "tall" | "extra_tall";
144
+ export type ColumnSpacing = "narrow" | "normal" | "wide";
145
+ export type ToolbarLayout = "airtable" | "excel" | "shadcn" | "aggrid";
146
+ export interface ClassNameMap {
147
+ container: string;
148
+ table: string;
149
+ thead: string;
150
+ tbody: string;
151
+ tfoot: string;
152
+ tr: string;
153
+ th: string;
154
+ td: string;
155
+ pagination: string;
156
+ filterBar: string;
157
+ sortBar: string;
158
+ groupBar: string;
159
+ }
160
+ /** Parameterized SQL query — never construct SQL by string concatenation */
161
+ export interface ParameterizedQuery {
162
+ sql: string;
163
+ params: unknown[];
164
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ // TypeScript types for @shotleybuilder/svelte-gridlite-kit
2
+ export {};
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Filter operator utilities
3
+ *
4
+ * Maps ColumnDataType to available filter operators for UI rendering.
5
+ */
6
+ import type { FilterOperator, ColumnDataType } from '../types.js';
7
+ export interface OperatorOption {
8
+ value: FilterOperator;
9
+ label: string;
10
+ }
11
+ /**
12
+ * Get operators available for a specific data type.
13
+ */
14
+ export declare function getOperatorsForType(dataType?: ColumnDataType): OperatorOption[];
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Filter operator utilities
3
+ *
4
+ * Maps ColumnDataType to available filter operators for UI rendering.
5
+ */
6
+ const ALL_OPERATORS = [
7
+ { value: 'equals', label: 'equals' },
8
+ { value: 'not_equals', label: 'does not equal' },
9
+ { value: 'contains', label: 'contains' },
10
+ { value: 'not_contains', label: 'does not contain' },
11
+ { value: 'starts_with', label: 'starts with' },
12
+ { value: 'ends_with', label: 'ends with' },
13
+ { value: 'is_empty', label: 'is empty' },
14
+ { value: 'is_not_empty', label: 'is not empty' },
15
+ { value: 'greater_than', label: '>' },
16
+ { value: 'less_than', label: '<' },
17
+ { value: 'greater_or_equal', label: '>=' },
18
+ { value: 'less_or_equal', label: '<=' },
19
+ { value: 'is_before', label: 'is before' },
20
+ { value: 'is_after', label: 'is after' }
21
+ ];
22
+ /**
23
+ * Get operators available for a specific data type.
24
+ */
25
+ export function getOperatorsForType(dataType = 'text') {
26
+ switch (dataType) {
27
+ case 'text':
28
+ return ALL_OPERATORS.filter((op) => [
29
+ 'equals', 'not_equals', 'contains', 'not_contains',
30
+ 'starts_with', 'ends_with', 'is_empty', 'is_not_empty'
31
+ ].includes(op.value));
32
+ case 'number':
33
+ return ALL_OPERATORS.filter((op) => [
34
+ 'equals', 'not_equals', 'greater_than', 'less_than',
35
+ 'greater_or_equal', 'less_or_equal', 'is_empty', 'is_not_empty'
36
+ ].includes(op.value));
37
+ case 'date':
38
+ return ALL_OPERATORS.filter((op) => ['equals', 'not_equals', 'is_before', 'is_after', 'is_empty', 'is_not_empty'].includes(op.value));
39
+ case 'boolean':
40
+ return ALL_OPERATORS.filter((op) => ['equals', 'is_empty', 'is_not_empty'].includes(op.value));
41
+ case 'select':
42
+ return ALL_OPERATORS.filter((op) => ['equals', 'not_equals', 'is_empty', 'is_not_empty'].includes(op.value));
43
+ default:
44
+ return ALL_OPERATORS.filter((op) => [
45
+ 'equals', 'not_equals', 'contains', 'not_contains',
46
+ 'starts_with', 'ends_with', 'is_empty', 'is_not_empty'
47
+ ].includes(op.value));
48
+ }
49
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Format date string to localized format
3
+ */
4
+ export declare function formatDate(dateStr: string | Date, locale?: string): string;
5
+ /**
6
+ * Format number as currency
7
+ */
8
+ export declare function formatCurrency(value: number, currency?: string, locale?: string): string;
9
+ /**
10
+ * Format number with locale-specific separators
11
+ */
12
+ export declare function formatNumber(value: number, locale?: string): string;
13
+ /**
14
+ * Format number as percentage
15
+ */
16
+ export declare function formatPercent(value: number, decimals?: number, locale?: string): string;
@@ -0,0 +1,39 @@
1
+ // Cell formatting utilities
2
+ /**
3
+ * Format date string to localized format
4
+ */
5
+ export function formatDate(dateStr, locale = 'en-GB') {
6
+ if (!dateStr)
7
+ return '-';
8
+ const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr;
9
+ return date.toLocaleDateString(locale, {
10
+ day: '2-digit',
11
+ month: 'short',
12
+ year: 'numeric'
13
+ });
14
+ }
15
+ /**
16
+ * Format number as currency
17
+ */
18
+ export function formatCurrency(value, currency = 'GBP', locale = 'en-GB') {
19
+ return new Intl.NumberFormat(locale, {
20
+ style: 'currency',
21
+ currency
22
+ }).format(value);
23
+ }
24
+ /**
25
+ * Format number with locale-specific separators
26
+ */
27
+ export function formatNumber(value, locale = 'en-GB') {
28
+ return new Intl.NumberFormat(locale).format(value);
29
+ }
30
+ /**
31
+ * Format number as percentage
32
+ */
33
+ export function formatPercent(value, decimals = 1, locale = 'en-GB') {
34
+ return new Intl.NumberFormat(locale, {
35
+ style: 'percent',
36
+ minimumFractionDigits: decimals,
37
+ maximumFractionDigits: decimals
38
+ }).format(value / 100);
39
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Fuzzy search utilities for column/field picker
3
+ */
4
+ export interface FuzzyMatch {
5
+ /** The original string that was matched */
6
+ text: string;
7
+ /** The match score (higher = better match) */
8
+ score: number;
9
+ /** Indices of characters that matched in the original string */
10
+ matchedIndices: number[];
11
+ }
12
+ /**
13
+ * Perform fuzzy matching of a search pattern against a target string.
14
+ * Returns null if no match, or a FuzzyMatch object with score and matched indices.
15
+ *
16
+ * Scoring:
17
+ * - Consecutive matches score higher
18
+ * - Matches at word boundaries score higher
19
+ * - Matches at the start of the string score higher
20
+ * - Case-insensitive matching
21
+ *
22
+ * @param pattern - The search pattern (e.g., "cdt" to find "Created Date")
23
+ * @param target - The target string to search in
24
+ * @returns FuzzyMatch object or null if no match
25
+ */
26
+ export declare function fuzzyMatch(pattern: string, target: string): FuzzyMatch | null;
27
+ /**
28
+ * Search through an array of strings and return matches sorted by score.
29
+ *
30
+ * @param pattern - The search pattern
31
+ * @param items - Array of strings to search
32
+ * @param limit - Maximum number of results to return (default: all)
33
+ * @returns Array of FuzzyMatch objects sorted by score (highest first)
34
+ */
35
+ export declare function fuzzySearch(pattern: string, items: string[], limit?: number): FuzzyMatch[];
36
+ /**
37
+ * Highlight matched characters in a string by wrapping them in a specified tag.
38
+ * Returns an array of segments with matched/unmatched flags for rendering.
39
+ *
40
+ * @param text - The original text
41
+ * @param matchedIndices - Array of indices that matched
42
+ * @returns Array of text segments with isMatch flag
43
+ */
44
+ export declare function highlightMatches(text: string, matchedIndices: number[]): {
45
+ text: string;
46
+ isMatch: boolean;
47
+ }[];
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Fuzzy search utilities for column/field picker
3
+ */
4
+ /**
5
+ * Perform fuzzy matching of a search pattern against a target string.
6
+ * Returns null if no match, or a FuzzyMatch object with score and matched indices.
7
+ *
8
+ * Scoring:
9
+ * - Consecutive matches score higher
10
+ * - Matches at word boundaries score higher
11
+ * - Matches at the start of the string score higher
12
+ * - Case-insensitive matching
13
+ *
14
+ * @param pattern - The search pattern (e.g., "cdt" to find "Created Date")
15
+ * @param target - The target string to search in
16
+ * @returns FuzzyMatch object or null if no match
17
+ */
18
+ export function fuzzyMatch(pattern, target) {
19
+ if (!pattern) {
20
+ return { text: target, score: 0, matchedIndices: [] };
21
+ }
22
+ const patternLower = pattern.toLowerCase();
23
+ const targetLower = target.toLowerCase();
24
+ // Quick check: all pattern characters must exist in target
25
+ let patternIdx = 0;
26
+ for (let i = 0; i < targetLower.length && patternIdx < patternLower.length; i++) {
27
+ if (targetLower[i] === patternLower[patternIdx]) {
28
+ patternIdx++;
29
+ }
30
+ }
31
+ if (patternIdx !== patternLower.length) {
32
+ return null; // Not all pattern characters found
33
+ }
34
+ // Find optimal match positions using greedy algorithm
35
+ const matchedIndices = [];
36
+ let score = 0;
37
+ patternIdx = 0;
38
+ let lastMatchIdx = -1;
39
+ let consecutiveCount = 0;
40
+ for (let i = 0; i < targetLower.length && patternIdx < patternLower.length; i++) {
41
+ if (targetLower[i] === patternLower[patternIdx]) {
42
+ matchedIndices.push(i);
43
+ // Base score for match
44
+ score += 1;
45
+ // Bonus for consecutive matches
46
+ if (lastMatchIdx === i - 1) {
47
+ consecutiveCount++;
48
+ score += consecutiveCount * 2;
49
+ }
50
+ else {
51
+ consecutiveCount = 0;
52
+ }
53
+ // Bonus for match at start of string
54
+ if (i === 0) {
55
+ score += 10;
56
+ }
57
+ // Bonus for match at word boundary (after space, underscore, or uppercase)
58
+ if (i > 0) {
59
+ const prevChar = target[i - 1];
60
+ const currChar = target[i];
61
+ if (prevChar === ' ' || prevChar === '_' || prevChar === '-') {
62
+ score += 5;
63
+ }
64
+ else if (currChar === currChar.toUpperCase() && currChar !== currChar.toLowerCase()) {
65
+ // CamelCase boundary
66
+ score += 3;
67
+ }
68
+ }
69
+ lastMatchIdx = i;
70
+ patternIdx++;
71
+ }
72
+ }
73
+ // Bonus for shorter target strings (prefer more specific matches)
74
+ score += Math.max(0, 20 - target.length);
75
+ // Bonus if pattern matches significant portion of target
76
+ const coverageRatio = pattern.length / target.length;
77
+ score += Math.floor(coverageRatio * 10);
78
+ return {
79
+ text: target,
80
+ score,
81
+ matchedIndices
82
+ };
83
+ }
84
+ /**
85
+ * Search through an array of strings and return matches sorted by score.
86
+ *
87
+ * @param pattern - The search pattern
88
+ * @param items - Array of strings to search
89
+ * @param limit - Maximum number of results to return (default: all)
90
+ * @returns Array of FuzzyMatch objects sorted by score (highest first)
91
+ */
92
+ export function fuzzySearch(pattern, items, limit) {
93
+ if (!pattern) {
94
+ // Return all items with zero score when no pattern
95
+ const results = items.map((text) => ({ text, score: 0, matchedIndices: [] }));
96
+ return limit ? results.slice(0, limit) : results;
97
+ }
98
+ const matches = [];
99
+ for (const item of items) {
100
+ const match = fuzzyMatch(pattern, item);
101
+ if (match) {
102
+ matches.push(match);
103
+ }
104
+ }
105
+ // Sort by score descending
106
+ matches.sort((a, b) => b.score - a.score);
107
+ return limit ? matches.slice(0, limit) : matches;
108
+ }
109
+ /**
110
+ * Highlight matched characters in a string by wrapping them in a specified tag.
111
+ * Returns an array of segments with matched/unmatched flags for rendering.
112
+ *
113
+ * @param text - The original text
114
+ * @param matchedIndices - Array of indices that matched
115
+ * @returns Array of text segments with isMatch flag
116
+ */
117
+ export function highlightMatches(text, matchedIndices) {
118
+ if (!matchedIndices.length) {
119
+ return [{ text, isMatch: false }];
120
+ }
121
+ const matchSet = new Set(matchedIndices);
122
+ const segments = [];
123
+ let currentSegment = '';
124
+ let currentIsMatch = matchSet.has(0);
125
+ for (let i = 0; i < text.length; i++) {
126
+ const isMatch = matchSet.has(i);
127
+ if (isMatch === currentIsMatch) {
128
+ currentSegment += text[i];
129
+ }
130
+ else {
131
+ if (currentSegment) {
132
+ segments.push({ text: currentSegment, isMatch: currentIsMatch });
133
+ }
134
+ currentSegment = text[i];
135
+ currentIsMatch = isMatch;
136
+ }
137
+ }
138
+ if (currentSegment) {
139
+ segments.push({ text: currentSegment, isMatch: currentIsMatch });
140
+ }
141
+ return segments;
142
+ }
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@shotleybuilder/svelte-gridlite-kit",
3
+ "version": "0.1.0",
4
+ "description": "A SQL-native data grid component for Svelte and SvelteKit, powered by PGLite",
5
+ "author": "Sertantai",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "svelte",
9
+ "sveltekit",
10
+ "datagrid",
11
+ "pglite",
12
+ "postgres",
13
+ "sql",
14
+ "data-table",
15
+ "typescript"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/shotleybuilder/svelte-gridlite-kit.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/shotleybuilder/svelte-gridlite-kit/issues"
23
+ },
24
+ "homepage": "https://github.com/shotleybuilder/svelte-gridlite-kit#readme",
25
+ "type": "module",
26
+ "svelte": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "svelte": "./dist/index.js"
32
+ },
33
+ "./styles": "./dist/styles/gridlite.css"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "!dist/**/*.test.*",
38
+ "!dist/**/*.spec.*"
39
+ ],
40
+ "scripts": {
41
+ "dev": "vite dev",
42
+ "build": "vite build && npm run package",
43
+ "package": "svelte-kit sync && svelte-package && publint",
44
+ "prepublishOnly": "npm run package",
45
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
46
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
47
+ "test": "vitest",
48
+ "test:run": "vitest run",
49
+ "lint": "prettier --check . && eslint .",
50
+ "format": "prettier --write ."
51
+ },
52
+ "peerDependencies": {
53
+ "svelte": "^4.0.0 || ^5.0.0",
54
+ "@electric-sql/pglite": "^0.2.0"
55
+ },
56
+ "devDependencies": {
57
+ "@electric-sql/pglite": "^0.2.0",
58
+ "@sveltejs/adapter-auto": "^3.0.0",
59
+ "@sveltejs/kit": "^2.0.0",
60
+ "@sveltejs/package": "^2.0.0",
61
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
62
+ "@types/eslint": "^9.6.0",
63
+ "eslint": "^9.0.0",
64
+ "eslint-config-prettier": "^9.1.0",
65
+ "eslint-plugin-svelte": "^2.36.0",
66
+ "prettier": "^3.1.1",
67
+ "prettier-plugin-svelte": "^3.1.2",
68
+ "publint": "^0.1.9",
69
+ "svelte": "^4.2.7",
70
+ "svelte-check": "^3.6.0",
71
+ "tslib": "^2.4.1",
72
+ "typescript": "^5.0.0",
73
+ "vite": "^5.0.11",
74
+ "vitest": "^2.0.0"
75
+ }
76
+ }