bo-grid 0.8.0 → 0.21.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 (48) hide show
  1. package/README.md +202 -9
  2. package/dist/bo-grid.FilterMenu-BHI6rILc.js +154 -0
  3. package/dist/bo-grid.ToolPanel-C3u-4YKc.js +34 -0
  4. package/dist/bo-grid.element-DPnHUXMa.js +6623 -0
  5. package/dist/bo-grid.element.js +4 -0
  6. package/dist/charts/BarChart.svelte +50 -0
  7. package/dist/charts/BarChart.svelte.d.ts +16 -0
  8. package/dist/charts/DonutChart.svelte +54 -0
  9. package/dist/charts/DonutChart.svelte.d.ts +18 -0
  10. package/dist/charts/Legend.svelte +47 -0
  11. package/dist/charts/Legend.svelte.d.ts +12 -0
  12. package/dist/charts/LineChart.svelte +59 -0
  13. package/dist/charts/LineChart.svelte.d.ts +14 -0
  14. package/dist/charts/StackedBarChart.svelte +56 -0
  15. package/dist/charts/StackedBarChart.svelte.d.ts +18 -0
  16. package/dist/charts/chart-math.d.ts +57 -0
  17. package/dist/charts/chart-math.js +174 -0
  18. package/dist/charts/index.d.ts +8 -0
  19. package/dist/charts/index.js +11 -0
  20. package/dist/charts/palette.d.ts +4 -0
  21. package/dist/charts/palette.js +14 -0
  22. package/dist/format/format.d.ts +6 -0
  23. package/dist/format/format.js +41 -0
  24. package/dist/grid/Cell.svelte +247 -8
  25. package/dist/grid/Cell.svelte.d.ts +6 -0
  26. package/dist/grid/FilterMenu.svelte +7 -0
  27. package/dist/grid/Grid.svelte +307 -85
  28. package/dist/grid/Grid.svelte.d.ts +19 -0
  29. package/dist/grid/GroupRow.svelte +5 -2
  30. package/dist/grid/Pager.svelte +4 -0
  31. package/dist/grid/RowMenu.svelte +65 -2
  32. package/dist/grid/ToolPanel.svelte +5 -0
  33. package/dist/grid/column.d.ts +133 -0
  34. package/dist/grid/column.js +133 -4
  35. package/dist/grid/colvirt.d.ts +15 -0
  36. package/dist/grid/colvirt.js +43 -0
  37. package/dist/grid/export.js +5 -2
  38. package/dist/grid/filtering.d.ts +5 -2
  39. package/dist/grid/filtering.js +5 -4
  40. package/dist/grid/grouping.d.ts +30 -0
  41. package/dist/grid/grouping.js +33 -0
  42. package/dist/grid/theme.d.ts +15 -0
  43. package/dist/grid/theme.js +78 -0
  44. package/dist/grid/tree.d.ts +19 -7
  45. package/dist/grid/tree.js +16 -11
  46. package/dist/index.d.ts +5 -4
  47. package/dist/index.js +2 -2
  48. package/package.json +12 -2
@@ -10,6 +10,19 @@ export interface GroupNode {
10
10
  rows: GridRow[];
11
11
  count: number;
12
12
  collapsed: boolean;
13
+ /** Server-provided aggregate display strings, keyed by column key (lazy groups).
14
+ When present, the group header shows these instead of computing from `rows`. */
15
+ aggText?: Record<string, string>;
16
+ }
17
+ /** A server-side group summary (lazy grouping): the header data without the leaf
18
+ rows, which load on expand via `loadGroup`. */
19
+ export interface LazyGroup {
20
+ key: string;
21
+ /** Header label (defaults to `key`). */
22
+ label?: string;
23
+ count?: number;
24
+ /** Preformatted aggregate strings keyed by column key, shown in the header. */
25
+ agg?: Record<string, string>;
13
26
  }
