@calliopelabs/ui 0.14.0 → 0.18.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 (127) hide show
  1. package/README.md +235 -1
  2. package/dist/agent/AgentChat.d.ts +8 -1
  3. package/dist/agent/AgentChat.js +43 -2
  4. package/dist/agent/WorkflowRenderers.d.ts +61 -0
  5. package/dist/agent/WorkflowRenderers.js +102 -0
  6. package/dist/agent/controller.d.ts +19 -0
  7. package/dist/agent/controller.js +33 -0
  8. package/dist/agent/copilotkit/CopilotKitAgentProvider.js +2 -2
  9. package/dist/agent/index.d.ts +4 -2
  10. package/dist/agent/index.js +3 -1
  11. package/dist/agent/mock.d.ts +26 -4
  12. package/dist/agent/mock.js +68 -37
  13. package/dist/agent/renderers.d.ts +49 -0
  14. package/dist/agent/renderers.js +27 -0
  15. package/dist/appearance/brands.d.ts +17 -0
  16. package/dist/appearance/brands.js +14 -0
  17. package/dist/chat/MessageBubble.js +1 -1
  18. package/dist/chat/MessageList.d.ts +9 -2
  19. package/dist/chat/MessageList.js +11 -8
  20. package/dist/css/appearance.js +1 -1
  21. package/dist/css/calliope.css +5 -0
  22. package/dist/css/tokens.css +5 -0
  23. package/dist/index.d.ts +9 -1
  24. package/dist/index.js +8 -1
  25. package/dist/primitives/Badge.d.ts +14 -0
  26. package/dist/primitives/Badge.js +25 -0
  27. package/dist/primitives/ContextMenu.d.ts +18 -0
  28. package/dist/primitives/ContextMenu.js +34 -0
  29. package/dist/primitives/Menubar.d.ts +21 -0
  30. package/dist/primitives/Menubar.js +43 -0
  31. package/dist/primitives/ScrollArea.d.ts +16 -0
  32. package/dist/primitives/ScrollArea.js +11 -0
  33. package/dist/primitives/Toast.d.ts +37 -0
  34. package/dist/primitives/Toast.js +43 -0
  35. package/dist/primitives/Tooltip.d.ts +16 -0
  36. package/dist/primitives/Tooltip.js +26 -0
  37. package/dist/provider/messages.d.ts +217 -0
  38. package/dist/provider/messages.js +238 -0
  39. package/dist/shell/RailPanel.js +1 -1
  40. package/dist/theme/css-layer.js +2 -1
  41. package/dist/theme/tokens.generated.d.ts +3 -0
  42. package/dist/theme/tokens.generated.js +3 -0
  43. package/dist/workbench/ActivityBar.d.ts +37 -0
  44. package/dist/workbench/ActivityBar.js +57 -0
  45. package/dist/workbench/BottomPanel.d.ts +30 -0
  46. package/dist/workbench/BottomPanel.js +20 -0
  47. package/dist/workbench/CodeEditor.d.ts +48 -0
  48. package/dist/workbench/CodeEditor.js +153 -0
  49. package/dist/workbench/CommandPalette.d.ts +49 -0
  50. package/dist/workbench/CommandPalette.js +114 -0
  51. package/dist/workbench/DataChart.d.ts +45 -0
  52. package/dist/workbench/DataChart.js +146 -0
  53. package/dist/workbench/DataGrid.d.ts +89 -0
  54. package/dist/workbench/DataGrid.js +590 -0
  55. package/dist/workbench/DataProfile.d.ts +17 -0
  56. package/dist/workbench/DataProfile.js +51 -0
  57. package/dist/workbench/EditorTabs.d.ts +62 -0
  58. package/dist/workbench/EditorTabs.js +115 -0
  59. package/dist/workbench/FileBrowser.d.ts +62 -0
  60. package/dist/workbench/FileBrowser.js +117 -0
  61. package/dist/workbench/FileGrid.d.ts +13 -0
  62. package/dist/workbench/FileGrid.js +114 -0
  63. package/dist/workbench/FileIcon.d.ts +10 -0
  64. package/dist/workbench/FileIcon.js +24 -0
  65. package/dist/workbench/FileList.d.ts +35 -0
  66. package/dist/workbench/FileList.js +160 -0
  67. package/dist/workbench/FilePreview.d.ts +66 -0
  68. package/dist/workbench/FilePreview.js +108 -0
  69. package/dist/workbench/FileTree.d.ts +37 -0
  70. package/dist/workbench/FileTree.js +218 -0
  71. package/dist/workbench/GridCell.d.ts +19 -0
  72. package/dist/workbench/GridCell.js +50 -0
  73. package/dist/workbench/GridDetails.d.ts +31 -0
  74. package/dist/workbench/GridDetails.js +78 -0
  75. package/dist/workbench/MenuBar.d.ts +49 -0
  76. package/dist/workbench/MenuBar.js +25 -0
  77. package/dist/workbench/PaneGroup.d.ts +50 -0
  78. package/dist/workbench/PaneGroup.js +146 -0
  79. package/dist/workbench/PendingChangesBar.d.ts +20 -0
  80. package/dist/workbench/PendingChangesBar.js +19 -0
  81. package/dist/workbench/Shortcuts.d.ts +50 -0
  82. package/dist/workbench/Shortcuts.js +109 -0
  83. package/dist/workbench/SqlEditor.d.ts +21 -0
  84. package/dist/workbench/SqlEditor.js +79 -0
  85. package/dist/workbench/StatusBar.d.ts +28 -0
  86. package/dist/workbench/StatusBar.js +26 -0
  87. package/dist/workbench/TruncationBanner.d.ts +11 -0
  88. package/dist/workbench/TruncationBanner.js +12 -0
  89. package/dist/workbench/UploadDropzone.d.ts +52 -0
  90. package/dist/workbench/UploadDropzone.js +115 -0
  91. package/dist/workbench/WorkbenchShell.d.ts +36 -0
  92. package/dist/workbench/WorkbenchShell.js +20 -0
  93. package/dist/workbench/dnd.d.ts +17 -0
  94. package/dist/workbench/dnd.js +77 -0
  95. package/dist/workbench/download.d.ts +11 -0
  96. package/dist/workbench/download.js +28 -0
  97. package/dist/workbench/editor-theme.d.ts +42 -0
  98. package/dist/workbench/editor-theme.js +113 -0
  99. package/dist/workbench/grid-format.d.ts +59 -0
  100. package/dist/workbench/grid-format.js +169 -0
  101. package/dist/workbench/grid-model.d.ts +75 -0
  102. package/dist/workbench/grid-model.js +259 -0
  103. package/dist/workbench/grid-selection.d.ts +69 -0
  104. package/dist/workbench/grid-selection.js +183 -0
  105. package/dist/workbench/grid-stats.d.ts +58 -0
  106. package/dist/workbench/grid-stats.js +185 -0
  107. package/dist/workbench/index.d.ts +44 -0
  108. package/dist/workbench/index.js +47 -0
  109. package/dist/workbench/keys.d.ts +23 -0
  110. package/dist/workbench/keys.js +105 -0
  111. package/dist/workbench/model.d.ts +72 -0
  112. package/dist/workbench/model.js +214 -0
  113. package/dist/workbench/palette.d.ts +17 -0
  114. package/dist/workbench/palette.js +45 -0
  115. package/dist/workbench/pending.d.ts +92 -0
  116. package/dist/workbench/pending.js +207 -0
  117. package/dist/workbench/selection.d.ts +16 -0
  118. package/dist/workbench/selection.js +46 -0
  119. package/dist/workbench/sql-completion.d.ts +107 -0
  120. package/dist/workbench/sql-completion.js +475 -0
  121. package/dist/workbench/typeahead.d.ts +15 -0
  122. package/dist/workbench/typeahead.js +22 -0
  123. package/dist/workflow/WorkflowRuntimeControls.d.ts +21 -0
  124. package/dist/workflow/WorkflowRuntimeControls.js +54 -0
  125. package/dist/workflow/runtime-controls.d.ts +29 -0
  126. package/dist/workflow/runtime-controls.js +10 -0
  127. package/package.json +17 -2
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The grid's selection model, as pure data (from Loadr's grid).
3
+ *
4
+ * Coordinates are *view* coordinates: `row` indexes the visible (filtered and
5
+ * sorted) row order, `col` indexes the visible columns. The grid maps them back
6
+ * to source rows when it copies or edits. Keeping the model out of the
7
+ * component is what lets 50k-row selection behaviour be tested without a DOM.
8
+ */
9
+ export interface CellRef {
10
+ row: number;
11
+ col: number;
12
+ }
13
+ /** A rectangle, anchored where the drag or shift-click started. */
14
+ export interface SelectionRange {
15
+ anchor: CellRef;
16
+ focus: CellRef;
17
+ }
18
+ export interface SelectionState {
19
+ /** Additive ranges, in the order the user made them. */
20
+ ranges: SelectionRange[];
21
+ /** The cell the keyboard acts on. Null when nothing is selected. */
22
+ active: CellRef | null;
23
+ }
24
+ export declare const EMPTY_SELECTION: SelectionState;
25
+ export interface Bounds {
26
+ minRow: number;
27
+ maxRow: number;
28
+ minCol: number;
29
+ maxCol: number;
30
+ }
31
+ /** Is this cell inside any range? */
32
+ export declare function isSelected(state: SelectionState, row: number, col: number): boolean;
33
+ /** Total cells covered, counting an overlap once. */
34
+ export declare function selectionSize(state: SelectionState): number;
35
+ /** The bounding box of everything selected, or null when nothing is. */
36
+ export declare function selectionBounds(state: SelectionState): Bounds | null;
37
+ /** Plain click: one cell, everything else dropped. */
38
+ export declare function selectCell(cell: CellRef): SelectionState;
39
+ /**
40
+ * Shift-click or shift-arrow: stretch the newest range from its anchor.
41
+ *
42
+ * With nothing selected yet this behaves like a plain click, which is what
43
+ * every spreadsheet does when you shift-click into an empty grid.
44
+ */
45
+ export declare function extendSelection(state: SelectionState, cell: CellRef): SelectionState;
46
+ /**
47
+ * Cmd/Ctrl-click: add the cell as its own range, or remove it if it was
48
+ * already the whole of one. Clicking inside a bigger range leaves that range
49
+ * alone and just moves the active cell, which is how Excel behaves.
50
+ */
51
+ export declare function toggleCell(state: SelectionState, cell: CellRef): SelectionState;
52
+ /** Column header click. Additive keeps the existing ranges (cmd-click). */
53
+ export declare function selectColumn(state: SelectionState, col: number, rowCount: number, additive?: boolean): SelectionState;
54
+ /** Row-number click. */
55
+ export declare function selectRow(state: SelectionState, row: number, colCount: number, additive?: boolean): SelectionState;
56
+ /** Shift-click on a row number: every row between the anchor row and this one. */
57
+ export declare function extendRowSelection(state: SelectionState, row: number, colCount: number): SelectionState;
58
+ export declare function selectAll(rowCount: number, colCount: number): SelectionState;
59
+ /** True when every row of `col` is inside the selection. */
60
+ export declare function isColumnSelected(state: SelectionState, col: number, rowCount: number): boolean;
61
+ /** True when every column of `row` is inside the selection. */
62
+ export declare function isRowSelected(state: SelectionState, row: number, colCount: number): boolean;
63
+ /**
64
+ * Move the active cell, clamped to the grid.
65
+ *
66
+ * `extend` stretches the current range instead of starting a new one, which is
67
+ * what shift-arrow does.
68
+ */
69
+ export declare function moveActive(state: SelectionState, to: CellRef, rowCount: number, colCount: number, extend: boolean): SelectionState;
@@ -0,0 +1,183 @@
1
+ /**
2
+ * The grid's selection model, as pure data (from Loadr's grid).
3
+ *
4
+ * Coordinates are *view* coordinates: `row` indexes the visible (filtered and
5
+ * sorted) row order, `col` indexes the visible columns. The grid maps them back
6
+ * to source rows when it copies or edits. Keeping the model out of the
7
+ * component is what lets 50k-row selection behaviour be tested without a DOM.
8
+ */
9
+ export const EMPTY_SELECTION = { ranges: [], active: null };
10
+ function rangeBounds(range) {
11
+ return {
12
+ minRow: Math.min(range.anchor.row, range.focus.row),
13
+ maxRow: Math.max(range.anchor.row, range.focus.row),
14
+ minCol: Math.min(range.anchor.col, range.focus.col),
15
+ maxCol: Math.max(range.anchor.col, range.focus.col),
16
+ };
17
+ }
18
+ function contains(range, row, col) {
19
+ const b = rangeBounds(range);
20
+ return row >= b.minRow && row <= b.maxRow && col >= b.minCol && col <= b.maxCol;
21
+ }
22
+ /** Is this cell inside any range? */
23
+ export function isSelected(state, row, col) {
24
+ for (const range of state.ranges) {
25
+ if (contains(range, row, col))
26
+ return true;
27
+ }
28
+ return false;
29
+ }
30
+ /** Total cells covered, counting an overlap once. */
31
+ export function selectionSize(state) {
32
+ if (state.ranges.length === 0)
33
+ return 0;
34
+ const [only] = state.ranges;
35
+ if (state.ranges.length === 1 && only) {
36
+ const b = rangeBounds(only);
37
+ return (b.maxRow - b.minRow + 1) * (b.maxCol - b.minCol + 1);
38
+ }
39
+ const seen = new Set();
40
+ for (const range of state.ranges) {
41
+ const b = rangeBounds(range);
42
+ for (let r = b.minRow; r <= b.maxRow; r++) {
43
+ for (let c = b.minCol; c <= b.maxCol; c++)
44
+ seen.add(`${r}:${c}`);
45
+ }
46
+ }
47
+ return seen.size;
48
+ }
49
+ /** The bounding box of everything selected, or null when nothing is. */
50
+ export function selectionBounds(state) {
51
+ if (state.ranges.length === 0)
52
+ return null;
53
+ let out = null;
54
+ for (const range of state.ranges) {
55
+ const b = rangeBounds(range);
56
+ out = out
57
+ ? {
58
+ minRow: Math.min(out.minRow, b.minRow),
59
+ maxRow: Math.max(out.maxRow, b.maxRow),
60
+ minCol: Math.min(out.minCol, b.minCol),
61
+ maxCol: Math.max(out.maxCol, b.maxCol),
62
+ }
63
+ : b;
64
+ }
65
+ return out;
66
+ }
67
+ /** Plain click: one cell, everything else dropped. */
68
+ export function selectCell(cell) {
69
+ return { ranges: [{ anchor: cell, focus: cell }], active: cell };
70
+ }
71
+ /**
72
+ * Shift-click or shift-arrow: stretch the newest range from its anchor.
73
+ *
74
+ * With nothing selected yet this behaves like a plain click, which is what
75
+ * every spreadsheet does when you shift-click into an empty grid.
76
+ */
77
+ export function extendSelection(state, cell) {
78
+ if (state.ranges.length === 0)
79
+ return selectCell(cell);
80
+ const ranges = state.ranges.slice();
81
+ const last = ranges[ranges.length - 1];
82
+ if (!last)
83
+ return selectCell(cell);
84
+ ranges[ranges.length - 1] = { anchor: last.anchor, focus: cell };
85
+ return { ranges, active: cell };
86
+ }
87
+ /**
88
+ * Cmd/Ctrl-click: add the cell as its own range, or remove it if it was
89
+ * already the whole of one. Clicking inside a bigger range leaves that range
90
+ * alone and just moves the active cell, which is how Excel behaves.
91
+ */
92
+ export function toggleCell(state, cell) {
93
+ const exact = state.ranges.findIndex((r) => r.anchor.row === cell.row &&
94
+ r.anchor.col === cell.col &&
95
+ r.focus.row === cell.row &&
96
+ r.focus.col === cell.col);
97
+ if (exact >= 0) {
98
+ const ranges = state.ranges.filter((_, i) => i !== exact);
99
+ return { ranges, active: ranges[ranges.length - 1]?.focus ?? null };
100
+ }
101
+ return { ranges: [...state.ranges, { anchor: cell, focus: cell }], active: cell };
102
+ }
103
+ /** Column header click. Additive keeps the existing ranges (cmd-click). */
104
+ export function selectColumn(state, col, rowCount, additive = false) {
105
+ if (rowCount === 0)
106
+ return additive ? state : EMPTY_SELECTION;
107
+ const range = {
108
+ anchor: { row: 0, col },
109
+ focus: { row: rowCount - 1, col },
110
+ };
111
+ return {
112
+ ranges: additive ? [...state.ranges, range] : [range],
113
+ active: { row: 0, col },
114
+ };
115
+ }
116
+ /** Row-number click. */
117
+ export function selectRow(state, row, colCount, additive = false) {
118
+ if (colCount === 0)
119
+ return additive ? state : EMPTY_SELECTION;
120
+ const range = {
121
+ anchor: { row, col: 0 },
122
+ focus: { row, col: colCount - 1 },
123
+ };
124
+ return {
125
+ ranges: additive ? [...state.ranges, range] : [range],
126
+ active: { row, col: 0 },
127
+ };
128
+ }
129
+ /** Shift-click on a row number: every row between the anchor row and this one. */
130
+ export function extendRowSelection(state, row, colCount) {
131
+ if (state.ranges.length === 0)
132
+ return selectRow(state, row, colCount);
133
+ const ranges = state.ranges.slice();
134
+ const last = ranges[ranges.length - 1];
135
+ if (!last)
136
+ return selectRow(state, row, colCount);
137
+ ranges[ranges.length - 1] = {
138
+ anchor: { row: last.anchor.row, col: 0 },
139
+ focus: { row, col: Math.max(colCount - 1, 0) },
140
+ };
141
+ return { ranges, active: { row, col: 0 } };
142
+ }
143
+ export function selectAll(rowCount, colCount) {
144
+ if (rowCount === 0 || colCount === 0)
145
+ return EMPTY_SELECTION;
146
+ return {
147
+ ranges: [{ anchor: { row: 0, col: 0 }, focus: { row: rowCount - 1, col: colCount - 1 } }],
148
+ active: { row: 0, col: 0 },
149
+ };
150
+ }
151
+ /** True when every row of `col` is inside the selection. */
152
+ export function isColumnSelected(state, col, rowCount) {
153
+ if (rowCount === 0)
154
+ return false;
155
+ return state.ranges.some((r) => {
156
+ const b = rangeBounds(r);
157
+ return b.minCol <= col && b.maxCol >= col && b.minRow === 0 && b.maxRow >= rowCount - 1;
158
+ });
159
+ }
160
+ /** True when every column of `row` is inside the selection. */
161
+ export function isRowSelected(state, row, colCount) {
162
+ if (colCount === 0)
163
+ return false;
164
+ return state.ranges.some((r) => {
165
+ const b = rangeBounds(r);
166
+ return b.minRow <= row && b.maxRow >= row && b.minCol === 0 && b.maxCol >= colCount - 1;
167
+ });
168
+ }
169
+ /**
170
+ * Move the active cell, clamped to the grid.
171
+ *
172
+ * `extend` stretches the current range instead of starting a new one, which is
173
+ * what shift-arrow does.
174
+ */
175
+ export function moveActive(state, to, rowCount, colCount, extend) {
176
+ if (rowCount === 0 || colCount === 0)
177
+ return EMPTY_SELECTION;
178
+ const cell = {
179
+ row: Math.min(Math.max(to.row, 0), rowCount - 1),
180
+ col: Math.min(Math.max(to.col, 0), colCount - 1),
181
+ };
182
+ return extend ? extendSelection(state, cell) : selectCell(cell);
183
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Column and selection statistics, and the column profile (from Loadr's grid
3
+ * and profile view). Pure.
4
+ *
5
+ * One pass, no sorting of the whole column: at 50k rows the grid computes these
6
+ * on a header menu opening or a selection change, so the cost has to stay linear
7
+ * and allocation-light.
8
+ */
9
+ export interface ColumnStats {
10
+ /** Values looked at, including NULLs. */
11
+ count: number;
12
+ nulls: number;
13
+ distinct: number;
14
+ min?: number | string;
15
+ max?: number | string;
16
+ sum?: number;
17
+ avg?: number;
18
+ /** True when every non-NULL value was a number. */
19
+ numeric: boolean;
20
+ }
21
+ export declare function computeStats(values: readonly unknown[]): ColumnStats;
22
+ export interface NumericSummary {
23
+ count: number;
24
+ sum: number;
25
+ avg: number;
26
+ min: number;
27
+ max: number;
28
+ }
29
+ /**
30
+ * Sum/avg over whatever in the selection parses as a number.
31
+ *
32
+ * Unlike `computeStats` this does coerce numeric strings, because a selection
33
+ * spans columns and a numeric column arriving as text should still add up.
34
+ */
35
+ export declare function numericSummary(values: readonly unknown[]): NumericSummary | null;
36
+ export declare function formatStatValue(value: number | string | undefined): string;
37
+ /** What the profile infers a column holds. */
38
+ export type ProfileKind = "numeric" | "text" | "boolean" | "date" | "null";
39
+ /** One column of a profile. */
40
+ export interface ColumnProfile {
41
+ name: string;
42
+ kind: ProfileKind;
43
+ count: number;
44
+ nulls: number;
45
+ distinct: number;
46
+ min?: number | string;
47
+ max?: number | string;
48
+ mean?: number;
49
+ median?: number;
50
+ /** The most frequent values, most frequent first, as a share of the non-NULL values. */
51
+ top: {
52
+ value: string;
53
+ count: number;
54
+ share: number;
55
+ }[];
56
+ }
57
+ /** A column's profile: counts, range, mean and median (numeric), and the top values. */
58
+ export declare function profileColumn(name: string, values: readonly unknown[], topCount?: number): ColumnProfile;
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Column and selection statistics, and the column profile (from Loadr's grid
3
+ * and profile view). Pure.
4
+ *
5
+ * One pass, no sorting of the whole column: at 50k rows the grid computes these
6
+ * on a header menu opening or a selection change, so the cost has to stay linear
7
+ * and allocation-light.
8
+ */
9
+ function asNumber(value) {
10
+ if (typeof value === "number")
11
+ return Number.isFinite(value) ? value : null;
12
+ if (typeof value === "string" && value.trim() !== "") {
13
+ const parsed = Number(value);
14
+ return Number.isFinite(parsed) ? parsed : null;
15
+ }
16
+ return null;
17
+ }
18
+ export function computeStats(values) {
19
+ let nulls = 0;
20
+ let numericCount = 0;
21
+ let nonNull = 0;
22
+ let sum = 0;
23
+ let numMin = Number.POSITIVE_INFINITY;
24
+ let numMax = Number.NEGATIVE_INFINITY;
25
+ let strMin;
26
+ let strMax;
27
+ const distinct = new Set();
28
+ for (const value of values) {
29
+ if (value === null || value === undefined) {
30
+ nulls++;
31
+ continue;
32
+ }
33
+ nonNull++;
34
+ const text = typeof value === "object" ? JSON.stringify(value) : String(value);
35
+ distinct.add(text);
36
+ const num = typeof value === "number" && Number.isFinite(value) ? value : null;
37
+ if (num !== null) {
38
+ numericCount++;
39
+ sum += num;
40
+ if (num < numMin)
41
+ numMin = num;
42
+ if (num > numMax)
43
+ numMax = num;
44
+ }
45
+ else {
46
+ if (strMin === undefined || text < strMin)
47
+ strMin = text;
48
+ if (strMax === undefined || text > strMax)
49
+ strMax = text;
50
+ }
51
+ }
52
+ const numeric = nonNull > 0 && numericCount === nonNull;
53
+ const stats = {
54
+ count: nulls + nonNull,
55
+ nulls,
56
+ distinct: distinct.size,
57
+ numeric,
58
+ };
59
+ if (numeric) {
60
+ stats.min = numMin;
61
+ stats.max = numMax;
62
+ stats.sum = sum;
63
+ stats.avg = sum / numericCount;
64
+ }
65
+ else {
66
+ stats.min = strMin;
67
+ stats.max = strMax;
68
+ }
69
+ return stats;
70
+ }
71
+ /**
72
+ * Sum/avg over whatever in the selection parses as a number.
73
+ *
74
+ * Unlike `computeStats` this does coerce numeric strings, because a selection
75
+ * spans columns and a numeric column arriving as text should still add up.
76
+ */
77
+ export function numericSummary(values) {
78
+ let count = 0;
79
+ let sum = 0;
80
+ let min = Number.POSITIVE_INFINITY;
81
+ let max = Number.NEGATIVE_INFINITY;
82
+ for (const value of values) {
83
+ const num = asNumber(value);
84
+ if (num === null)
85
+ continue;
86
+ count++;
87
+ sum += num;
88
+ if (num < min)
89
+ min = num;
90
+ if (num > max)
91
+ max = num;
92
+ }
93
+ if (count === 0)
94
+ return null;
95
+ return { count, sum, avg: sum / count, min, max };
96
+ }
97
+ export function formatStatValue(value) {
98
+ if (value === undefined)
99
+ return "";
100
+ if (typeof value === "number") {
101
+ return Number.isInteger(value)
102
+ ? value.toLocaleString()
103
+ : value.toLocaleString(undefined, { maximumFractionDigits: 4 });
104
+ }
105
+ return value.length > 40 ? `${value.slice(0, 40)}\u2026` : value;
106
+ }
107
+ function profileKind(values) {
108
+ let total = 0;
109
+ let nums = 0;
110
+ let bools = 0;
111
+ let dates = 0;
112
+ for (const v of values) {
113
+ if (v === null || v === undefined)
114
+ continue;
115
+ total++;
116
+ if (typeof v === "number")
117
+ nums++;
118
+ else if (typeof v === "boolean")
119
+ bools++;
120
+ else if (typeof v === "string") {
121
+ if (/^\d{4}-\d{2}-\d{2}/.test(v))
122
+ dates++;
123
+ else if (asNumber(v) !== null)
124
+ nums++;
125
+ }
126
+ }
127
+ if (total === 0)
128
+ return "null";
129
+ if (bools / total > 0.8)
130
+ return "boolean";
131
+ if (dates / total > 0.8)
132
+ return "date";
133
+ if (nums / total > 0.8)
134
+ return "numeric";
135
+ return "text";
136
+ }
137
+ /** A column's profile: counts, range, mean and median (numeric), and the top values. */
138
+ export function profileColumn(name, values, topCount = 5) {
139
+ const kind = profileKind(values);
140
+ const freq = new Map();
141
+ let nulls = 0;
142
+ for (const v of values) {
143
+ if (v === null || v === undefined) {
144
+ nulls++;
145
+ continue;
146
+ }
147
+ const text = typeof v === "object" ? JSON.stringify(v) : String(v);
148
+ freq.set(text, (freq.get(text) ?? 0) + 1);
149
+ }
150
+ const nonNull = values.length - nulls;
151
+ const profile = {
152
+ name,
153
+ kind,
154
+ count: values.length,
155
+ nulls,
156
+ distinct: freq.size,
157
+ top: [...freq.entries()]
158
+ .sort((a, b) => b[1] - a[1])
159
+ .slice(0, topCount)
160
+ .map(([value, count]) => ({ value, count, share: nonNull > 0 ? count / nonNull : 0 })),
161
+ };
162
+ if (kind === "numeric") {
163
+ const nums = [];
164
+ for (const v of values) {
165
+ const n = asNumber(v);
166
+ if (n !== null)
167
+ nums.push(n);
168
+ }
169
+ nums.sort((a, b) => a - b);
170
+ if (nums.length > 0) {
171
+ const mid = Math.floor(nums.length / 2);
172
+ profile.min = nums[0];
173
+ profile.max = nums[nums.length - 1];
174
+ profile.mean = nums.reduce((s, n) => s + n, 0) / nums.length;
175
+ profile.median =
176
+ nums.length % 2 === 0 ? ((nums[mid - 1] ?? 0) + (nums[mid] ?? 0)) / 2 : nums[mid];
177
+ }
178
+ }
179
+ else if (kind === "text" || kind === "date") {
180
+ const keys = [...freq.keys()].sort();
181
+ profile.min = keys[0];
182
+ profile.max = keys[keys.length - 1];
183
+ }
184
+ return profile;
185
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * `@calliopelabs/ui/workbench`: the pieces of an IDE-style tool that more
3
+ * than one Calliope AI product draws. Opt-in, like `./agent`: an app that
4
+ * has no file browser never loads it. Everything is host-driven: data comes
5
+ * in as props, every change goes out through a callback, nothing fetches.
6
+ * Styles come from the package preset (`@calliopelabs/ui/preset.css`).
7
+ */
8
+ export { canDrop, fileExtension, formatBytes, isWithin, joinPath, parentPath, parseDelimited, pathSegments, previewKindFor, sortFiles, type FileBranch, type FileItem, type FileKind, type FileSort, type FileSortKey, type FileView, type PreviewKind, type UploadState, } from "./model.js";
9
+ export { FILE_DRAG_TYPE, type MoveHandler } from "./dnd.js";
10
+ export { FileIcon, type FileIconProps } from "./FileIcon.js";
11
+ export { FileTree, type FileTreeProps } from "./FileTree.js";
12
+ export { FileList, type FileListProps, type FileViewProps } from "./FileList.js";
13
+ export { FileGrid, type FileGridProps } from "./FileGrid.js";
14
+ export { FileBrowser, type FileBrowserProps } from "./FileBrowser.js";
15
+ export { UploadDropzone, type UploadDropzoneProps, type UploadItem, type UploadRejection, } from "./UploadDropzone.js";
16
+ export { FilePreview, type FilePreviewContent, type FilePreviewProps } from "./FilePreview.js";
17
+ export { formatShortcut, isMacPlatform, matchesShortcut, parseShortcut, shortcutKeys, type KeyChord, } from "./keys.js";
18
+ export { KeyboardShortcutsDialog, ShortcutKeys, useRegisteredShortcuts, useShortcuts, type KeyboardShortcutsDialogProps, type ShortcutDefinition, type ShortcutEntry, type ShortcutKeysProps, } from "./Shortcuts.js";
19
+ export { fuzzyScore, rankItems, type PaletteMatchable } from "./palette.js";
20
+ export { CommandPalette, type CommandPaletteProps, type PaletteItem } from "./CommandPalette.js";
21
+ export { MenuBar, type MenuBarProps, type MenuEntry, type WorkbenchMenu } from "./MenuBar.js";
22
+ export { ActivityBar, type ActivityBarProps, type ActivityItem } from "./ActivityBar.js";
23
+ export { EditorGroup, EditorTabs, editorTabId, type EditorGroupProps, type EditorTab, type EditorTabsProps, } from "./EditorTabs.js";
24
+ export { Pane, PaneGroup, resolvePaneSizes, type PaneGroupProps, type PaneProps, type PaneSize, } from "./PaneGroup.js";
25
+ export { BottomPanel, type BottomPanelProps, type BottomPanelView } from "./BottomPanel.js";
26
+ export { StatusBar, StatusBarItem, type StatusBarItemProps, type StatusBarProps, type StatusBarTone, } from "./StatusBar.js";
27
+ export { WorkbenchShell, type WorkbenchShellProps } from "./WorkbenchShell.js";
28
+ export { COLUMN_TYPES, asBinary, buildColumnMeta, cellText, columnSignature, compareCells, isNumericType, normalizeColumnType, sniffColumnType, viewRowIndexes, type BinaryCell, type ColumnType, type GridColumn, type GridColumnMeta, type GridRow, type GridSort, type SortDirection, } from "./grid-model.js";
29
+ export { EMPTY_SELECTION, extendSelection, isSelected, moveActive, selectAll, selectCell, selectColumn, selectRow, selectionBounds, selectionSize, toggleCell, type CellRef, type SelectionRange, type SelectionState, } from "./grid-selection.js";
30
+ export { EXPORT_FORMATS, exportBlob, exportMatrix, formatMatrix, quoteIdentifier, rowsMatrix, selectionMatrix, sqlLiteral, toCSV, toInsert, toJSON, toJSONL, toMarkdown, toTSV, type CellMatrix, type CopyFormat, type ExportFile, type ExportFormat, } from "./grid-format.js";
31
+ export { computeStats, formatStatValue, numericSummary, profileColumn, type ColumnProfile, type ColumnStats, type NumericSummary, type ProfileKind, } from "./grid-stats.js";
32
+ export { NO_CHANGES, addRow, changeSetToSql, deleteRows, editCell, insertedKeys, isCellChanged, parseCellInput, pendingCounts, pendingValue, revertRow, toChangeSet, type ChangeSet, type ChangeSetDelete, type ChangeSetInsert, type ChangeSetUpdate, type PendingChanges, type PendingCounts, type PendingRow, type PendingState, } from "./pending.js";
33
+ export { downloadBase64, downloadBlob, downloadExport } from "./download.js";
34
+ export { ColumnKeyIcons, ColumnTypeIcon, GridCellValue, type ColumnKeyIconsProps, type ColumnTypeIconProps, type GridCellValueProps, } from "./GridCell.js";
35
+ export { TruncationBanner, type TruncationBannerProps } from "./TruncationBanner.js";
36
+ export { CellDetailDialog, RowDetailDrawer, type CellDetailDialogProps, type RowDetailDrawerProps, } from "./GridDetails.js";
37
+ export { PendingChangesBar, type PendingChangesBarProps } from "./PendingChangesBar.js";
38
+ export { DataGrid, type DataGridProps, type GridCommitError, type GridCopyEvent, type GridExportOption, type GridExportRequest, } from "./DataGrid.js";
39
+ export { DataProfile, type DataProfileProps } from "./DataProfile.js";
40
+ export { DataChart, type ChartKind, type ChartLibrary, type DataChartProps } from "./DataChart.js";
41
+ export { CodeEditor, configureMonaco, type CodeEditorProps, type MonacoApi, type MonacoEditor, } from "./CodeEditor.js";
42
+ export { SqlEditor, type SqlEditorProps } from "./SqlEditor.js";
43
+ export { ambiguousColumns, extractTableRefs, isDdlStatement, resolveSqlDot, sqlCompletions, sqlCursorContext, sqlMatch, statementAt, SQL_FUNCTIONS, SQL_KEYWORDS, type SqlColumn, type SqlCompletion, type SqlCompletionKind, type SqlCompletionResult, type SqlCursorContext, type SqlDotTarget, type SqlSchema, type SqlSchemaRequest, type SqlTable, type SqlTableRef, } from "./sql-completion.js";
44
+ export { cssColorToHex, editorTheme, readEditorPalette, type EditorPalette, type EditorThemeData, } from "./editor-theme.js";
@@ -0,0 +1,47 @@
1
+ /**
2
+ * `@calliopelabs/ui/workbench`: the pieces of an IDE-style tool that more
3
+ * than one Calliope AI product draws. Opt-in, like `./agent`: an app that
4
+ * has no file browser never loads it. Everything is host-driven: data comes
5
+ * in as props, every change goes out through a callback, nothing fetches.
6
+ * Styles come from the package preset (`@calliopelabs/ui/preset.css`).
7
+ */
8
+ export { canDrop, fileExtension, formatBytes, isWithin, joinPath, parentPath, parseDelimited, pathSegments, previewKindFor, sortFiles, } from "./model.js";
9
+ export { FILE_DRAG_TYPE } from "./dnd.js";
10
+ export { FileIcon } from "./FileIcon.js";
11
+ export { FileTree } from "./FileTree.js";
12
+ export { FileList } from "./FileList.js";
13
+ export { FileGrid } from "./FileGrid.js";
14
+ export { FileBrowser } from "./FileBrowser.js";
15
+ export { UploadDropzone, } from "./UploadDropzone.js";
16
+ export { FilePreview } from "./FilePreview.js";
17
+ // The IDE shell.
18
+ export { formatShortcut, isMacPlatform, matchesShortcut, parseShortcut, shortcutKeys, } from "./keys.js";
19
+ export { KeyboardShortcutsDialog, ShortcutKeys, useRegisteredShortcuts, useShortcuts, } from "./Shortcuts.js";
20
+ export { fuzzyScore, rankItems } from "./palette.js";
21
+ export { CommandPalette } from "./CommandPalette.js";
22
+ export { MenuBar } from "./MenuBar.js";
23
+ export { ActivityBar } from "./ActivityBar.js";
24
+ export { EditorGroup, EditorTabs, editorTabId, } from "./EditorTabs.js";
25
+ export { Pane, PaneGroup, resolvePaneSizes, } from "./PaneGroup.js";
26
+ export { BottomPanel } from "./BottomPanel.js";
27
+ export { StatusBar, StatusBarItem, } from "./StatusBar.js";
28
+ export { WorkbenchShell } from "./WorkbenchShell.js";
29
+ // The data grid, profile and chart.
30
+ export { COLUMN_TYPES, asBinary, buildColumnMeta, cellText, columnSignature, compareCells, isNumericType, normalizeColumnType, sniffColumnType, viewRowIndexes, } from "./grid-model.js";
31
+ export { EMPTY_SELECTION, extendSelection, isSelected, moveActive, selectAll, selectCell, selectColumn, selectRow, selectionBounds, selectionSize, toggleCell, } from "./grid-selection.js";
32
+ export { EXPORT_FORMATS, exportBlob, exportMatrix, formatMatrix, quoteIdentifier, rowsMatrix, selectionMatrix, sqlLiteral, toCSV, toInsert, toJSON, toJSONL, toMarkdown, toTSV, } from "./grid-format.js";
33
+ export { computeStats, formatStatValue, numericSummary, profileColumn, } from "./grid-stats.js";
34
+ export { NO_CHANGES, addRow, changeSetToSql, deleteRows, editCell, insertedKeys, isCellChanged, parseCellInput, pendingCounts, pendingValue, revertRow, toChangeSet, } from "./pending.js";
35
+ export { downloadBase64, downloadBlob, downloadExport } from "./download.js";
36
+ export { ColumnKeyIcons, ColumnTypeIcon, GridCellValue, } from "./GridCell.js";
37
+ export { TruncationBanner } from "./TruncationBanner.js";
38
+ export { CellDetailDialog, RowDetailDrawer, } from "./GridDetails.js";
39
+ export { PendingChangesBar } from "./PendingChangesBar.js";
40
+ export { DataGrid, } from "./DataGrid.js";
41
+ export { DataProfile } from "./DataProfile.js";
42
+ export { DataChart } from "./DataChart.js";
43
+ // The code and SQL editors (Monaco, an optional peer the host loads).
44
+ export { CodeEditor, configureMonaco, } from "./CodeEditor.js";
45
+ export { SqlEditor } from "./SqlEditor.js";
46
+ export { ambiguousColumns, extractTableRefs, isDdlStatement, resolveSqlDot, sqlCompletions, sqlCursorContext, sqlMatch, statementAt, SQL_FUNCTIONS, SQL_KEYWORDS, } from "./sql-completion.js";
47
+ export { cssColorToHex, editorTheme, readEditorPalette, } from "./editor-theme.js";
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Keyboard chords as strings: `"Mod+K"`, `"Mod+Shift+A"`, `"Alt+ArrowLeft"`,
3
+ * `"F2"`. `Mod` is Command on a Mac and Control elsewhere, so one binding
4
+ * serves both. Pure: parsing, matching and display, no listeners.
5
+ */
6
+ export interface KeyChord {
7
+ /** The key, as `KeyboardEvent.key` names it, lowercased for letters. */
8
+ key: string;
9
+ mod: boolean;
10
+ ctrl: boolean;
11
+ meta: boolean;
12
+ alt: boolean;
13
+ shift: boolean;
14
+ }
15
+ export declare function parseShortcut(shortcut: string): KeyChord;
16
+ export declare function isMacPlatform(): boolean;
17
+ type KeyEventLike = Pick<KeyboardEvent, "key" | "code" | "ctrlKey" | "metaKey" | "altKey" | "shiftKey">;
18
+ export declare function matchesShortcut(event: KeyEventLike, shortcut: string | KeyChord, isMac?: boolean): boolean;
19
+ /** The keys of a chord as they are drawn: `["⌘", "K"]` on a Mac, `["Ctrl", "K"]` elsewhere. */
20
+ export declare function shortcutKeys(shortcut: string, isMac?: boolean): string[];
21
+ /** One string for a menu or a tooltip: `"⌘K"` on a Mac, `"Ctrl+K"` elsewhere. */
22
+ export declare function formatShortcut(shortcut: string, isMac?: boolean): string;
23
+ export {};