@lapis-notes/bases 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 (155) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE.md +8 -0
  3. package/README.md +20 -0
  4. package/dist/bases-plugin.d.ts +10 -0
  5. package/dist/bases-plugin.js +118 -0
  6. package/dist/bases-view/app-database-query-source.d.ts +30 -0
  7. package/dist/bases-view/app-database-query-source.js +248 -0
  8. package/dist/bases-view/bases.svelte.d.ts +569 -0
  9. package/dist/bases-view/bases.svelte.js +910 -0
  10. package/dist/bases-view/card-view/components/card-placeholder.svelte +68 -0
  11. package/dist/bases-view/card-view/components/card-placeholder.svelte.d.ts +7 -0
  12. package/dist/bases-view/card-view/components/card.svelte +289 -0
  13. package/dist/bases-view/card-view/components/card.svelte.d.ts +7 -0
  14. package/dist/bases-view/card-view/index.d.ts +11 -0
  15. package/dist/bases-view/card-view/index.js +55 -0
  16. package/dist/bases-view/cell-editor-options.d.ts +2 -0
  17. package/dist/bases-view/cell-editor-options.js +26 -0
  18. package/dist/bases-view/cell-editor.svelte +206 -0
  19. package/dist/bases-view/cell-editor.svelte.d.ts +12 -0
  20. package/dist/bases-view/cell.svelte +132 -0
  21. package/dist/bases-view/cell.svelte.d.ts +16 -0
  22. package/dist/bases-view/column-definition.d.ts +22 -0
  23. package/dist/bases-view/column-definition.js +149 -0
  24. package/dist/bases-view/columns.d.ts +15 -0
  25. package/dist/bases-view/columns.js +103 -0
  26. package/dist/bases-view/components/Tag.svelte +14 -0
  27. package/dist/bases-view/components/Tag.svelte.d.ts +8 -0
  28. package/dist/bases-view/components/autocomplete.svelte +45 -0
  29. package/dist/bases-view/components/autocomplete.svelte.d.ts +17 -0
  30. package/dist/bases-view/components/card-image.svelte +121 -0
  31. package/dist/bases-view/components/card-image.svelte.d.ts +11 -0
  32. package/dist/bases-view/components/column-visibility.svelte +388 -0
  33. package/dist/bases-view/components/column-visibility.svelte.d.ts +13 -0
  34. package/dist/bases-view/components/datetime.svelte +35 -0
  35. package/dist/bases-view/components/datetime.svelte.d.ts +7 -0
  36. package/dist/bases-view/components/file.svelte +31 -0
  37. package/dist/bases-view/components/file.svelte.d.ts +8 -0
  38. package/dist/bases-view/components/filters/filter-editor.svelte +102 -0
  39. package/dist/bases-view/components/filters/filter-editor.svelte.d.ts +10 -0
  40. package/dist/bases-view/components/filters/filter-group.svelte +142 -0
  41. package/dist/bases-view/components/filters/filter-group.svelte.d.ts +11 -0
  42. package/dist/bases-view/components/filters/filter-properties.svelte +77 -0
  43. package/dist/bases-view/components/filters/filter-properties.svelte.d.ts +8 -0
  44. package/dist/bases-view/components/filters/filter-root.svelte +112 -0
  45. package/dist/bases-view/components/filters/filter-root.svelte.d.ts +12 -0
  46. package/dist/bases-view/components/filters/filter-row.svelte +351 -0
  47. package/dist/bases-view/components/filters/filter-row.svelte.d.ts +11 -0
  48. package/dist/bases-view/components/group/group-root.svelte +120 -0
  49. package/dist/bases-view/components/group/group-root.svelte.d.ts +8 -0
  50. package/dist/bases-view/components/limit.svelte +100 -0
  51. package/dist/bases-view/components/limit.svelte.d.ts +12 -0
  52. package/dist/bases-view/components/query-editor.svelte +230 -0
  53. package/dist/bases-view/components/query-editor.svelte.d.ts +15 -0
  54. package/dist/bases-view/components/sort/sort-direction-labels.d.ts +9 -0
  55. package/dist/bases-view/components/sort/sort-direction-labels.js +25 -0
  56. package/dist/bases-view/components/sort/sort-root.svelte +239 -0
  57. package/dist/bases-view/components/sort/sort-root.svelte.d.ts +11 -0
  58. package/dist/bases-view/components/sort/sort-row.svelte +190 -0
  59. package/dist/bases-view/components/sort/sort-row.svelte.d.ts +15 -0
  60. package/dist/bases-view/components/summary-strip.svelte +56 -0
  61. package/dist/bases-view/components/summary-strip.svelte.d.ts +8 -0
  62. package/dist/bases-view/components/tag-chip.svelte +47 -0
  63. package/dist/bases-view/components/tag-chip.svelte.d.ts +12 -0
  64. package/dist/bases-view/components/views.svelte +178 -0
  65. package/dist/bases-view/components/views.svelte.d.ts +12 -0
  66. package/dist/bases-view/data-table-adapter/data-table.svelte.d.ts +45 -0
  67. package/dist/bases-view/data-table-adapter/data-table.svelte.js +112 -0
  68. package/dist/bases-view/data-table-adapter/flex-render.svelte +43 -0
  69. package/dist/bases-view/data-table-adapter/flex-render.svelte.d.ts +30 -0
  70. package/dist/bases-view/data-table-adapter/index.d.ts +3 -0
  71. package/dist/bases-view/data-table-adapter/index.js +3 -0
  72. package/dist/bases-view/data-table-adapter/render-helpers.d.ts +101 -0
  73. package/dist/bases-view/data-table-adapter/render-helpers.js +110 -0
  74. package/dist/bases-view/db.d.ts +31 -0
  75. package/dist/bases-view/db.js +174 -0
  76. package/dist/bases-view/document-core.d.ts +2 -0
  77. package/dist/bases-view/document-core.js +166 -0
  78. package/dist/bases-view/export-core.d.ts +4 -0
  79. package/dist/bases-view/export-core.js +31 -0
  80. package/dist/bases-view/file-fields-core.d.ts +31 -0
  81. package/dist/bases-view/file-fields-core.js +114 -0
  82. package/dist/bases-view/filter-parser.d.ts +27 -0
  83. package/dist/bases-view/filter-parser.js +315 -0
  84. package/dist/bases-view/functions-core.d.ts +66 -0
  85. package/dist/bases-view/functions-core.js +265 -0
  86. package/dist/bases-view/functions.d.ts +5 -0
  87. package/dist/bases-view/functions.js +107 -0
  88. package/dist/bases-view/fuzzy-search.d.ts +6 -0
  89. package/dist/bases-view/fuzzy-search.js +15 -0
  90. package/dist/bases-view/hooks/useResizeObserver.svelte.d.ts +7 -0
  91. package/dist/bases-view/hooks/useResizeObserver.svelte.js +26 -0
  92. package/dist/bases-view/index.d.ts +66 -0
  93. package/dist/bases-view/index.js +231 -0
  94. package/dist/bases-view/list-view/index.d.ts +10 -0
  95. package/dist/bases-view/list-view/index.js +17 -0
  96. package/dist/bases-view/list-view/list.svelte +156 -0
  97. package/dist/bases-view/list-view/list.svelte.d.ts +7 -0
  98. package/dist/bases-view/map-view/index.d.ts +10 -0
  99. package/dist/bases-view/map-view/index.js +17 -0
  100. package/dist/bases-view/map-view/view.svelte +28 -0
  101. package/dist/bases-view/map-view/view.svelte.d.ts +7 -0
  102. package/dist/bases-view/metadata-invalidation-core.d.ts +34 -0
  103. package/dist/bases-view/metadata-invalidation-core.js +162 -0
  104. package/dist/bases-view/metadata-type-info.d.ts +7 -0
  105. package/dist/bases-view/metadata-type-info.js +10 -0
  106. package/dist/bases-view/models.d.ts +90 -0
  107. package/dist/bases-view/models.js +133 -0
  108. package/dist/bases-view/query-result-core.d.ts +8 -0
  109. package/dist/bases-view/query-result-core.js +16 -0
  110. package/dist/bases-view/resource-url.d.ts +2 -0
  111. package/dist/bases-view/resource-url.js +21 -0
  112. package/dist/bases-view/search-core.d.ts +9 -0
  113. package/dist/bases-view/search-core.js +20 -0
  114. package/dist/bases-view/summary-core.d.ts +7 -0
  115. package/dist/bases-view/summary-core.js +17 -0
  116. package/dist/bases-view/table-view/components/div-table.svelte +464 -0
  117. package/dist/bases-view/table-view/components/div-table.svelte.d.ts +32 -0
  118. package/dist/bases-view/table-view/components/dnd-style.d.ts +3 -0
  119. package/dist/bases-view/table-view/components/dnd-style.js +6 -0
  120. package/dist/bases-view/table-view/components/sort-header.svelte +48 -0
  121. package/dist/bases-view/table-view/components/sort-header.svelte.d.ts +11 -0
  122. package/dist/bases-view/table-view/components/table-column-tracks.d.ts +14 -0
  123. package/dist/bases-view/table-view/components/table-column-tracks.js +27 -0
  124. package/dist/bases-view/table-view/components/table-header.svelte +146 -0
  125. package/dist/bases-view/table-view/components/table-header.svelte.d.ts +10 -0
  126. package/dist/bases-view/table-view/components/table-placeholder.svelte +46 -0
  127. package/dist/bases-view/table-view/components/table-placeholder.svelte.d.ts +30 -0
  128. package/dist/bases-view/table-view/components/table-virtualizer-core.d.ts +13 -0
  129. package/dist/bases-view/table-view/components/table-virtualizer-core.js +12 -0
  130. package/dist/bases-view/table-view/components/table.svelte +997 -0
  131. package/dist/bases-view/table-view/components/table.svelte.d.ts +32 -0
  132. package/dist/bases-view/table-view/index.svelte.d.ts +10 -0
  133. package/dist/bases-view/table-view/index.svelte.js +30 -0
  134. package/dist/bases-view/unknown-view/index.d.ts +10 -0
  135. package/dist/bases-view/unknown-view/index.js +19 -0
  136. package/dist/bases-view/unknown-view/view.svelte +11 -0
  137. package/dist/bases-view/unknown-view/view.svelte.d.ts +6 -0
  138. package/dist/bases-view/view-header.svelte +142 -0
  139. package/dist/bases-view/view-header.svelte.d.ts +28 -0
  140. package/dist/bases-view/view-registration-inventory.d.ts +22 -0
  141. package/dist/bases-view/view-registration-inventory.js +7 -0
  142. package/dist/bases-view/view-settings.svelte +350 -0
  143. package/dist/bases-view/view-settings.svelte.d.ts +9 -0
  144. package/dist/bases-view/view.svelte +192 -0
  145. package/dist/bases-view/view.svelte.d.ts +15 -0
  146. package/dist/bases-view-surface.svelte +31 -0
  147. package/dist/bases-view-surface.svelte.d.ts +14 -0
  148. package/dist/index.d.ts +10 -0
  149. package/dist/index.js +8 -0
  150. package/dist/serialized-write-queue.d.ts +10 -0
  151. package/dist/serialized-write-queue.js +36 -0
  152. package/dist/styles.css +2164 -0
  153. package/manifest.json +33 -0
  154. package/package.json +90 -0
  155. package/styles.css +1 -0