14
27
  export type VisualRow = {
15
28
  kind: 'data';
@@ -19,6 +32,9 @@ export type VisualRow = {
19
32
  } | {
20
33
  kind: 'group';
21
34
  group: GroupNode;
35
+ } | {
36
+ kind: 'treeloading';
37
+ depth: number;
22
38
  };
23
39
  /**
24
40
  * Flatten data rows into the visual row list the grid renders: a stream of
@@ -36,3 +52,17 @@ export declare function buildFlatRows(rows: GridRow[], groupBy: string[], collap
36
52
  * nearest preceding header at each depth until the depth-0 group is found.
37
53
  */
38
54
  export declare function activeGroupsAt(flat: VisualRow[], idx: number): GroupNode[];
55
+ /** How lazy grouping reads expand/loading state and the rows loaded per group. */
56
+ export interface LazyGroupAccess {
57
+ isExpanded: (key: string) => boolean;
58
+ /** Loaded leaf rows for a group, or undefined when not yet loaded. */
59
+ rowsOf: (key: string) => readonly GridRow[] | undefined;
60
+ isLoading: (key: string) => boolean;
61
+ }
62
+ /**
63
+ * Flatten server-side group summaries into visual rows: a group header per group,
64
+ * then — when expanded — its loaded leaf rows, or a single `treeloading`
65
+ * placeholder while they load. Aggregates come from the summary (not computed).
66
+ * Pure; unit-tested.
67
+ */
68
+ export declare function buildLazyGroupRows(groups: readonly LazyGroup[], access: LazyGroupAccess): VisualRow[];
@@ -60,3 +60,36 @@ export function activeGroupsAt(flat, idx) {
60
60
  }
61
61
  return [...found.values()].sort((a, b) => a.depth - b.depth);
62
62
  }