@@ -0,0 +1,997 @@
1
+ <script lang="ts" generics="TData, TValue">
2
+ import {
3
+ getCoreRowModel,
4
+ getSortedRowModel,
5
+ type ColumnDef,
6
+ type ColumnOrderState,
7
+ type ColumnSizingInfoState,
8
+ type ColumnSizingState,
9
+ type Header,
10
+ type VisibilityState,
11
+ } from "@tanstack/table-core";
12
+ import TableHeader from "./table-header.svelte";
13
+ import { DragDropProvider } from "@dnd-kit/svelte";
14
+ import type { DragEndEvent } from "@dnd-kit/dom";
15
+ import { arrayMove } from "@dnd-kit/helpers";
16
+ import { createVirtualizer, type MetadataType } from "@lapis-notes/api";
17
+ import Cell from "../../cell.svelte";
18
+ import {
19
+ BasesEntry,
20
+ type BasesPropertyId,
21
+ type BasesView,
22
+ type QueryController,
23
+ } from "../../bases.svelte";
24
+ import {
25
+ createSvelteTable,
26
+ renderComponent,
27
+ } from "../../data-table-adapter";
28
+ import ChevronDown from "@lucide/svelte/icons/chevron-down";
29
+ import ChevronRight from "@lucide/svelte/icons/chevron-right";
30
+ import type { SortColumn } from "../../models";
31
+ import { getMetadataTypeInfo } from "../../metadata-type-info";
32
+ import {
33
+ formatSummaryLabel,
34
+ resolveConfiguredSummaries,
35
+ } from "../../summary-core";
36
+ import SortHeader from "./sort-header.svelte";
37
+ import { resolveVirtualTotalSize } from "./table-virtualizer-core";
38
+ import * as ScrollArea from "@lapismd/design-core/shadcn/scroll-area";
39
+ import { onDestroy, onMount, untrack } from "svelte";
40
+ import TablePlaceholder from "./table-placeholder.svelte";
41
+ import { useResizeObserver } from "../../hooks/useResizeObserver.svelte";
42
+ import { resolveTableColumnTracks } from "./table-column-tracks";
43
+
44
+ type DataTableProps = {
45
+ view: BasesView;
46
+ };
47
+
48
+ type GroupConfig = {
49
+ property: BasesPropertyId;
50
+ direction: "ASC" | "DESC";
51
+ };
52
+
53
+ type TableDisplayItem =
54
+ | {
55
+ kind: "group";
56
+ key: string;
57
+ label: string;
58
+ value: string;
59
+ collapsed: boolean;
60
+ }
61
+ | {
62
+ kind: "row";
63
+ key: string;
64
+ row: BasesEntry;
65
+ };
66
+
67
+ type GroupSection = {
68
+ key: string;
69
+ label: string;
70
+ value: string;
71
+ collapsed: boolean;
72
+ start: number;
73
+ };
74
+
75
+ let { view }: DataTableProps = $props();
76
+
77
+ let queryResults = $derived(view.data);
78
+
79
+ let columnSizingInfo: ColumnSizingInfoState = $state({
80
+ columnSizingStart: [],
81
+ deltaOffset: null,
82
+ deltaPercentage: null,
83
+ isResizingColumn: false,
84
+ startOffset: null,
85
+ startSize: null,
86
+ });
87
+
88
+ let types = $derived.by(() => {
89
+ return queryResults.properties
90
+ .filter((it) => it.startsWith("note."))
91
+ .reduce<Record<string, { type: MetadataType; icon: string }>>(
92
+ (acc, id) => {
93
+ const key = id.substring(5);
94
+ const { type, icon } = getMetadataTypeInfo(
95
+ key,
96
+ "text",
97
+ view.controller.app,
98
+ );
99
+
100
+ acc[id] = { type, icon };
101
+ return acc;
102
+ },
103
+ {},
104
+ );
105
+ });
106
+
107
+ const FILE_ICONS: Record<string, string> = {
108
+ file: "lucide-file",
109
+ "file.name": "lucide-text",
110
+ "file.basename": "lucide-text",
111
+ "file.fullname": "lucide-text",
112
+ "file.folder": "lucide-text",
113
+ "file.path": "lucide-text",
114
+ "file.ext": "lucide-text",
115
+ "file.ctime": "lucide-clock",
116
+ "file.mtime": "lucide-clock",
117
+ "file.size": "lucide-binary",
118
+ "file.tags": "lucide-tags",
119
+ };
120
+
121
+ function getIcon(id: BasesPropertyId) {
122
+ if (id.startsWith("formula.")) {
123
+ return "lucide-square-function";
124
+ } else if (id.startsWith("file.")) {
125
+ return FILE_ICONS[id] || "lucide-file";
126
+ }
127
+ return types[id]?.icon || "lucide-file";
128
+ }
129
+
130
+ const MIN_COLUMN_WIDTH = 120;
131
+ const DEFAULT_COLUMN_WIDTH = 300;
132
+ const HEADER_PADDING_WIDTH = 96;
133
+ const CELL_PADDING_WIDTH = 24;
134
+ const GROUP_HEADER_HEIGHT = 44;
135
+ const ACTIVE_SEARCH_HEIGHT = 36;
136
+
137
+ export function estimateTextWidth(
138
+ text: string,
139
+ font: string = '20px ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
140
+ ): number {
141
+ if (!text) return 0;
142
+ // Reuse a single offscreen canvas for performance
143
+ const canvas: HTMLCanvasElement =
144
+ (estimateTextWidth as any)._canvas ||
145
+ ((estimateTextWidth as any)._canvas = document.createElement("canvas"));
146
+ const context = canvas.getContext("2d");
147
+ if (!context) throw new Error("2D context not available on this browser.");
148
+
149
+ context.font = font;
150
+ const metrics = context.measureText(text);
151
+ return metrics.width;
152
+ }
153
+
154
+ let columnSizing = $derived(
155
+ (view.config.get("columnSize") || {}) as ColumnSizingState,
156
+ );
157
+
158
+ let intrinsicWidths: Record<string, number> = $derived.by(() => {
159
+ const sizes: Record<string, number> = {};
160
+ const order = view.config.getOrder();
161
+
162
+ for (const id of order) {
163
+ const label = view.config.getDisplayName(id as BasesPropertyId) || id;
164
+ sizes[id] = Math.min(
165
+ DEFAULT_COLUMN_WIDTH,
166
+ Math.max(
167
+ MIN_COLUMN_WIDTH,
168
+ Math.round(estimateTextWidth(label) + HEADER_PADDING_WIDTH),
169
+ ),
170
+ );
171
+ }
172
+
173
+ for (const row of queryResults.data) {
174
+ for (const id of order) {
175
+ if (sizes[id] === DEFAULT_COLUMN_WIDTH) continue;
176
+ const value = row.getValue(id)?.value?.toString();
177
+ if (!value) continue;
178
+ const size = Math.round(estimateTextWidth(value) + CELL_PADDING_WIDTH);
179
+ sizes[id] = Math.min(
180
+ DEFAULT_COLUMN_WIDTH,
181
+ Math.max(sizes[id] || MIN_COLUMN_WIDTH, size, MIN_COLUMN_WIDTH),
182
+ );
183
+ }
184
+ }
185
+
186
+ return sizes;
187
+ });
188
+
189
+ let containerSize = useResizeObserver();
190
+ let resolvedWidths: Record<string, number> = $derived.by(() => {
191
+ const order = view.config.getOrder();
192
+ const sizes = Object.fromEntries(
193
+ order.map((id) => [
194
+ id,
195
+ columnSizing[id] ?? intrinsicWidths[id] ?? DEFAULT_COLUMN_WIDTH,
196
+ ]),
197
+ ) as Record<string, number>;
198
+
199
+ if (!order.length) {
200
+ return sizes;
201
+ }
202
+
203
+ const availableWidth = containerSize.size.width;
204
+ const totalWidth = order.reduce(
205
+ (sum, id) => sum + (sizes[id] ?? DEFAULT_COLUMN_WIDTH),
206
+ 0,
207
+ );
208
+ const extraWidth = Math.max(0, availableWidth - totalWidth);
209
+
210
+ if (extraWidth > 0) {
211
+ const lastColumnId = order[order.length - 1];
212
+ sizes[lastColumnId] =
213
+ (sizes[lastColumnId] ?? DEFAULT_COLUMN_WIDTH) + extraWidth;
214
+ }
215
+
216
+ return sizes;
217
+ });
218
+
219
+ let columns: Array<ColumnDef<BasesEntry, any>> = $derived.by(() => {
220
+ return view.allProperties.map((id) => {
221
+ return {
222
+ id: id,
223
+ accessorKey: id,
224
+ size: resolvedWidths[id] ?? DEFAULT_COLUMN_WIDTH,
225
+ accessorFn: (row) => {
226
+ return row.getValue(id);
227
+ },
228
+ header: ({ column }) => {
229
+ return renderComponent(SortHeader, {
230
+ text: view.config.getDisplayName(id),
231
+ icon: getIcon(id),
232
+ direction: column.getIsSorted(),
233
+ onclick: column.getToggleSortingHandler(),
234
+ });
235
+ },
236
+ };
237
+ });
238
+ });
239
+
240
+ let columnOrder = $derived(view.config.getOrder());
241
+ let summaries = $derived.by(() => {
242
+ return resolveConfiguredSummaries(
243
+ view.config.getOrder(),
244
+ view.controller.doc.summaries,
245
+ view.config.get("summaries") as Record<string, string> | undefined,
246
+ ).map(({ propertyId, summaryKey }) => ({
247
+ propertyId,
248
+ label: formatSummaryLabel(summaryKey),
249
+ value: queryResults
250
+ .getSummaryValue(
251
+ view.controller,
252
+ queryResults.data,
253
+ propertyId as BasesPropertyId,
254
+ summaryKey,
255
+ )
256
+ .toString(),
257
+ }));
258
+ });
259
+ let summaryMap = $derived.by(() => {
260
+ return summaries.reduce<Record<string, { label: string; value: string }>>(
261
+ (acc, summary) => {
262
+ acc[summary.propertyId] = {
263
+ label: summary.label,
264
+ value: summary.value,
265
+ };
266
+ return acc;
267
+ },
268
+ {},
269
+ );
270
+ });
271
+
272
+ const table = createSvelteTable({
273
+ get data() {
274
+ return queryResults.data;
275
+ },
276
+ get columns() {
277
+ return columns;
278
+ },
279
+ defaultColumn: {
280
+ minSize: 30,
281
+ size: 300,
282
+ maxSize: 800,
283
+ },
284
+ manualPagination: true,
285
+ manualSorting: true,
286
+ columnResizeMode: "onChange",
287
+ enableSortingRemoval: true,
288
+ isMultiSortEvent: (e) => true,
289
+ getCoreRowModel: getCoreRowModel(),
290
+ getSortedRowModel: getSortedRowModel(),
291
+ onSortingChange: (updater) => {
292
+ let sorting = view.config.getSort().map((s) => ({
293
+ id: s.property as string,
294
+ desc: s.direction === "DESC",
295
+ }));
296
+ if (typeof updater === "function") {
297
+ sorting = updater(sorting);
298
+ } else {
299
+ sorting = updater;
300
+ }
301
+ view.config.set(
302
+ "sort",
303
+ sorting.map((s) => ({
304
+ property: s.id,
305
+ direction: s.desc ? "DESC" : "ASC",
306
+ })) as Array<SortColumn>,
307
+ );
308
+ },
309
+ onColumnVisibilityChange: (updater) => {
310
+ let columnVisibility: VisibilityState = columns.reduce<VisibilityState>(
311
+ (acc, value) => {
312
+ const id = value.id as BasesPropertyId;
313
+ if (id) {
314
+ acc[id] = view.config.getOrder().includes(id);
315
+ }
316
+ return acc;
317
+ },
318
+ {},
319
+ );
320
+ if (typeof updater === "function") {
321
+ columnVisibility = updater(columnVisibility);
322
+ } else {
323
+ columnVisibility = updater;
324
+ }
325
+ const order: string[] = [];
326
+ view.config.getOrder().forEach((id) => {
327
+ if (columnVisibility[id]) {
328
+ order.push(id);
329
+ }
330
+ });
331
+ const newColumns = Object.keys(columnVisibility).filter(
332
+ (k) => columnVisibility[k] && !order.includes(k),
333
+ );
334
+ view.config.set("order", [...order, ...newColumns]);
335
+ },
336
+ onColumnSizingInfoChange: (updater) => {
337
+ if (typeof updater === "function") {
338
+ columnSizingInfo = updater(columnSizingInfo);
339
+ } else {
340
+ columnSizingInfo = updater;
341
+ }
342
+ },
343
+ onColumnSizingChange: (updater) => {
344
+ let columnSizing: ColumnSizingState = {
345
+ ...(view.config.get("columnSize") || {}),
346
+ };
347
+ if (typeof updater === "function") {
348
+ columnSizing = updater(columnSizing);
349
+ } else {
350
+ columnSizing = updater;
351
+ }
352
+ view.config.set("columnSize", columnSizing);
353
+ },
354
+ onColumnOrderChange: (updater) => {
355
+ let columnOrder: ColumnOrderState = [...view.config.getOrder()];
356
+ if (typeof updater === "function") {
357
+ columnOrder = updater(columnOrder);
358
+ } else {
359
+ columnOrder = updater;
360
+ }
361
+ view.config.set("order", columnOrder);
362
+ },
363
+ state: {
364
+ get sorting() {
365
+ return view.config
366
+ .getSort()
367
+ .map((s) => ({ id: s.property, desc: s.direction === "DESC" }));
368
+ },
369
+ get columnSizingInfo() {
370
+ return columnSizingInfo;
371
+ },
372
+ get columnSizing() {
373
+ return columnSizing;
374
+ },
375
+ get columnVisibility() {
376
+ return columns.reduce<VisibilityState>((acc, value) => {
377
+ const id = value.id as BasesPropertyId;
378
+ if (id) {
379
+ acc[id] = view.config.getOrder().includes(id);
380
+ }
381
+ return acc;
382
+ }, {});
383
+ },
384
+ get columnOrder() {
385
+ return columnOrder;
386
+ },
387
+ },
388
+ });
389
+
390
+ function handleDragEnd(event: DragEndEvent) {
391
+ const active = event.operation.source;
392
+ const over = event.operation.target;
393
+ if (active && over && active.id !== over.id) {
394
+ const oldIndex = view.config
395
+ .getOrder()
396
+ .indexOf(active.id as BasesPropertyId);
397
+ const newIndex = view.config
398
+ .getOrder()
399
+ .indexOf(over.id as BasesPropertyId);
400
+ view.config.set(
401
+ "order",
402
+ arrayMove(view.config.getOrder(), oldIndex, newIndex),
403
+ );
404
+ }
405
+ }
406
+
407
+ const rowHeights: Record<string, number> = {
408
+ short: 30,
409
+ medium: 60,
410
+ tall: 120,
411
+ extra: 240,
412
+ };
413
+ let rowHeight: number = $derived(
414
+ rowHeights[view.config.get("rowHeight") as string] ?? 30,
415
+ );
416
+ let groupBy = $derived(view.config.get("groupBy") as GroupConfig | undefined);
417
+ let collapsedGroups = $state<Record<string, boolean>>({});
418
+
419
+ function getGroupKey(
420
+ group: { key?: { toString(): string } | null },
421
+ groupIndex: number,
422
+ ) {
423
+ return `group_${groupIndex}_${group.key?.toString() ?? "ungrouped"}`;
424
+ }
425
+
426
+ function toggleGroupCollapse(groupKey: string) {
427
+ collapsedGroups = {
428
+ ...collapsedGroups,
429
+ [groupKey]: !collapsedGroups[groupKey],
430
+ };
431
+ }
432
+
433
+ let groupedResults = $derived.by(() => {
434
+ const groups = [...queryResults.groupedData];
435
+
436
+ if (!groupBy?.property) {
437
+ return groups;
438
+ }
439
+
440
+ const direction = groupBy.direction === "DESC" ? -1 : 1;
441
+
442
+ return groups.sort((left, right) => {
443
+ const leftHasKey = left.hasKey();
444
+ const rightHasKey = right.hasKey();
445
+
446
+ if (leftHasKey && !rightHasKey) {
447
+ return -1;
448
+ }
449
+
450
+ if (!leftHasKey && rightHasKey) {
451
+ return 1;
452
+ }
453
+
454
+ const leftValue = left.key?.toString() ?? "";
455
+ const rightValue = right.key?.toString() ?? "";
456
+
457
+ return (
458
+ direction *
459
+ leftValue.localeCompare(rightValue, undefined, {
460
+ numeric: true,
461
+ sensitivity: "base",
462
+ })
463
+ );
464
+ });
465
+ });
466
+ let displayItems = $derived.by(() => {
467
+ const items: TableDisplayItem[] = [];
468
+ const groupLabel = groupBy?.property
469
+ ? view.config.getDisplayName(groupBy.property) || groupBy.property
470
+ : "";
471
+
472
+ for (const [groupIndex, group] of groupedResults.entries()) {
473
+ if (groupBy?.property) {
474
+ const groupKey = getGroupKey(group, groupIndex);
475
+ const collapsed = !!collapsedGroups[groupKey];
476
+ items.push({
477
+ kind: "group",
478
+ key: groupKey,
479
+ label: groupLabel,
480
+ value: group.hasKey() ? (group.key?.toString() ?? "") : "Ungrouped",
481
+ collapsed,
482
+ });
483
+
484
+ if (collapsed) {
485
+ continue;
486
+ }
487
+ }
488
+
489
+ for (const row of group.entries) {
490
+ items.push({
491
+ kind: "row",
492
+ key: row.id,
493
+ row,
494
+ });
495
+ }
496
+ }
497
+
498
+ return items;
499
+ });
500
+ let activeSearchQuery = $derived(view.controller.searchQuery.trim());
501
+ let showStickySearch = $derived(
502
+ !!activeSearchQuery && !view.controller.searchPanelOpen,
503
+ );
504
+ let tableContainerRef: HTMLElement | null = $state(null);
505
+ let scrollTop = $state(0);
506
+ let headers = $derived(view.config.getOrder());
507
+ let headerMap = $derived.by(() => {
508
+ return table
509
+ .getFlatHeaders()
510
+ .reduce<Record<string, Header<BasesEntry, any>>>((acc, value) => {
511
+ acc[value.id] = value;
512
+ return acc;
513
+ }, {});
514
+ });
515
+ let columnTracks = $derived.by(() => {
516
+ columnSizing;
517
+ resolvedWidths;
518
+ const order = view.config.getOrder();
519
+ return resolveTableColumnTracks(order, (id) => {
520
+ return (
521
+ headerMap[id]?.column.getSize() ??
522
+ resolvedWidths[id] ??
523
+ DEFAULT_COLUMN_WIDTH
524
+ );
525
+ });
526
+ });
527
+ let columnTrackMap = $derived.by(() => {
528
+ return Object.fromEntries(
529
+ columnTracks.tracks.map((track) => [track.id, track]),
530
+ );
531
+ });
532
+ let displayItemCount = $derived(displayItems.length);
533
+ let displayItemMeasurementKey = $derived(
534
+ displayItems.map((item) => item.key).join("\u0000"),
535
+ );
536
+ let measuredItemSizes: Record<string, number> = $state({});
537
+ let virtualItemEls: Array<HTMLDivElement | null> = $state([]);
538
+ let rowVirtualizer = createVirtualizer({
539
+ count: untrack(() => displayItemCount),
540
+ getScrollElement: () => tableContainerRef,
541
+ estimateSize: (index) =>
542
+ untrack(() => {
543
+ const item = displayItems[index];
544
+ return item
545
+ ? (measuredItemSizes[item.key] ??
546
+ (item.kind === "group" ? GROUP_HEADER_HEIGHT : rowHeight))
547
+ : rowHeight;
548
+ }),
549
+ overscan: 5,
550
+ });
551
+
552
+ $effect(() => {
553
+ if (rowVirtualizer.options.count !== displayItemCount) {
554
+ rowVirtualizer.setOptions({ count: displayItemCount });
555
+ }
556
+ });
557
+
558
+ let groupSections = $derived.by(() => {
559
+ rowVirtualizer.getTotalSize();
560
+ const sections: GroupSection[] = [];
561
+ let estimatedStart = 0;
562
+
563
+ for (const [index, item] of displayItems.entries()) {
564
+ const measurement = rowVirtualizer.measurementsCache[index];
565
+ if (item.kind === "group") {
566
+ sections.push({
567
+ key: item.key,
568
+ label: item.label,
569
+ value: item.value,
570
+ collapsed: item.collapsed,
571
+ start: measurement?.start ?? estimatedStart,
572
+ });
573
+ }
574
+
575
+ estimatedStart +=
576
+ measurement?.size ??
577
+ (item.kind === "group" ? GROUP_HEADER_HEIGHT : rowHeight);
578
+ }
579
+
580
+ return sections;
581
+ });
582
+ let stickyGroup = $derived.by(() => {
583
+ if (!groupBy?.property || !groupSections.length) {
584
+ return null;
585
+ }
586
+
587
+ let activeIndex = 0;
588
+
589
+ for (let index = 0; index < groupSections.length; index += 1) {
590
+ if (groupSections[index].start <= scrollTop) {
591
+ activeIndex = index;
592
+ continue;
593
+ }
594
+
595
+ break;
596
+ }
597
+
598
+ const active = groupSections[activeIndex];
599
+ const next = groupSections[activeIndex + 1];
600
+ let offset = 0;
601
+
602
+ if (next) {
603
+ offset = Math.min(0, next.start - scrollTop - GROUP_HEADER_HEIGHT);
604
+ }
605
+
606
+ return {
607
+ ...active,
608
+ offset,
609
+ visible: scrollTop > active.start,
610
+ };
611
+ });
612
+
613
+ let columnVirtualizer = createVirtualizer({
614
+ horizontal: true,
615
+ get count() {
616
+ return view.config.getOrder().length;
617
+ },
618
+ getScrollElement: () => tableContainerRef,
619
+ estimateSize: (i) => {
620
+ return columnTracks.tracks[i]?.width ?? DEFAULT_COLUMN_WIDTH;
621
+ },
622
+ overscan: 3,
623
+ });
624
+
625
+ $effect(() => {
626
+ columnVirtualizer.setOptions({ count: view.config.getOrder().length });
627
+ });
628
+
629
+ $effect(() => {
630
+ if (!tableContainerRef) {
631
+ return;
632
+ }
633
+
634
+ rowVirtualizer.setOptions({
635
+ count: displayItems.length,
636
+ getScrollElement: () => tableContainerRef,
637
+ });
638
+ columnVirtualizer.setOptions({
639
+ count: view.config.getOrder().length,
640
+ getScrollElement: () => tableContainerRef,
641
+ });
642
+ });
643
+
644
+ $effect(() => {
645
+ const viewport = tableContainerRef;
646
+ if (!viewport) {
647
+ return;
648
+ }
649
+
650
+ containerSize.ref = viewport;
651
+ const updateScrollTop = () => {
652
+ scrollTop = viewport.scrollTop;
653
+ };
654
+ updateScrollTop();
655
+ viewport.addEventListener("scroll", updateScrollTop, { passive: true });
656
+
657
+ return () => viewport.removeEventListener("scroll", updateScrollTop);
658
+ });
659
+
660
+ $effect(() => {
661
+ columnTracks;
662
+ columnSizingInfo;
663
+ containerSize.size.width;
664
+ view.config.getOrder();
665
+ columnVirtualizer.measure();
666
+ });
667
+
668
+ let measuredDisplayItemKey = "";
669
+ let measuredRowHeight = 0;
670
+ let measurementFrame = 0;
671
+
672
+ $effect(() => {
673
+ if (
674
+ measuredDisplayItemKey === displayItemMeasurementKey &&
675
+ measuredRowHeight === rowHeight
676
+ ) {
677
+ return;
678
+ }
679
+
680
+ measuredDisplayItemKey = displayItemMeasurementKey;
681
+ const rowHeightChanged = measuredRowHeight !== rowHeight;
682
+ measuredRowHeight = rowHeight;
683
+ if (rowHeightChanged) {
684
+ measuredItemSizes = {};
685
+ }
686
+ virtualItemEls.length = displayItemCount;
687
+ rowVirtualizer.measure();
688
+ });
689
+
690
+ $effect(() => {
691
+ const _ = [
692
+ displayItems,
693
+ columnTracks,
694
+ columnSizingInfo.isResizingColumn,
695
+ rowHeight,
696
+ ];
697
+ const renderedElements = virtualItemEls.slice();
698
+ cancelAnimationFrame(measurementFrame);
699
+ measurementFrame = requestAnimationFrame(() => {
700
+ const nextSizes = { ...measuredItemSizes };
701
+ let sizesChanged = false;
702
+
703
+ renderedElements.forEach((element, index) => {
704
+ if (element?.isConnected) {
705
+ const item = displayItems[index];
706
+ const height = element.getBoundingClientRect().height;
707
+ if (item && Math.abs((nextSizes[item.key] ?? 0) - height) > 0.25) {
708
+ nextSizes[item.key] = height;
709
+ sizesChanged = true;
710
+ }
711
+ rowVirtualizer.resizeItem(
712
+ index,
713
+ height,
714
+ );
715
+ }
716
+ });
717
+
718
+ if (sizesChanged) {
719
+ measuredItemSizes = nextSizes;
720
+ }
721
+ });
722
+ });
723
+
724
+ onDestroy(() => cancelAnimationFrame(measurementFrame));
725
+
726
+ type RenderedVirtualRow = ReturnType<
727
+ typeof rowVirtualizer.getVirtualItems
728
+ >[number];
729
+
730
+ let virtualRows = $derived.by(() => {
731
+ displayItems.length;
732
+ rowHeight;
733
+ scrollTop;
734
+ return rowVirtualizer.getVirtualItems();
735
+ });
736
+
737
+ let visibleVirtualRows = $derived.by(() => {
738
+ return virtualRows.reduce<
739
+ Array<{ virtualRow: RenderedVirtualRow; item: TableDisplayItem }>
740
+ >((entries, virtualRow) => {
741
+ const item = displayItems[virtualRow.index];
742
+ if (!item) {
743
+ return entries;
744
+ }
745
+
746
+ entries.push({ virtualRow, item });
747
+ return entries;
748
+ }, []);
749
+ });
750
+
751
+ let lastDataRowIndex = $derived.by(() => {
752
+ for (let index = displayItems.length - 1; index >= 0; index -= 1) {
753
+ if (displayItems[index]?.kind === "row") {
754
+ return index;
755
+ }
756
+ }
757
+
758
+ return -1;
759
+ });
760
+
761
+ let virtualTotalSize = $derived.by(() => {
762
+ rowHeight;
763
+ scrollTop;
764
+ return resolveVirtualTotalSize(
765
+ displayItems.length,
766
+ rowVirtualizer.getTotalSize(),
767
+ );
768
+ });
769
+
770
+ let previousDisplayItemCount = $state(0);
771
+
772
+ $effect(() => {
773
+ const count = displayItems.length;
774
+
775
+ if (
776
+ count < previousDisplayItemCount &&
777
+ tableContainerRef &&
778
+ tableContainerRef.scrollTop > 0
779
+ ) {
780
+ tableContainerRef.scrollTop = 0;
781
+ scrollTop = 0;
782
+ }
783
+
784
+ previousDisplayItemCount = count;
785
+ });
786
+
787
+ let show = $state(false);
788
+ onMount(() => {
789
+ setTimeout(() => {
790
+ show = true;
791
+ });
792
+ });
793
+
794
+ let tableWidth = $derived.by(() => {
795
+ return Math.max(containerSize.size.width, columnTracks.totalWidth);
796
+ });
797
+ </script>
798
+
799
+ <DragDropProvider onDragEnd={handleDragEnd}>
800
+ <div
801
+ class="bases-table-view bases-style-h-full-668b21 bases-style-w-full-6da6a3 bases-style-flex-grow-95a3df"
802
+ data-layout="table"
803
+ data-ui-component="bases-table-view"
804
+ data-ui-part="scroll-area-shell"
805
+ >
806
+ <ScrollArea.Root
807
+ class="bases-table__scroll-area"
808
+ orientation="both"
809
+ type="always"
810
+ bind:viewportRef={tableContainerRef}
811
+ scrollbarXClasses="bases-table__scrollbar bases-table__scrollbar--horizontal"
812
+ scrollbarYClasses="bases-table__scrollbar bases-table__scrollbar--vertical"
813
+ >
814
+ <div
815
+ class="bases-table-container bases-table relative bases-style-min-w-full-a1e7a8 bases-style-pb-100px-03c580 bases-style-text-sm-fc7473"
816
+ style={`--ui-bases-table-row-height: ${rowHeight}px; width: ${tableWidth}px; height: ${virtualTotalSize + 2 * rowHeight}px;`}
817
+ >
818
+ <div
819
+ class="bases-table__head bases-thead sticky bases-style-top-0-216740 bases-style-h-9-e7a768"
820
+ data-ui-part="header"
821
+ >
822
+ <div
823
+ class="bases-tr relative bases-style-flex-60fbb7 bases-style-h-9-e7a768 bases-style-min-w-full-a1e7a8 bases-style-flex-row-a6e886"
824
+ style={`width: ${tableWidth}px;`}
825
+ >
826
+ {#each columnVirtualizer.getVirtualItems() as virtualColumn (virtualColumn.key)}
827
+ {@const track = columnTracks.tracks[virtualColumn.index]}
828
+ {#if track}
829
+ <div
830
+ data-index={virtualColumn.index}
831
+ data-column-id={track.id}
832
+ class="bases-table__header-cell absolute bases-style-top-0-216740 bases-style-left-0-c78fac"
833
+ style={`inset-inline-start: ${track.startCss}; width: ${track.widthCss}`}
834
+ >
835
+ <TableHeader
836
+ header={headerMap[track.id]}
837
+ icon={getIcon(track.id as BasesPropertyId)}
838
+ text={view.config.getDisplayName(track.id as BasesPropertyId)}
839
+ width={track.width}
840
+ />
841
+ </div>
842
+ {/if}
843
+ {/each}
844
+ </div>
845
+ </div>
846
+ {#if showStickySearch}
847
+ <div
848
+ class="bases-table__sticky-search sticky bases-style-z-96-7882ad bases-style-flex-60fbb7 bases-style-min-w-full-a1e7a8 bases-style-items-center-3960ff bases-style-gap-2-77a2a2 bases-style-border-b-65fdba bases-style-px-3-0e17f2 bases-style-py-2-03b4dd bases-style-text-sm-fc7473 backdrop-blur-sm"
849
+ style={`top: 36px; width: ${tableWidth}px; min-height: ${ACTIVE_SEARCH_HEIGHT}px;`}
850
+ >
851
+ <span class="bases-table__group-label">Search</span>
852
+ <span class="bases-style-font-medium-2689f3">{activeSearchQuery}</span>
853
+ </div>
854
+ {/if}
855
+ {#if stickyGroup?.visible}
856
+ <div
857
+ class="bases-table__group sticky bases-style-z-95-0002d5 bases-style-flex-60fbb7 bases-style-min-w-full-a1e7a8 bases-style-items-center-3960ff bases-style-border-t-b950dd bases-style-border-b-65fdba bases-style-px-3-0e17f2 bases-style-py-2-03b4dd bases-style-text-sm-fc7473"
858
+ style={`top: ${36 + (showStickySearch ? ACTIVE_SEARCH_HEIGHT : 0)}px; width: ${tableWidth}px; transform: translateY(${stickyGroup.offset}px); min-height: ${GROUP_HEADER_HEIGHT}px;`}
859
+ >
860
+ <button
861
+ type="button"
862
+ class="bases-style-flex-60fbb7 bases-style-w-full-6da6a3 bases-style-items-center-3960ff bases-style-gap-2-77a2a2 bases-style-text-left-2eba0d"
863
+ aria-expanded={!stickyGroup.collapsed}
864
+ onclick={() => toggleGroupCollapse(stickyGroup.key)}
865
+ >
866
+ {#if stickyGroup.collapsed}
867
+ <ChevronRight
868
+ class="bases-table__group-label bases-style-size-4-f7b5fa bases-style-shrink-0-012fbd"
869
+ />
870
+ {:else}
871
+ <ChevronDown class="bases-table__group-label bases-style-size-4-f7b5fa bases-style-shrink-0-012fbd" />
872
+ {/if}
873
+ <span class="bases-table__group-label">{stickyGroup.label}</span>
874
+ <span class="bases-style-font-semibold-e83a70">{stickyGroup.value}</span>
875
+ </button>
876
+ </div>
877
+ {/if}
878
+ <div
879
+ class="bases-tbody absolute"
880
+ style={`height: ${virtualTotalSize}px;`}
881
+ >
882
+ {#if show}
883
+ {#each visibleVirtualRows as entry (entry.item.key)}
884
+ {@const virtualRow = entry.virtualRow}
885
+ {@const item = entry.item}
886
+ {#if item?.kind === "group"}
887
+ <div
888
+ data-index={virtualRow.index}
889
+ bind:this={
890
+ () => {
891
+ virtualItemEls[virtualRow.index] ||= null;
892
+ return virtualItemEls[virtualRow.index];
893
+ },
894
+ (value) => {
895
+ virtualItemEls[virtualRow.index] = value;
896
+ }
897
+ }
898
+ class="bases-table__group absolute bases-style-top-0-216740 bases-style-left-0-c78fac bases-style-flex-60fbb7 bases-style-min-w-full-a1e7a8 bases-style-items-center-3960ff bases-style-border-t-b950dd bases-style-border-b-65fdba bases-style-px-3-0e17f2 bases-style-py-2-03b4dd bases-style-text-sm-fc7473"
899
+ style={`width: ${tableWidth}px; top: ${virtualRow.start}px; min-height: ${GROUP_HEADER_HEIGHT}px;`}
900
+ >
901
+ <button
902
+ type="button"
903
+ class="bases-style-flex-60fbb7 bases-style-w-full-6da6a3 bases-style-items-center-3960ff bases-style-gap-2-77a2a2 bases-style-text-left-2eba0d"
904
+ aria-expanded={!item.collapsed}
905
+ onclick={() => toggleGroupCollapse(item.key)}
906
+ >
907
+ {#if item.collapsed}
908
+ <ChevronRight
909
+ class="bases-table__group-label bases-style-size-4-f7b5fa bases-style-shrink-0-012fbd"
910
+ />
911
+ {:else}
912
+ <ChevronDown
913
+ class="bases-table__group-label bases-style-size-4-f7b5fa bases-style-shrink-0-012fbd"
914
+ />
915
+ {/if}
916
+ <span class="bases-table__group-label">{item.label}</span>
917
+ <span class="bases-style-font-semibold-e83a70">{item.value}</span>
918
+ </button>
919
+ </div>
920
+ {:else if item.kind === "row"}
921
+ {@const row = item.row}
922
+ <div
923
+ data-index={virtualRow.index}
924
+ bind:this={
925
+ () => {
926
+ virtualItemEls[virtualRow.index] ||= null;
927
+ return virtualItemEls[virtualRow.index];
928
+ },
929
+ (value) => {
930
+ virtualItemEls[virtualRow.index] = value;
931
+ }
932
+ }
933
+ class="bases-table__row bases-tr absolute bases-style-top-0-216740 bases-style-left-0-c78fac bases-style-flex-60fbb7 bases-style-min-w-full-a1e7a8 bases-style-flex-row-a6e886 bases-style-transition-colors-ceb69a"
934
+ style={`width: ${tableWidth}px; top: ${virtualRow.start}px; min-height: var(--ui-bases-table-row-height);`}
935
+ data-ui-part="row"
936
+ data-last-row={virtualRow.index === lastDataRowIndex}
937
+ >
938
+ {#each headers as id, idx (`${id}_${virtualRow.key}_${idx}`)}
939
+ {@const track = columnTrackMap[id]}
940
+ <div
941
+ data-column-id={id}
942
+ class="bases-table__cell bases-td bases-style-flex-none-81e443 bases-style-overflow-hidden-2cd02d bases-style-text-nowrap-621d3b bases-style-overflow-ellipsis-5b2ef5 bases-style-whitespace-nowrap-e82ae8"
943
+ style={`flex: 0 0 auto; width: ${track?.widthCss ?? "0px"}; min-height: var(--ui-bases-table-row-height)`}
944
+ >
945
+ <div
946
+ class="bases-table__cell-inner bases-style-h-full-668b21 bases-style-w-full-6da6a3 bases-style-px-2-d5eab2 bases-style-py-1-660d2e"
947
+ >
948
+ <Cell
949
+ app={view.controller.app}
950
+ name={id}
951
+ file={row.file}
952
+ readOnly={view.controller.readOnly}
953
+ type={types[id]?.type}
954
+ value={row.getValue(id as BasesPropertyId)}
955
+ class="bases-style-z-1-0bcb04 bases-style-h-full-668b21 bases-style-w-full-6da6a3 bases-style-min-w-full-a1e7a8 bases-style-overflow-hidden-2cd02d bases-style-text-nowrap-621d3b bases-style-overflow-ellipsis-5b2ef5"
956
+ />
957
+ </div>
958
+ </div>
959
+ {/each}
960
+ </div>
961
+ {/if}
962
+ {/each}
963
+ {/if}
964
+ </div>
965
+ {#if summaries.length}
966
+ <div
967
+ class="bases-table__footer bases-tfoot sticky bases-style-bottom-0-189f03 bases-style-z-90-3d4b39 bases-style-border-t-b950dd backdrop-blur-sm"
968
+ >
969
+ <div
970
+ class="bases-tr relative bases-style-flex-60fbb7 bases-style-min-w-full-a1e7a8 bases-style-flex-row-a6e886"
971
+ style={`width: ${tableWidth}px;`}
972
+ >
973
+ {#each headers as id, idx (`${id}_summary_${idx}`)}
974
+ {@const summary = summaryMap[id]}
975
+ {@const track = columnTrackMap[id]}
976
+ <div
977
+ data-column-id={id}
978
+ class="bases-table__summary-cell bases-td bases-style-min-h-11-0e5b24 bases-style-flex-none-81e443 bases-style-items-center-3960ff bases-style-overflow-hidden-2cd02d bases-style-px-2-d5eab2 bases-style-py-1-660d2e bases-style-text-xs-359090"
979
+ style={`flex: 0 0 auto; width: ${track?.widthCss ?? "0px"}`}
980
+ >
981
+ {#if summary}
982
+ <div class="bases-style-min-w-0-7e0b7c">
983
+ <div class="bases-table__summary-label truncate">
984
+ {summary.label}
985
+ </div>
986
+ <div class="truncate bases-style-font-medium-2689f3">{summary.value}</div>
987
+ </div>
988
+ {/if}
989
+ </div>
990
+ {/each}
991
+ </div>
992
+ </div>
993
+ {/if}
994
+ </div>
995
+ </ScrollArea.Root>
996
+ </div>
997
+ </DragDropProvider>