63
+ /**
64
+ * Flatten server-side group summaries into visual rows: a group header per group,
65
+ * then — when expanded — its loaded leaf rows, or a single `treeloading`
66
+ * placeholder while they load. Aggregates come from the summary (not computed).
67
+ * Pure; unit-tested.
68
+ */
69
+ export function buildLazyGroupRows(groups, access) {
70
+ const out = [];
71
+ for (const g of groups) {
72
+ const expanded = access.isExpanded(g.key);
73
+ out.push({
74
+ kind: 'group',
75
+ group: {
76
+ path: g.key,
77
+ depth: 0,
78
+ value: g.label ?? g.key,
79
+ rows: [],
80
+ count: g.count ?? 0,
81
+ collapsed: !expanded,
82
+ aggText: g.agg,
83
+ },
84
+ });
85
+ if (!expanded)
86
+ continue;
87
+ const loaded = access.rowsOf(g.key);
88
+ if (loaded)
89
+ for (const row of loaded)
90
+ out.push({ kind: 'data', row });
91
+ else if (access.isLoading(g.key))
92
+ out.push({ kind: 'treeloading', depth: 1 });
93
+ }
94
+ return out;
95
+ }
@@ -35,3 +35,18 @@ export interface GridTheme {
35
35
  export declare function themeVars(theme: GridTheme): string;
36
36
  export declare const darkTheme: GridTheme;
37
37
  export declare const lightTheme: GridTheme;
38
+ export declare const highContrastDark: GridTheme;
39
+ export declare const highContrastLight: GridTheme;
40
+ export declare const midnightTheme: GridTheme;
41
+ export declare const terminalTheme: GridTheme;
42
+ /** All built-in presets, keyed by name (handy for a theme picker). */
43
+ export declare const themePresets: {
44
+ dark: GridTheme;
45
+ light: GridTheme;
46
+ 'high-contrast-dark': GridTheme;
47
+ 'high-contrast-light': GridTheme;
48
+ midnight: GridTheme;
49
+ terminal: GridTheme;
50
+ };
51
+ /** Built-in preset name. */
52
+ export type ThemePreset = keyof typeof themePresets;
@@ -64,3 +64,81 @@ export const lightTheme = {
64
64
  selBorder: '#6366f1',
65
65
  scheme: 'light',
66
66
  };
67
+ // High-contrast dark (accessibility): pure black, white text, strong borders and
68
+ // vivid status colours — comfortably exceeds WCAG AA, toward AAA.
69
+ export const highContrastDark = {
70
+ bg: '#000000',
71
+ headerBg: '#0a0a0a',
72
+ rowA: '#000000',
73
+ rowB: '#0a0a0a',
74
+ rowHover: '#1c1c1c',
75
+ text: '#ffffff',
76
+ textDim: '#c8c8c8',
77
+ border: 'rgba(255,255,255,0.34)',
78
+ up: '#00e676',
79
+ down: '#ff5252',
80
+ amber: '#ffd740',
81
+ selFill: 'rgba(255,255,255,0.20)',
82
+ selBorder: '#ffffff',
83
+ scheme: 'dark',
84
+ };
85
+ // High-contrast light (accessibility): white, near-black text, strong borders.
86
+ export const highContrastLight = {
87
+ bg: '#ffffff',
88
+ headerBg: '#eeeeee',
89
+ rowA: '#ffffff',
90
+ rowB: '#f5f5f5',
91
+ rowHover: '#e3e3e3',
92
+ text: '#000000',
93
+ textDim: '#383838',
94
+ border: 'rgba(0,0,0,0.42)',
95
+ up: '#007a36',
96
+ down: '#c20000',
97
+ amber: '#7a5c00',
98
+ selFill: 'rgba(0,0,0,0.10)',
99
+ selBorder: '#000000',
100
+ scheme: 'light',
101
+ };
102
+ // Midnight: a deep navy/indigo dark theme — a calmer, "premium" alternative.
103
+ export const midnightTheme = {
104
+ bg: '#0f172a',
105
+ headerBg: '#0b1120',
106
+ rowA: '#0f172a',
107
+ rowB: '#121d35',
108
+ rowHover: '#1e293b',
109
+ text: '#e2e8f0',
110
+ textDim: '#94a3b8',
111
+ border: 'rgba(148,163,184,0.16)',
112
+ up: '#34d399',
113
+ down: '#fb7185',
114
+ amber: '#fbbf24',
115
+ selFill: 'rgba(129,140,248,0.22)',
116
+ selBorder: '#818cf8',
117
+ scheme: 'dark',
118
+ };
119
+ // Terminal: green phosphor on near-black — a retro fintech/console look.
120
+ export const terminalTheme = {
121
+ bg: '#0a0f0a',
122
+ headerBg: '#0d140d',
123
+ rowA: '#0a0f0a',
124
+ rowB: '#0e160e',
125
+ rowHover: '#16241a',
126
+ text: '#4ade80',
127
+ textDim: '#3f9e60',
128
+ border: 'rgba(74,222,128,0.20)',
129
+ up: '#4ade80',
130
+ down: '#f87171',
131
+ amber: '#fde047',
132
+ selFill: 'rgba(74,222,128,0.16)',
133
+ selBorder: '#4ade80',
134
+ scheme: 'dark',
135
+ };
136
+ /** All built-in presets, keyed by name (handy for a theme picker). */
137
+ export const themePresets = {
138
+ dark: darkTheme,
139
+ light: lightTheme,
140
+ 'high-contrast-dark': highContrastDark,
141
+ 'high-contrast-light': highContrastLight,
142
+ midnight: midnightTheme,
143
+ terminal: terminalTheme,
144
+ };
@@ -1,12 +1,24 @@
1
1
  import type { GridRow } from './column';
2
2
  import type { VisualRow } from './grouping';
3
- /** Resolve a row's children (undefined/empty = leaf). */
3
+ /** Resolve a row's children (undefined/empty = leaf). Sync. */
4
4
  export type GetChildren = (row: GridRow) => GridRow[] | undefined;
5
+ /** How the flattener reads a tree: which rows have children, which are expanded,
6
+ the children currently available (sync result or async cache), and which
7
+ expanded nodes are still loading. */
8
+ export interface TreeAccess {
9
+ /** Children available now (sync result or loaded cache); undefined = not loaded. */
10
+ childrenOf: (row: GridRow) => readonly GridRow[] | undefined;
11
+ /** Cheap predicate: does this row have children? (Drives the expand chevron.) */
12
+ hasChildren: (row: GridRow) => boolean;
13
+ isExpanded: (row: GridRow) => boolean;
14
+ /** Whether an expanded row's children are still loading (async trees). */
15
+ isLoading?: (row: GridRow) => boolean;
16
+ }
5
17
  /**
6
- * Flatten a tree of rows into the visible, depth-tagged data rows the grid
7
- * renders. Pre-order DFS: each node is emitted, then — if it has children and
8
- * `isExpanded` returns true — its children, one level deeper. Collapsed or leaf
9
- * nodes contribute only themselves. Pure: no row values are read, so a realtime
10
- * tick never rebuilds this list.
18
+ * Flatten a tree of rows into the visible, depth-tagged rows the grid renders.
19
+ * Pre-order DFS: each node is emitted, then — if it has children and is expanded
20
+ * — its loaded children one level deeper, or a single `treeloading` placeholder
21
+ * while they load. Pure: no row values are read, so a realtime tick never rebuilds
22
+ * this list.
11
23
  */
12
- export declare function buildTreeRows(roots: readonly GridRow[], getChildren: GetChildren, isExpanded: (row: GridRow) => boolean): VisualRow[];
24
+ export declare function buildTreeRows(roots: readonly GridRow[], access: TreeAccess): VisualRow[];
package/dist/grid/tree.js CHANGED
@@ -1,19 +1,24 @@
1
1
  /**
2
- * Flatten a tree of rows into the visible, depth-tagged data rows the grid
3
- * renders. Pre-order DFS: each node is emitted, then — if it has children and
4
- * `isExpanded` returns true — its children, one level deeper. Collapsed or leaf
5
- * nodes contribute only themselves. Pure: no row values are read, so a realtime
6
- * tick never rebuilds this list.
2
+ * Flatten a tree of rows into the visible, depth-tagged rows the grid renders.
3
+ * Pre-order DFS: each node is emitted, then — if it has children and is expanded
4
+ * — its loaded children one level deeper, or a single `treeloading` placeholder
5
+ * while they load. Pure: no row values are read, so a realtime tick never rebuilds
6
+ * this list.
7
7
  */
8
- export function buildTreeRows(roots, getChildren, isExpanded) {
8
+ export function buildTreeRows(roots, access) {
9
+ const { childrenOf, hasChildren, isExpanded, isLoading } = access;
9
10
  const out = [];
10
11
  const walk = (nodes, depth) => {
11
12
  for (const row of nodes) {
12
- const children = getChildren(row);
13
- const hasChildren = !!children && children.length > 0;
14
- out.push({ kind: 'data', row, depth, hasChildren });
15
- if (hasChildren && isExpanded(row))
16
- walk(children, depth + 1);
13
+ const has = hasChildren(row);
14
+ out.push({ kind: 'data', row, depth, hasChildren: has });
15
+ if (has && isExpanded(row)) {
16
+ const children = childrenOf(row);
17
+ if (children && children.length > 0)
18
+ walk(children, depth + 1);
19
+ else if (isLoading?.(row))
20
+ out.push({ kind: 'treeloading', depth: depth + 1 });
21
+ }
17
22
  }
18
23
  };
19
24
  walk(roots, 0);
package/dist/index.d.ts CHANGED
@@ -1,16 +1,17 @@
1
1
  export { default as Grid } from './grid/Grid.svelte';
2
2
  export { default as Sparkline } from './sparkline/Sparkline.svelte';
3
- export type { ColumnDef, Align, GridRow, SortDir, SortState, CellEditEvent } from './grid/column';
3
+ export type { LazyGroup } from './grid/grouping';
4
+ export type { ColumnDef, Align, GridRow, SortDir, SortState, CellEditEvent, BadgeTone, DataBarConfig, IconRule, ColorScaleConfig, } from './grid/column';
4
5
  export type { AggKind, AggResult } from './grid/aggregate';
5
6
  export type { ColumnFilter, FilterKind, TextOp, NumberOp, DateOp } from './grid/filtering';
6
- export { fmtPrice, fmtPercent, fmtVolume, fmtDate } from './format/format';
7
+ export { fmtPrice, fmtPercent, fmtVolume, fmtDate, fmtCurrency, relativeTime } from './format/format';
7
8
  export type { DateStyle } from './format/format';
8
9
  export { aggregate } from './grid/aggregate';
9
10
  export { heatColor } from './grid/heatmap';
10
11
  export { pivot } from './grid/pivot';
11
12
  export type { PivotConfig, PivotResult } from './grid/pivot';
12
- export { themeVars, darkTheme, lightTheme } from './grid/theme';
13
- export type { GridTheme } from './grid/theme';
13
+ export { themeVars, darkTheme, lightTheme, highContrastDark, highContrastLight, midnightTheme, terminalTheme, themePresets, } from './grid/theme';
14
+ export type { GridTheme, ThemePreset } from './grid/theme';
14
15
  export { drawCandles, setupHiDpiCanvas } from './sparkline/sparkline-render';
15
16
  export { toCSV, exportCSV } from './grid/export';
16
17
  export { exportXLSX } from './grid/export-xlsx';
package/dist/index.js CHANGED
@@ -8,13 +8,13 @@
8
8
  export { default as Grid } from './grid/Grid.svelte';
9
9
  export { default as Sparkline } from './sparkline/Sparkline.svelte';
10
10
  // Value formatters (handy when building custom cell content)
11
- export { fmtPrice, fmtPercent, fmtVolume, fmtDate } from './format/format';
11
+ export { fmtPrice, fmtPercent, fmtVolume, fmtDate, fmtCurrency, relativeTime } from './format/format';
12
12
  // Standalone helpers
13
13
  export { aggregate } from './grid/aggregate';
14
14
  export { heatColor } from './grid/heatmap';
15
15
  export { pivot } from './grid/pivot';
16
16
  // Theming
17
- export { themeVars, darkTheme, lightTheme } from './grid/theme';
17
+ export { themeVars, darkTheme, lightTheme, highContrastDark, highContrastLight, midnightTheme, terminalTheme, themePresets, } from './grid/theme';
18
18
  // Sparkline canvas primitives (draw candlesticks on your own canvas)
19
19
  export { drawCandles, setupHiDpiCanvas } from './sparkline/sparkline-render';
20
20
  // Export (CSV is dependency-free; XLSX dynamic-imports the optional `xlsx` peer)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bo-grid",
3
- "version": "0.8.0",
3
+ "version": "0.21.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Tiny, fast Svelte 5 data grid: canvas sparklines, batched realtime cell updates, and virtual scrolling. A free, fintech-focused alternative to heavyweight grids.",
@@ -33,6 +33,14 @@
33
33
  "svelte": "./dist/index.js",
34
34
  "default": "./dist/index.js"
35
35
  },
36
+ "./charts": {
37
+ "types": "./dist/charts/index.d.ts",
38
+ "svelte": "./dist/charts/index.js",
39
+ "default": "./dist/charts/index.js"
40
+ },
41
+ "./element": {
42
+ "default": "./dist/bo-grid.element.js"
43
+ },
36
44
  "./package.json": "./package.json"
37
45
  },
38
46
  "files": [
@@ -53,12 +61,14 @@
53
61
  "demo:build": "vite build",
54
62
  "pages:build": "vite build --base=/bo-grid/ --outDir demo-dist",
55
63
  "preview": "vite preview",
56
- "package": "svelte-package -i src/lib -o dist && node scripts/clean-dist.mjs",
64
+ "package": "svelte-package -i src/lib -o dist && node scripts/clean-dist.mjs && pnpm run build:wc",
65
+ "build:wc": "vite build --config vite.wc.config.ts",
57
66
  "prepublishOnly": "pnpm run package",
58
67
  "check": "svelte-check --tsconfig ./tsconfig.json",
59
68
  "size": "vite build && node scripts/size-check.mjs",
60
69
  "size:lib": "vite build --config vite.lib.config.ts && node scripts/size-lib.mjs",
61
70
  "smoke": "vite build --base=./ --outDir demo-dist && node scripts/smoke.mjs",
71
+ "smoke:wc": "node scripts/wc-smoke.mjs",
62
72
  "ssr": "node scripts/ssr.mjs",
63
73
  "bench": "node scripts/bench.mjs",
64
74
  "test": "vitest run",