snice 7.8.0 → 7.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/adapters/react/SniceProvider.js +1 -1
- package/adapters/react/SniceRouter.js +1 -1
- package/adapters/react/matchRoute.js +1 -1
- package/adapters/react/table.d.ts +1 -0
- package/adapters/react/table.d.ts.map +1 -1
- package/adapters/react/table.js +1 -1
- package/adapters/react/table.js.map +1 -1
- package/adapters/react/table.tsx +2 -1
- package/adapters/react/useRequestHandler.js +1 -1
- package/bin/analyzer-contracts.js +17 -1
- package/custom-elements.json +57 -3
- package/dist/cdn/accordion/snice-accordion.js +1 -1
- package/dist/cdn/action-bar/snice-action-bar.js +1 -1
- package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
- package/dist/cdn/alert/snice-alert.js +1 -1
- package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
- package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
- package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
- package/dist/cdn/availability/snice-availability.js +1 -1
- package/dist/cdn/avatar/snice-avatar.js +1 -1
- package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
- package/dist/cdn/badge/snice-badge.js +1 -1
- package/dist/cdn/banner/snice-banner.js +1 -1
- package/dist/cdn/binpack/snice-binpack.js +1 -1
- package/dist/cdn/book/snice-book.js +1 -1
- package/dist/cdn/booking/snice-booking.js +1 -1
- package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
- package/dist/cdn/button/snice-button.js +1 -1
- package/dist/cdn/calendar/README.md +2 -2
- package/dist/cdn/calendar/snice-calendar.js +537 -44
- package/dist/cdn/calendar/snice-calendar.js.map +1 -1
- package/dist/cdn/calendar/snice-calendar.min.js +2 -2
- package/dist/cdn/calendar/snice-calendar.min.js.map +1 -1
- package/dist/cdn/camera/snice-camera.js +1 -1
- package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
- package/dist/cdn/candlestick/snice-candlestick.js +1 -1
- package/dist/cdn/card/snice-card.js +1 -1
- package/dist/cdn/carousel/snice-carousel.js +1 -1
- package/dist/cdn/cart/snice-cart.js +1 -1
- package/dist/cdn/chart/snice-chart.js +1 -1
- package/dist/cdn/chat/snice-chat.js +1 -1
- package/dist/cdn/checkbox/snice-checkbox.js +1 -1
- package/dist/cdn/chip/snice-chip.js +1 -1
- package/dist/cdn/code-block/README.md +2 -2
- package/dist/cdn/code-block/snice-code-block.js +177 -167
- package/dist/cdn/code-block/snice-code-block.js.map +1 -1
- package/dist/cdn/code-block/snice-code-block.min.js +2 -2
- package/dist/cdn/code-block/snice-code-block.min.js.map +1 -1
- package/dist/cdn/color-display/snice-color-display.js +1 -1
- package/dist/cdn/color-picker/snice-color-picker.js +1 -1
- package/dist/cdn/command-palette/README.md +1 -1
- package/dist/cdn/command-palette/snice-command-palette.js +2 -2
- package/dist/cdn/command-palette/snice-command-palette.js.map +1 -1
- package/dist/cdn/command-palette/snice-command-palette.min.js +1 -1
- package/dist/cdn/command-palette/snice-command-palette.min.js.map +1 -1
- package/dist/cdn/comments/snice-comments.js +1 -1
- package/dist/cdn/countdown/snice-countdown.js +1 -1
- package/dist/cdn/cropper/snice-cropper.js +1 -1
- package/dist/cdn/data-card/snice-data-card.js +1 -1
- package/dist/cdn/date-picker/snice-date-picker.js +1 -1
- package/dist/cdn/date-range-picker/snice-date-range-picker.js +1 -1
- package/dist/cdn/date-time-picker/snice-date-time-picker.js +1 -1
- package/dist/cdn/diff/snice-diff.js +1 -1
- package/dist/cdn/divider/snice-divider.js +1 -1
- package/dist/cdn/doc/snice-doc.js +1 -1
- package/dist/cdn/draw/snice-draw.js +1 -1
- package/dist/cdn/drawer/snice-drawer.js +1 -1
- package/dist/cdn/empty-state/snice-empty-state.js +1 -1
- package/dist/cdn/estimate/snice-estimate.js +1 -1
- package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
- package/dist/cdn/file-upload/snice-file-upload.js +1 -1
- package/dist/cdn/flip-card/snice-flip-card.js +1 -1
- package/dist/cdn/flow/snice-flow.js +1 -1
- package/dist/cdn/form-layout/snice-form-layout.js +1 -1
- package/dist/cdn/funnel/snice-funnel.js +1 -1
- package/dist/cdn/gantt/snice-gantt.js +1 -1
- package/dist/cdn/gauge/snice-gauge.js +1 -1
- package/dist/cdn/grid/snice-grid.js +1 -1
- package/dist/cdn/heatmap/snice-heatmap.js +1 -1
- package/dist/cdn/image/snice-image.js +1 -1
- package/dist/cdn/input/snice-input.js +1 -1
- package/dist/cdn/invoice/snice-invoice.js +1 -1
- package/dist/cdn/kanban/snice-kanban.js +1 -1
- package/dist/cdn/key-value/snice-key-value.js +1 -1
- package/dist/cdn/kpi/snice-kpi.js +1 -1
- package/dist/cdn/layout/snice-layout.js +1 -1
- package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
- package/dist/cdn/link/snice-link.js +1 -1
- package/dist/cdn/link-preview/snice-link-preview.js +1 -1
- package/dist/cdn/list/snice-list.js +1 -1
- package/dist/cdn/location/snice-location.js +1 -1
- package/dist/cdn/login/snice-login.js +1 -1
- package/dist/cdn/map/snice-map.js +1 -1
- package/dist/cdn/markdown/snice-markdown.js +1 -1
- package/dist/cdn/masonry/snice-masonry.js +1 -1
- package/dist/cdn/menu/snice-menu.js +1 -1
- package/dist/cdn/message-strip/snice-message-strip.js +1 -1
- package/dist/cdn/modal/snice-modal.js +1 -1
- package/dist/cdn/music-player/snice-music-player.js +1 -1
- package/dist/cdn/nav/snice-nav.js +1 -1
- package/dist/cdn/network-graph/snice-network-graph.js +1 -1
- package/dist/cdn/notification-center/snice-notification-center.js +1 -1
- package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
- package/dist/cdn/org-chart/snice-org-chart.js +1 -1
- package/dist/cdn/pagination/snice-pagination.js +1 -1
- package/dist/cdn/paint/snice-paint.js +1 -1
- package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
- package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
- package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
- package/dist/cdn/popover/snice-popover.js +1 -1
- package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
- package/dist/cdn/product-card/snice-product-card.js +1 -1
- package/dist/cdn/progress/snice-progress.js +2 -2
- package/dist/cdn/progress/snice-progress.js.map +1 -1
- package/dist/cdn/progress/snice-progress.min.js +1 -1
- package/dist/cdn/progress/snice-progress.min.js.map +1 -1
- package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
- package/dist/cdn/qr-code/README.md +2 -2
- package/dist/cdn/qr-code/snice-qr-code.js +19 -3
- package/dist/cdn/qr-code/snice-qr-code.js.map +1 -1
- package/dist/cdn/qr-code/snice-qr-code.min.js +2 -2
- package/dist/cdn/qr-code/snice-qr-code.min.js.map +1 -1
- package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
- package/dist/cdn/radio/snice-radio.js +1 -1
- package/dist/cdn/range-slider/snice-range-slider.js +1 -1
- package/dist/cdn/rating/snice-rating.js +1 -1
- package/dist/cdn/receipt/snice-receipt.js +5 -2
- package/dist/cdn/receipt/snice-receipt.js.map +1 -1
- package/dist/cdn/receipt/snice-receipt.min.js +1 -1
- package/dist/cdn/receipt/snice-receipt.min.js.map +1 -1
- package/dist/cdn/recipe/snice-recipe.js +1 -1
- package/dist/cdn/runtime/snice-runtime.esm.js +4 -4
- package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.js +4 -4
- package/dist/cdn/runtime/snice-runtime.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
- package/dist/cdn/sankey/snice-sankey.js +1 -1
- package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
- package/dist/cdn/select/README.md +2 -2
- package/dist/cdn/select/snice-select.js +6 -9
- package/dist/cdn/select/snice-select.js.map +1 -1
- package/dist/cdn/select/snice-select.min.js +2 -2
- package/dist/cdn/select/snice-select.min.js.map +1 -1
- package/dist/cdn/skeleton/snice-skeleton.js +1 -1
- package/dist/cdn/slider/snice-slider.js +1 -1
- package/dist/cdn/sortable/snice-sortable.js +1 -1
- package/dist/cdn/sparkline/snice-sparkline.js +1 -1
- package/dist/cdn/spinner/snice-spinner.js +1 -1
- package/dist/cdn/split-button/snice-split-button.js +1 -1
- package/dist/cdn/split-pane/snice-split-pane.js +1 -1
- package/dist/cdn/spotlight/snice-spotlight.js +1 -1
- package/dist/cdn/stat-group/snice-stat-group.js +1 -1
- package/dist/cdn/step-input/snice-step-input.js +1 -1
- package/dist/cdn/stepper/snice-stepper.js +1 -1
- package/dist/cdn/switch/snice-switch.js +1 -1
- package/dist/cdn/table/README.md +2 -2
- package/dist/cdn/table/snice-table.esm.js +1940 -407
- package/dist/cdn/table/snice-table.esm.js.map +1 -1
- package/dist/cdn/table/snice-table.esm.min.js +242 -53
- package/dist/cdn/table/snice-table.esm.min.js.map +1 -1
- package/dist/cdn/table/snice-table.js +1940 -407
- package/dist/cdn/table/snice-table.js.map +1 -1
- package/dist/cdn/table/snice-table.min.js +234 -45
- package/dist/cdn/table/snice-table.min.js.map +1 -1
- package/dist/cdn/tabs/snice-tabs.js +1 -1
- package/dist/cdn/tag/snice-tag.js +1 -1
- package/dist/cdn/tag-input/snice-tag-input.js +1 -1
- package/dist/cdn/terminal/snice-terminal.js +1 -1
- package/dist/cdn/testimonial/snice-testimonial.js +1 -1
- package/dist/cdn/textarea/snice-textarea.js +1 -1
- package/dist/cdn/time-picker/snice-time-picker.js +1 -1
- package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
- package/dist/cdn/timeline/snice-timeline.js +1 -1
- package/dist/cdn/timer/snice-timer.js +1 -1
- package/dist/cdn/toast/snice-toast.js +1 -1
- package/dist/cdn/tooltip/snice-tooltip.js +1 -1
- package/dist/cdn/tree/snice-tree.js +1 -1
- package/dist/cdn/treemap/snice-treemap.js +1 -1
- package/dist/cdn/user-card/snice-user-card.js +1 -1
- package/dist/cdn/video-player/snice-video-player.js +1 -1
- package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
- package/dist/cdn/waterfall/snice-waterfall.js +1 -1
- package/dist/cdn/weather/snice-weather.js +1 -1
- package/dist/cdn/work-order/snice-work-order.js +1 -1
- package/dist/components/calendar/snice-calendar.d.ts +187 -5
- package/dist/components/calendar/snice-calendar.js +537 -44
- package/dist/components/calendar/snice-calendar.js.map +1 -1
- package/dist/components/calendar/snice-calendar.types.d.ts +2 -1
- package/dist/components/code-block/formatter.d.ts +6 -0
- package/dist/components/code-block/formatter.js +174 -164
- package/dist/components/code-block/formatter.js.map +1 -1
- package/dist/components/code-block/grammars/snice.json +1 -1
- package/dist/components/code-block/grammars/typescript.json +1 -1
- package/dist/components/command-palette/snice-command-palette.js +1 -1
- package/dist/components/command-palette/snice-command-palette.js.map +1 -1
- package/dist/components/progress/snice-progress.js +1 -1
- package/dist/components/progress/snice-progress.js.map +1 -1
- package/dist/components/qr-code/qrcode.d.ts +1 -1
- package/dist/components/qr-code/qrcode.js +18 -2
- package/dist/components/qr-code/qrcode.js.map +1 -1
- package/dist/components/receipt/snice-receipt.js +4 -1
- package/dist/components/receipt/snice-receipt.js.map +1 -1
- package/dist/components/select/snice-select.d.ts +1 -1
- package/dist/components/select/snice-select.js +5 -8
- package/dist/components/select/snice-select.js.map +1 -1
- package/dist/components/table/snice-cell-actions.js +1 -1
- package/dist/components/table/snice-cell-actions.js.map +1 -1
- package/dist/components/table/snice-cell-color.js +1 -1
- package/dist/components/table/snice-cell-color.js.map +1 -1
- package/dist/components/table/snice-cell-date.js +20 -8
- package/dist/components/table/snice-cell-date.js.map +1 -1
- package/dist/components/table/snice-cell-email.js +1 -1
- package/dist/components/table/snice-cell-email.js.map +1 -1
- package/dist/components/table/snice-cell-image.js +1 -1
- package/dist/components/table/snice-cell-image.js.map +1 -1
- package/dist/components/table/snice-cell-json.js +1 -1
- package/dist/components/table/snice-cell-json.js.map +1 -1
- package/dist/components/table/snice-cell-link.js +1 -1
- package/dist/components/table/snice-cell-link.js.map +1 -1
- package/dist/components/table/snice-cell-location.js +1 -1
- package/dist/components/table/snice-cell-location.js.map +1 -1
- package/dist/components/table/snice-cell-phone.js +1 -1
- package/dist/components/table/snice-cell-phone.js.map +1 -1
- package/dist/components/table/snice-cell-status.js +1 -1
- package/dist/components/table/snice-cell-status.js.map +1 -1
- package/dist/components/table/snice-cell.d.ts +10 -0
- package/dist/components/table/snice-cell.js +59 -13
- package/dist/components/table/snice-cell.js.map +1 -1
- package/dist/components/table/snice-row.d.ts +0 -1
- package/dist/components/table/snice-row.js +4 -10
- package/dist/components/table/snice-row.js.map +1 -1
- package/dist/components/table/snice-table.d.ts +170 -2
- package/dist/components/table/snice-table.js +868 -189
- package/dist/components/table/snice-table.js.map +1 -1
- package/dist/components/table/snice-table.types.d.ts +17 -0
- package/dist/components/table/table-cell-presentation.d.ts +17 -4
- package/dist/components/table/table-cell-presentation.js +37 -11
- package/dist/components/table/table-cell-presentation.js.map +1 -1
- package/dist/components/table/table-column-manager.d.ts +153 -2
- package/dist/components/table/table-column-manager.js +364 -43
- package/dist/components/table/table-column-manager.js.map +1 -1
- package/dist/components/table/table-date.d.ts +29 -0
- package/dist/components/table/table-date.js +78 -0
- package/dist/components/table/table-date.js.map +1 -0
- package/dist/components/table/table-export.js +6 -2
- package/dist/components/table/table-export.js.map +1 -1
- package/dist/components/table/table-filter-engine.d.ts +9 -0
- package/dist/components/table/table-filter-engine.js +58 -14
- package/dist/components/table/table-filter-engine.js.map +1 -1
- package/dist/components/table/table-keyboard.d.ts +8 -0
- package/dist/components/table/table-keyboard.js +14 -3
- package/dist/components/table/table-keyboard.js.map +1 -1
- package/dist/components/table/table-toolbar.js +1 -0
- package/dist/components/table/table-toolbar.js.map +1 -1
- package/dist/components/table/table-tree-data.d.ts +2 -0
- package/dist/components/table/table-tree-data.js +35 -9
- package/dist/components/table/table-tree-data.js.map +1 -1
- package/dist/components/table/table-virtualizer.d.ts +44 -7
- package/dist/components/table/table-virtualizer.js +101 -54
- package/dist/components/table/table-virtualizer.js.map +1 -1
- package/dist/components/theme/theme.css +9 -0
- package/dist/index.cjs +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.iife.js +1 -1
- package/dist/react/SniceProvider.js +1 -1
- package/dist/react/SniceRouter.js +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/matchRoute.js +1 -1
- package/dist/react/useRequestHandler.js +1 -1
- package/dist/symbols.cjs +1 -1
- package/dist/symbols.esm.js +1 -1
- package/dist/testing-dom.cjs +1 -1
- package/dist/testing-dom.esm.js +1 -1
- package/dist/transitions.cjs +1 -1
- package/dist/transitions.esm.js +1 -1
- package/docs/ai/DEVELOPMENT.md +93 -2
- package/docs/ai/components/calendar.md +113 -10
- package/docs/ai/components/code-block.md +4 -0
- package/docs/ai/components/doc.md +1 -1
- package/docs/ai/components/progress.md +1 -0
- package/docs/ai/components/receipt.md +1 -1
- package/docs/ai/components/table.md +29 -30
- package/docs/ai/components/theme.md +1 -0
- package/docs/ai/events.md +30 -0
- package/docs/ai/theme.md +1 -0
- package/docs/components/calendar.md +171 -11
- package/docs/components/code-block.md +2 -0
- package/docs/components/doc.md +1 -1
- package/docs/components/progress.md +13 -0
- package/docs/components/receipt.md +1 -0
- package/docs/components/table.md +274 -15
- package/docs/components/theme.md +5 -0
- package/docs/events.md +49 -0
- package/docs/plans/2026-03-06-date-range-picker-plan.md +4 -4
- package/docs/plans/2026-03-07-table-mui-parity-design.md +1 -1
- package/docs/plans/2026-03-09-action-bar-plan.md +11 -11
- package/docs/superpowers/specs/2026-07-09-table-incredible-design.md +1 -1
- package/docs/superpowers/specs/2026-07-09-table-phase0-implementation.md +2 -2
- package/package.json +3 -1
- package/vscode.html-custom-data.json +13 -1
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
* Column management for snice-table.
|
|
3
3
|
* Handles: flex width, resize, auto-size, visibility, ordering, pinning, groups.
|
|
4
4
|
*/
|
|
5
|
+
/** Padding + border a cell spends before any content fits inside it. */
|
|
6
|
+
function horizontalCellChrome(cell) {
|
|
7
|
+
const style = getComputedStyle(cell);
|
|
8
|
+
const px = (value) => Number.parseFloat(value) || 0;
|
|
9
|
+
return px(style.paddingLeft) + px(style.paddingRight)
|
|
10
|
+
+ px(style.borderLeftWidth) + px(style.borderRightWidth);
|
|
11
|
+
}
|
|
5
12
|
class TableColumnManager {
|
|
6
13
|
constructor() {
|
|
7
14
|
this.states = new Map();
|
|
@@ -11,28 +18,111 @@ class TableColumnManager {
|
|
|
11
18
|
this.resizingKey = null;
|
|
12
19
|
this.resizeOverlay = null;
|
|
13
20
|
this.tableElement = null;
|
|
21
|
+
this.fitMode = 'scroll';
|
|
22
|
+
/**
|
|
23
|
+
* The content budget the last `squish` fit shared out. A drag-resize needs it
|
|
24
|
+
* to know how much width the columns beside the dragged one have to give up
|
|
25
|
+
* (or take back) for the total to stay on the frame.
|
|
26
|
+
*/
|
|
27
|
+
this.squishBudget = null;
|
|
28
|
+
}
|
|
29
|
+
/** Fallback content width for a column nobody sized. */
|
|
30
|
+
static { this.DEFAULT_WIDTH = 150; }
|
|
31
|
+
/**
|
|
32
|
+
* The floor `squish` relaxes `minWidth` down to. Not zero: a column narrower
|
|
33
|
+
* than this shows no glyph at all, only its ellipsis, and stops being a
|
|
34
|
+
* column the reader can identify. A frame too narrow even for this is past
|
|
35
|
+
* what the mode can honour — see `fitVisibleColumns`.
|
|
36
|
+
*/
|
|
37
|
+
static { this.SQUISH_MIN_WIDTH = 24; }
|
|
38
|
+
/**
|
|
39
|
+
* Which fitting policy `fitVisibleColumns` (and a drag-resize) follows.
|
|
40
|
+
* Owned by the table's `columnFit` property; see the `ColumnFit` docs.
|
|
41
|
+
*/
|
|
42
|
+
setFitMode(mode) {
|
|
43
|
+
if (mode === this.fitMode)
|
|
44
|
+
return;
|
|
45
|
+
this.fitMode = mode;
|
|
46
|
+
// The budget belongs to the squish fit that recorded it.
|
|
47
|
+
if (mode !== 'squish')
|
|
48
|
+
this.squishBudget = null;
|
|
49
|
+
}
|
|
50
|
+
getFitMode() {
|
|
51
|
+
return this.fitMode;
|
|
14
52
|
}
|
|
15
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Routine resync, run on every render: make sure a state exists for each
|
|
55
|
+
* declared column and refresh the flags that are pure declaration (min/max,
|
|
56
|
+
* resizable, reorderable, hideable, pinnable, flex).
|
|
57
|
+
*
|
|
58
|
+
* Deliberately PRESERVES the interaction-owned members of an existing state —
|
|
59
|
+
* width, visible, pinned, order — because renderBody() calls this on every
|
|
60
|
+
* paint, and re-applying the declaration here would undo a drag-resize, a
|
|
61
|
+
* hidden column or a user reorder on the very next render. Re-applying the
|
|
62
|
+
* declaration is applyConfiguration()'s job, and only a `columns` assignment
|
|
63
|
+
* calls that.
|
|
64
|
+
*/
|
|
16
65
|
initialize(columns, tableEl) {
|
|
17
66
|
this.tableElement = tableEl;
|
|
18
67
|
columns.forEach((col, index) => {
|
|
19
68
|
const existing = this.states.get(col.key);
|
|
20
|
-
this.states.set(col.key,
|
|
21
|
-
key: col.key,
|
|
22
|
-
width: existing?.width ?? this.parseWidth(col.width) ?? 150,
|
|
23
|
-
flex: col.flex,
|
|
24
|
-
minWidth: col.minWidth ?? 50,
|
|
25
|
-
maxWidth: col.maxWidth ?? Infinity,
|
|
26
|
-
visible: existing?.visible ?? true,
|
|
27
|
-
pinned: existing?.pinned ?? (col.pinned || false),
|
|
28
|
-
order: existing?.order ?? index,
|
|
29
|
-
resizable: col.resizable !== false,
|
|
30
|
-
reorderable: col.reorderable !== false,
|
|
31
|
-
hideable: col.hideable !== false,
|
|
32
|
-
pinnable: col.pinnable !== false,
|
|
33
|
-
});
|
|
69
|
+
this.states.set(col.key, this.buildState(col, index, existing));
|
|
34
70
|
});
|
|
35
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* A `columns` assignment (or setColumns()) delivered a NEW CONFIGURATION.
|
|
74
|
+
*
|
|
75
|
+
* The declaration is the source of truth here: painted order, `pinned`,
|
|
76
|
+
* `width` and visibility all come from the array just assigned, and states for
|
|
77
|
+
* columns the new array no longer declares are DROPPED. Without this the first
|
|
78
|
+
* configuration the table ever saw won permanently — a re-ordered array kept
|
|
79
|
+
* the original order, a newly declared pin or width was ignored, and a column
|
|
80
|
+
* hidden through setColumnVisible() could never be brought back
|
|
81
|
+
* (MATRIX-columns-2/3/4/6).
|
|
82
|
+
*
|
|
83
|
+
* The cost is that the assignment also discards user interaction state (a
|
|
84
|
+
* drag-resize, a manual reorder, a hidden column) for the columns it
|
|
85
|
+
* re-declares. That is the intended reading of the contract, and it applies to
|
|
86
|
+
* EVERY assignment: `columns` declares `hasChanged: () => true`, so handing
|
|
87
|
+
* back the array the table already holds — after mutating it, or unchanged —
|
|
88
|
+
* re-applies the declaration exactly like a fresh array would. Mutating the
|
|
89
|
+
* published definitions is therefore NOT an escape hatch; the only way to keep
|
|
90
|
+
* user column state is to not assign `columns` at all and drive the change
|
|
91
|
+
* through the column APIs instead (setColumnVisible / moveColumn / pinColumn /
|
|
92
|
+
* unpinColumn), which mutate the state map in place. Renders triggered by this
|
|
93
|
+
* go through the table's coalescing queue, so re-applying costs no extra paint.
|
|
94
|
+
*/
|
|
95
|
+
applyConfiguration(columns, tableEl) {
|
|
96
|
+
this.tableElement = tableEl;
|
|
97
|
+
const next = new Map();
|
|
98
|
+
columns.forEach((col, index) => {
|
|
99
|
+
next.set(col.key, this.buildState(col, index));
|
|
100
|
+
});
|
|
101
|
+
this.states = next;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* One place that turns a column definition into a state. `existing` supplies
|
|
105
|
+
* the interaction-owned members on the resync path; omitting it yields the
|
|
106
|
+
* pure declared state applyConfiguration() wants.
|
|
107
|
+
*/
|
|
108
|
+
buildState(col, index, existing) {
|
|
109
|
+
const declared = this.parseWidth(col.width);
|
|
110
|
+
return {
|
|
111
|
+
key: col.key,
|
|
112
|
+
width: existing?.width ?? declared ?? TableColumnManager.DEFAULT_WIDTH,
|
|
113
|
+
flex: col.flex,
|
|
114
|
+
minWidth: col.minWidth ?? 50,
|
|
115
|
+
maxWidth: col.maxWidth ?? Infinity,
|
|
116
|
+
visible: existing?.visible ?? true,
|
|
117
|
+
pinned: existing?.pinned ?? (col.pinned || false),
|
|
118
|
+
order: existing?.order ?? index,
|
|
119
|
+
resizable: col.resizable !== false,
|
|
120
|
+
reorderable: col.reorderable !== false,
|
|
121
|
+
hideable: col.hideable !== false,
|
|
122
|
+
pinnable: col.pinnable !== false,
|
|
123
|
+
authored: existing?.authored ?? declared !== undefined,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
36
126
|
parseWidth(width) {
|
|
37
127
|
if (!width)
|
|
38
128
|
return undefined;
|
|
@@ -87,6 +177,176 @@ class TableColumnManager {
|
|
|
87
177
|
}
|
|
88
178
|
return widths;
|
|
89
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Fit the columns nobody sized into `availableWidth` (the frame's content
|
|
182
|
+
* box), reserving `chromePerColumn` for each column's own padding + border.
|
|
183
|
+
*
|
|
184
|
+
* A column width is a CONTENT width — the rendered column is that plus its
|
|
185
|
+
* chrome — so the budget has to come off the top or the fitted table lands a
|
|
186
|
+
* few pixels wider than the frame it was fitted to.
|
|
187
|
+
*
|
|
188
|
+
* Declared and user-chosen widths are spent first and never rewritten: a
|
|
189
|
+
* table that asked for `width: '80'` keeps 80 whatever the frame does. What
|
|
190
|
+
* is left is split evenly and clamped to each column's [minWidth, maxWidth],
|
|
191
|
+
* so a frame too narrow for the minimums overflows into the frame's own
|
|
192
|
+
* scroller instead of collapsing the columns to nothing.
|
|
193
|
+
*
|
|
194
|
+
* Returns whether any width actually moved, so callers can skip a repaint.
|
|
195
|
+
*
|
|
196
|
+
* Under `column-fit="squish"` the frame stops being a suggestion: see
|
|
197
|
+
* `squishVisibleColumns`.
|
|
198
|
+
*/
|
|
199
|
+
fitVisibleColumns(availableWidth, chromePerColumn = 0) {
|
|
200
|
+
const visible = this.getVisibleColumns();
|
|
201
|
+
// A layoutless (or not-yet-laid-out) frame reports 0. Fitting to that would
|
|
202
|
+
// slam every column to its minimum for a measurement that means nothing.
|
|
203
|
+
if (visible.length === 0 || !(availableWidth > 0))
|
|
204
|
+
return false;
|
|
205
|
+
const budget = availableWidth - visible.length * chromePerColumn;
|
|
206
|
+
if (this.fitMode === 'squish') {
|
|
207
|
+
this.squishBudget = budget;
|
|
208
|
+
return this.squishVisibleColumns(visible, budget);
|
|
209
|
+
}
|
|
210
|
+
const auto = visible.filter((state) => !state.authored);
|
|
211
|
+
if (auto.length === 0)
|
|
212
|
+
return false;
|
|
213
|
+
let remaining = budget;
|
|
214
|
+
for (const state of visible) {
|
|
215
|
+
if (state.authored)
|
|
216
|
+
remaining -= state.width;
|
|
217
|
+
}
|
|
218
|
+
const share = Math.floor(remaining / auto.length);
|
|
219
|
+
let changed = false;
|
|
220
|
+
for (const state of auto) {
|
|
221
|
+
const next = Math.max(state.minWidth, Math.min(state.maxWidth, share));
|
|
222
|
+
if (next !== state.width) {
|
|
223
|
+
state.width = next;
|
|
224
|
+
changed = true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return changed;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* The `squish` policy: the columns add up to the frame, whatever that costs.
|
|
231
|
+
*
|
|
232
|
+
* `minWidth` is a readability preference, and this mode has already decided
|
|
233
|
+
* the frame outranks it, so the only floor left is SQUISH_MIN_WIDTH. Two
|
|
234
|
+
* cases:
|
|
235
|
+
*
|
|
236
|
+
* - There is an unsized column left to absorb the difference, and the
|
|
237
|
+
* authored widths still leave room for it. Those are honoured exactly (a
|
|
238
|
+
* column that asked for 80, or that the user dragged to 80, keeps 80) and
|
|
239
|
+
* the rest is split evenly between the unsized ones.
|
|
240
|
+
*
|
|
241
|
+
* - Every column is authored, or the authored widths alone already overflow
|
|
242
|
+
* the frame. There is nothing left to give, so `scroll`'s escape hatch
|
|
243
|
+
* (overflow into the frame's scroller) is exactly what this mode exists to
|
|
244
|
+
* prevent: every column is scaled by the same factor instead. Scaling is a
|
|
245
|
+
* fixed point — the second pass computes a factor of 1 — so this settles
|
|
246
|
+
* on the first render rather than creeping on every repaint.
|
|
247
|
+
*
|
|
248
|
+
* Either way the remainder from integer division is handed back to the widest
|
|
249
|
+
* columns that are free to take it, so the widths sum to the budget EXACTLY
|
|
250
|
+
* and the rightmost column edge lands on the frame's inner edge instead of a
|
|
251
|
+
* few pixels short of it.
|
|
252
|
+
*/
|
|
253
|
+
squishVisibleColumns(visible, budget) {
|
|
254
|
+
const floor = TableColumnManager.SQUISH_MIN_WIDTH;
|
|
255
|
+
const auto = visible.filter((state) => !state.authored);
|
|
256
|
+
// What the frame has left once the authored widths are paid for.
|
|
257
|
+
const spare = budget - visible.reduce((spent, state) => spent + (state.authored ? state.width : 0), 0);
|
|
258
|
+
const next = new Map();
|
|
259
|
+
if (auto.length > 0 && spare >= auto.length * floor) {
|
|
260
|
+
const share = Math.floor(spare / auto.length);
|
|
261
|
+
for (const state of visible) {
|
|
262
|
+
next.set(state.key, state.authored
|
|
263
|
+
? state.width
|
|
264
|
+
: Math.max(floor, Math.min(state.maxWidth, share)));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
const current = visible.reduce((sum, state) => sum + state.width, 0) || 1;
|
|
269
|
+
const scale = budget / current;
|
|
270
|
+
for (const state of visible) {
|
|
271
|
+
next.set(state.key, Math.max(floor, Math.floor(state.width * scale)));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// Hand the leftover pixels to the widest column that is free to grow: it
|
|
275
|
+
// absorbs a few pixels without reading as a different column, and a
|
|
276
|
+
// narrower one might be sitting on its floor or its maxWidth.
|
|
277
|
+
let slack = budget - Array.from(next.values()).reduce((sum, w) => sum + w, 0);
|
|
278
|
+
if (slack > 0) {
|
|
279
|
+
const takers = visible
|
|
280
|
+
.filter((state) => (next.get(state.key) ?? 0) < state.maxWidth)
|
|
281
|
+
.sort((a, b) => (next.get(b.key) ?? 0) - (next.get(a.key) ?? 0));
|
|
282
|
+
for (const state of takers) {
|
|
283
|
+
if (slack <= 0)
|
|
284
|
+
break;
|
|
285
|
+
const room = Math.min(slack, state.maxWidth - (next.get(state.key) ?? 0));
|
|
286
|
+
next.set(state.key, (next.get(state.key) ?? 0) + room);
|
|
287
|
+
slack -= room;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
let changed = false;
|
|
291
|
+
for (const state of visible) {
|
|
292
|
+
const width = next.get(state.key);
|
|
293
|
+
if (width !== state.width) {
|
|
294
|
+
state.width = width;
|
|
295
|
+
changed = true;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return changed;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* A drag-resize under `squish` moved one column; the others pay for it.
|
|
302
|
+
*
|
|
303
|
+
* The dragged column is the anchor — it keeps the width the pointer asked
|
|
304
|
+
* for, capped so the remaining columns can still sit on their floor — and the
|
|
305
|
+
* rest are scaled to fill exactly what is left of the frame. Without this a
|
|
306
|
+
* drag would simply push the trailing column out of a frame that is not
|
|
307
|
+
* allowed to scroll.
|
|
308
|
+
*/
|
|
309
|
+
rebalanceSquish(anchorKey) {
|
|
310
|
+
const budget = this.squishBudget;
|
|
311
|
+
const anchor = this.states.get(anchorKey);
|
|
312
|
+
if (budget === null || !anchor)
|
|
313
|
+
return;
|
|
314
|
+
const others = this.getVisibleColumns().filter((state) => state.key !== anchorKey);
|
|
315
|
+
if (others.length === 0)
|
|
316
|
+
return;
|
|
317
|
+
const floor = TableColumnManager.SQUISH_MIN_WIDTH;
|
|
318
|
+
anchor.width = Math.max(floor, Math.min(anchor.width, budget - others.length * floor));
|
|
319
|
+
const remaining = budget - anchor.width;
|
|
320
|
+
const current = others.reduce((sum, state) => sum + state.width, 0) || 1;
|
|
321
|
+
const scale = remaining / current;
|
|
322
|
+
for (const state of others) {
|
|
323
|
+
state.width = Math.max(floor, Math.floor(state.width * scale));
|
|
324
|
+
}
|
|
325
|
+
let slack = remaining - others.reduce((sum, state) => sum + state.width, 0);
|
|
326
|
+
for (const state of [...others].sort((a, b) => b.width - a.width)) {
|
|
327
|
+
if (slack <= 0)
|
|
328
|
+
break;
|
|
329
|
+
const room = Math.min(slack, state.maxWidth - state.width);
|
|
330
|
+
state.width += room;
|
|
331
|
+
slack -= room;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/** Push the current widths onto the painted header and body cells. */
|
|
335
|
+
writeWidths(keys) {
|
|
336
|
+
const root = this.tableElement?.shadowRoot;
|
|
337
|
+
if (!root)
|
|
338
|
+
return;
|
|
339
|
+
for (const key of keys) {
|
|
340
|
+
const width = this.states.get(key)?.width;
|
|
341
|
+
if (width === undefined)
|
|
342
|
+
continue;
|
|
343
|
+
const th = root.querySelector(`th[data-key="${key}"]`);
|
|
344
|
+
if (th)
|
|
345
|
+
th.style.width = `${width}px`;
|
|
346
|
+
const tds = root.querySelectorAll(`td[data-key="${key}"]`);
|
|
347
|
+
tds.forEach((td) => { td.style.width = `${width}px`; });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
90
350
|
/** Apply computed widths to <col> or <th> elements */
|
|
91
351
|
applyWidths(headerRow, widths) {
|
|
92
352
|
const ths = headerRow.querySelectorAll('th[data-key]');
|
|
@@ -113,22 +373,26 @@ class TableColumnManager {
|
|
|
113
373
|
const onMove = (e) => {
|
|
114
374
|
e.preventDefault();
|
|
115
375
|
const delta = e.clientX - this.resizeStartX;
|
|
116
|
-
|
|
117
|
-
|
|
376
|
+
// Squish relaxes minWidth for the fit, so it has to relax it for the drag
|
|
377
|
+
// too — otherwise a column the fit already squished below its minimum
|
|
378
|
+
// would jump back up to it the moment its edge was touched.
|
|
379
|
+
const squish = this.fitMode === 'squish';
|
|
380
|
+
const min = squish ? TableColumnManager.SQUISH_MIN_WIDTH : state.minWidth;
|
|
381
|
+
state.width = Math.max(min, Math.min(state.maxWidth, this.resizeStartWidth + delta));
|
|
118
382
|
// Remove flex if manually resized
|
|
119
383
|
state.flex = undefined;
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
384
|
+
// The user chose this width — the container fit must leave it alone.
|
|
385
|
+
state.authored = true;
|
|
386
|
+
// Squish cannot let the drag push the table past the frame: the columns
|
|
387
|
+
// beside this one give up (or take back) the difference.
|
|
388
|
+
if (squish)
|
|
389
|
+
this.rebalanceSquish(columnKey);
|
|
390
|
+
this.writeWidths(squish
|
|
391
|
+
? this.getVisibleColumns().map((column) => column.key)
|
|
392
|
+
: [columnKey]);
|
|
129
393
|
// Dispatch resize event
|
|
130
394
|
this.tableElement?.dispatchEvent(new CustomEvent('column-resize', {
|
|
131
|
-
detail: { key: columnKey, width:
|
|
395
|
+
detail: { key: columnKey, width: state.width },
|
|
132
396
|
bubbles: true, composed: true
|
|
133
397
|
}));
|
|
134
398
|
};
|
|
@@ -148,24 +412,81 @@ class TableColumnManager {
|
|
|
148
412
|
}
|
|
149
413
|
/** Auto-size a column to fit its content */
|
|
150
414
|
autoSizeColumn(columnKey, tbody) {
|
|
151
|
-
|
|
152
|
-
if (!state)
|
|
153
|
-
return;
|
|
154
|
-
// Measure header
|
|
155
|
-
const th = this.tableElement?.shadowRoot?.querySelector(`th[data-key="${columnKey}"]`);
|
|
156
|
-
let maxWidth = th ? th.scrollWidth : 0;
|
|
157
|
-
// Measure body cells
|
|
158
|
-
const cells = tbody.querySelectorAll(`td[data-key="${columnKey}"]`);
|
|
159
|
-
cells.forEach(cell => {
|
|
160
|
-
maxWidth = Math.max(maxWidth, cell.scrollWidth);
|
|
161
|
-
});
|
|
162
|
-
state.width = Math.max(state.minWidth, Math.min(state.maxWidth, maxWidth + 16)); // 16px padding
|
|
163
|
-
state.flex = undefined;
|
|
415
|
+
this.autoSizeColumns([columnKey], tbody);
|
|
164
416
|
}
|
|
165
417
|
/** Auto-size all columns */
|
|
166
418
|
autoSizeAll(tbody) {
|
|
167
|
-
|
|
168
|
-
|
|
419
|
+
this.autoSizeColumns(Array.from(this.states.keys()), tbody);
|
|
420
|
+
}
|
|
421
|
+
/** Slack added to a measured content width so the last glyph never sits on
|
|
422
|
+
* the clip edge (and a sortable header keeps room for its chevron). */
|
|
423
|
+
static { this.AUTO_SIZE_SLACK = 4; }
|
|
424
|
+
/**
|
|
425
|
+
* Measure the columns' content and give each the width it actually needs.
|
|
426
|
+
*
|
|
427
|
+
* A table cell's `scrollWidth` is NOT its content width: for content that
|
|
428
|
+
* fits, it reports the padding box — the width the column already has. The
|
|
429
|
+
* previous implementation took that maximum and added 16px, so every
|
|
430
|
+
* "auto-size" pass could only GROW the column, by a chrome's worth each
|
|
431
|
+
* time, until the table outgrew its own frame. Once it did, the right-pinned
|
|
432
|
+
* column (`position: sticky`) parked over the columns beside it, and the
|
|
433
|
+
* columns behind it read as deleted.
|
|
434
|
+
*
|
|
435
|
+
* The width a column NEEDS is a layout question, so ask layout: drop the
|
|
436
|
+
* table into content-driven sizing (`table-layout: auto` at `max-content`)
|
|
437
|
+
* with the measured columns' imposed widths removed, and read back the width
|
|
438
|
+
* each header settles at. `max-content` also means no wrapping, so a long
|
|
439
|
+
* cell reports its full single-line extent even though the painted column
|
|
440
|
+
* ellipsises it. Everything is restored in the same task, before paint.
|
|
441
|
+
*/
|
|
442
|
+
autoSizeColumns(columnKeys, tbody) {
|
|
443
|
+
const root = this.tableElement?.shadowRoot ?? null;
|
|
444
|
+
const tableEl = (root?.querySelector('table')
|
|
445
|
+
?? tbody.closest('table'));
|
|
446
|
+
const targets = columnKeys
|
|
447
|
+
.map((key) => this.states.get(key))
|
|
448
|
+
.filter((state) => !!state);
|
|
449
|
+
if (!tableEl || targets.length === 0)
|
|
450
|
+
return;
|
|
451
|
+
const restore = [];
|
|
452
|
+
const push = (el, property) => {
|
|
453
|
+
const previous = el.style[property];
|
|
454
|
+
restore.push(() => { el.style[property] = previous; });
|
|
455
|
+
};
|
|
456
|
+
push(tableEl, 'tableLayout');
|
|
457
|
+
push(tableEl, 'width');
|
|
458
|
+
tableEl.style.tableLayout = 'auto';
|
|
459
|
+
tableEl.style.width = 'max-content';
|
|
460
|
+
const headers = new Map();
|
|
461
|
+
for (const state of targets) {
|
|
462
|
+
const header = root?.querySelector(`th[data-key="${state.key}"]`);
|
|
463
|
+
if (!header)
|
|
464
|
+
continue;
|
|
465
|
+
headers.set(state.key, header);
|
|
466
|
+
// An imposed width is still a preferred width under auto layout, so it
|
|
467
|
+
// has to come off before the column can report what it wants.
|
|
468
|
+
push(header, 'width');
|
|
469
|
+
header.style.width = 'auto';
|
|
470
|
+
for (const cell of Array.from(tbody.querySelectorAll(`td[data-key="${state.key}"]`))) {
|
|
471
|
+
push(cell, 'width');
|
|
472
|
+
cell.style.width = 'auto';
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const widths = new Map();
|
|
476
|
+
for (const [key, header] of headers) {
|
|
477
|
+
widths.set(key, header.getBoundingClientRect().width - horizontalCellChrome(header));
|
|
478
|
+
}
|
|
479
|
+
for (const undo of restore)
|
|
480
|
+
undo();
|
|
481
|
+
for (const state of targets) {
|
|
482
|
+
const content = widths.get(state.key) ?? 0;
|
|
483
|
+
// Nothing measurable — a layoutless DOM, or a column with no rendered
|
|
484
|
+
// header. Leave the width alone rather than slamming it to the minimum.
|
|
485
|
+
if (content <= 0)
|
|
486
|
+
continue;
|
|
487
|
+
state.width = Math.max(state.minWidth, Math.min(state.maxWidth, Math.ceil(content) + TableColumnManager.AUTO_SIZE_SLACK));
|
|
488
|
+
state.flex = undefined;
|
|
489
|
+
state.authored = true;
|
|
169
490
|
}
|
|
170
491
|
}
|
|
171
492
|
// ── Visibility ──
|
|
@@ -285,5 +606,5 @@ class TableColumnManager {
|
|
|
285
606
|
}
|
|
286
607
|
}
|
|
287
608
|
|
|
288
|
-
export { TableColumnManager };
|
|
609
|
+
export { TableColumnManager, horizontalCellChrome };
|
|
289
610
|
//# sourceMappingURL=table-column-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-column-manager.js","sources":["../../../../components/table/table-column-manager.ts"],"sourcesContent":["/**\n * Column management for snice-table.\n * Handles: flex width, resize, auto-size, visibility, ordering, pinning, groups.\n */\n\nimport type { ColumnDefinition } from './snice-table.types';\n\nexport interface ColumnState {\n key: string;\n width: number; // Computed pixel width\n flex?: number; // Flex ratio (shares remaining space)\n minWidth: number; // Minimum width in px\n maxWidth: number; // Maximum width in px (Infinity = no limit)\n visible: boolean;\n pinned: 'left' | 'right' | false;\n order: number; // Display order\n resizable: boolean;\n reorderable: boolean;\n hideable: boolean;\n pinnable: boolean;\n}\n\nexport interface ColumnGroup {\n label: string;\n children: string[]; // Column keys\n headerClass?: string;\n}\n\nexport class TableColumnManager {\n private states: Map<string, ColumnState> = new Map();\n private groups: ColumnGroup[] = [];\n private resizeStartX = 0;\n private resizeStartWidth = 0;\n private resizingKey: string | null = null;\n private resizeOverlay: HTMLElement | null = null;\n private tableElement: HTMLElement | null = null;\n\n /** Initialize column states from column definitions */\n initialize(columns: ColumnDefinition[], tableEl: HTMLElement) {\n this.tableElement = tableEl;\n columns.forEach((col, index) => {\n const existing = this.states.get(col.key);\n this.states.set(col.key, {\n key: col.key,\n width: existing?.width ?? this.parseWidth(col.width) ?? 150,\n flex: (col as any).flex,\n minWidth: (col as any).minWidth ?? 50,\n maxWidth: (col as any).maxWidth ?? Infinity,\n visible: existing?.visible ?? true,\n pinned: existing?.pinned ?? ((col as any).pinned || false),\n order: existing?.order ?? index,\n resizable: (col as any).resizable !== false,\n reorderable: (col as any).reorderable !== false,\n hideable: (col as any).hideable !== false,\n pinnable: (col as any).pinnable !== false,\n });\n });\n }\n\n private parseWidth(width?: string): number | undefined {\n if (!width) return undefined;\n const num = parseInt(width, 10);\n return isNaN(num) ? undefined : num;\n }\n\n /** Get ordered, visible columns */\n getVisibleColumns(): ColumnState[] {\n return Array.from(this.states.values())\n .filter(s => s.visible)\n .sort((a, b) => a.order - b.order);\n }\n\n /** Get all column states */\n getAllStates(): ColumnState[] {\n return Array.from(this.states.values()).sort((a, b) => a.order - b.order);\n }\n\n /** Get columns pinned to left */\n getPinnedLeft(): ColumnState[] {\n return this.getVisibleColumns().filter(s => s.pinned === 'left');\n }\n\n /** Get columns pinned to right */\n getPinnedRight(): ColumnState[] {\n return this.getVisibleColumns().filter(s => s.pinned === 'right');\n }\n\n /** Get unpinned columns */\n getUnpinned(): ColumnState[] {\n return this.getVisibleColumns().filter(s => !s.pinned);\n }\n\n /** Compute flex widths based on available space */\n computeFlexWidths(availableWidth: number): Map<string, number> {\n const visible = this.getVisibleColumns();\n const widths = new Map<string, number>();\n\n // First pass: allocate fixed-width columns\n let fixedTotal = 0;\n const flexCols: ColumnState[] = [];\n\n for (const col of visible) {\n if (col.flex && col.flex > 0) {\n flexCols.push(col);\n } else {\n fixedTotal += col.width;\n widths.set(col.key, col.width);\n }\n }\n\n // Second pass: distribute remaining space to flex columns\n const remaining = Math.max(0, availableWidth - fixedTotal);\n const totalFlex = flexCols.reduce((sum, c) => sum + (c.flex || 1), 0);\n\n for (const col of flexCols) {\n const flexShare = ((col.flex || 1) / totalFlex) * remaining;\n const clamped = Math.max(col.minWidth, Math.min(col.maxWidth, flexShare));\n widths.set(col.key, clamped);\n }\n\n return widths;\n }\n\n /** Apply computed widths to <col> or <th> elements */\n applyWidths(headerRow: HTMLElement, widths: Map<string, number>) {\n const ths = headerRow.querySelectorAll('th[data-key]') as NodeListOf<HTMLElement>;\n ths.forEach(th => {\n const key = th.getAttribute('data-key');\n if (key && widths.has(key)) {\n th.style.width = `${widths.get(key)}px`;\n }\n });\n }\n\n // ── Resize ──\n\n /** Start column resize. Call from mousedown on resize handle. */\n startResize(columnKey: string, startX: number) {\n const state = this.states.get(columnKey);\n if (!state || !state.resizable) return;\n\n this.resizingKey = columnKey;\n this.resizeStartX = startX;\n this.resizeStartWidth = state.width;\n\n // Create overlay to capture mouse events\n this.resizeOverlay = document.createElement('div');\n this.resizeOverlay.style.cssText = 'position:fixed;inset:0;z-index:99999;cursor:col-resize;';\n document.body.appendChild(this.resizeOverlay);\n\n const onMove = (e: MouseEvent) => {\n e.preventDefault();\n const delta = e.clientX - this.resizeStartX;\n const newWidth = Math.max(state.minWidth, Math.min(state.maxWidth, this.resizeStartWidth + delta));\n state.width = newWidth;\n // Remove flex if manually resized\n state.flex = undefined;\n\n // Apply width to DOM immediately\n const root = this.tableElement?.shadowRoot;\n if (root) {\n const th = root.querySelector(`th[data-key=\"${columnKey}\"]`) as HTMLElement;\n if (th) th.style.width = `${newWidth}px`;\n const tds = root.querySelectorAll(`td[data-key=\"${columnKey}\"]`) as NodeListOf<HTMLElement>;\n tds.forEach(td => td.style.width = `${newWidth}px`);\n }\n\n // Dispatch resize event\n this.tableElement?.dispatchEvent(new CustomEvent('column-resize', {\n detail: { key: columnKey, width: newWidth },\n bubbles: true, composed: true\n }));\n };\n\n const onUp = () => {\n this.resizingKey = null;\n this.resizeOverlay?.remove();\n this.resizeOverlay = null;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n\n this.tableElement?.dispatchEvent(new CustomEvent('column-resize-end', {\n detail: { key: columnKey, width: state.width },\n bubbles: true, composed: true\n }));\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n }\n\n /** Auto-size a column to fit its content */\n autoSizeColumn(columnKey: string, tbody: HTMLElement) {\n const state = this.states.get(columnKey);\n if (!state) return;\n\n // Measure header\n const th = this.tableElement?.shadowRoot?.querySelector(`th[data-key=\"${columnKey}\"]`) as HTMLElement;\n let maxWidth = th ? th.scrollWidth : 0;\n\n // Measure body cells\n const cells = tbody.querySelectorAll(`td[data-key=\"${columnKey}\"]`) as NodeListOf<HTMLElement>;\n cells.forEach(cell => {\n maxWidth = Math.max(maxWidth, cell.scrollWidth);\n });\n\n state.width = Math.max(state.minWidth, Math.min(state.maxWidth, maxWidth + 16)); // 16px padding\n state.flex = undefined;\n }\n\n /** Auto-size all columns */\n autoSizeAll(tbody: HTMLElement) {\n for (const key of this.states.keys()) {\n this.autoSizeColumn(key, tbody);\n }\n }\n\n // ── Visibility ──\n\n setColumnVisible(key: string, visible: boolean) {\n const state = this.states.get(key);\n if (state && state.hideable) {\n state.visible = visible;\n }\n }\n\n showAllColumns() {\n for (const state of this.states.values()) {\n state.visible = true;\n }\n }\n\n hideAllColumns() {\n for (const state of this.states.values()) {\n if (state.hideable) state.visible = false;\n }\n }\n\n getVisibilityModel(): Record<string, boolean> {\n const model: Record<string, boolean> = {};\n for (const [key, state] of this.states) {\n model[key] = state.visible;\n }\n return model;\n }\n\n // ── Ordering ──\n\n moveColumn(key: string, toIndex: number) {\n const state = this.states.get(key);\n if (!state || !state.reorderable || state.pinned) return;\n\n const ordered = this.getVisibleColumns();\n const fromIndex = ordered.findIndex(s => s.key === key);\n if (fromIndex === -1 || fromIndex === toIndex) return;\n\n // Recompute order values\n ordered.splice(fromIndex, 1);\n ordered.splice(toIndex, 0, state);\n ordered.forEach((s, i) => { s.order = i; });\n }\n\n // ── Pinning ──\n\n pinColumn(key: string, side: 'left' | 'right') {\n const state = this.states.get(key);\n if (state && state.pinnable) {\n state.pinned = side;\n }\n }\n\n unpinColumn(key: string) {\n const state = this.states.get(key);\n if (state) {\n state.pinned = false;\n }\n }\n\n // ── Groups ──\n\n setColumnGroups(groups: ColumnGroup[]) {\n this.groups = groups;\n }\n\n getColumnGroups(): ColumnGroup[] {\n return this.groups;\n }\n\n /** Render group headers in the same order as the painted columns. Reordering\n * can split one declared group into multiple visual runs; repeating its\n * label for each run keeps every colspan aligned with the columns below. */\n renderGroupHeaders(columnKeys = this.getVisibleColumns().map((column) => column.key)): string {\n if (this.groups.length === 0) return '';\n\n const groupForKey = new Map<string, ColumnGroup>();\n for (const group of this.groups) {\n for (const key of group.children) groupForKey.set(key, group);\n }\n\n const runs: { group: ColumnGroup | null; span: number }[] = [];\n for (const key of columnKeys) {\n if (!this.states.get(key)?.visible) continue;\n const group = groupForKey.get(key) ?? null;\n const current = runs[runs.length - 1];\n if (current && current.group === group) current.span++;\n else runs.push({ group, span: 1 });\n }\n\n return runs.map(({ group, span }) => {\n if (!group) {\n return `<th colspan=\"${span}\" class=\"column-group-header column-group-header--ungrouped\" aria-hidden=\"true\"></th>`;\n }\n return `<th colspan=\"${span}\" class=\"column-group-header ${group.headerClass || ''}\">${group.label}</th>`;\n }).join('');\n }\n\n isResizing(): boolean {\n return this.resizingKey !== null;\n }\n\n getState(key: string): ColumnState | undefined {\n return this.states.get(key);\n }\n\n /** Get sticky left offset for pinned-left columns */\n getPinnedLeftOffsets(): Map<string, number> {\n const offsets = new Map<string, number>();\n let left = 0;\n for (const col of this.getPinnedLeft()) {\n offsets.set(col.key, left);\n left += col.width;\n }\n return offsets;\n }\n\n /** Get sticky right offset for pinned-right columns */\n getPinnedRightOffsets(): Map<string, number> {\n const offsets = new Map<string, number>();\n const pinned = this.getPinnedRight();\n let right = 0;\n for (let i = pinned.length - 1; i >= 0; i--) {\n offsets.set(pinned[i].key, right);\n right += pinned[i].width;\n }\n return offsets;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table-column-manager.js","sources":["../../../../components/table/table-column-manager.ts"],"sourcesContent":["/**\n * Column management for snice-table.\n * Handles: flex width, resize, auto-size, visibility, ordering, pinning, groups.\n */\n\nimport type { ColumnDefinition, ColumnFit } from './snice-table.types';\n\n/** Padding + border a cell spends before any content fits inside it. */\nexport function horizontalCellChrome(cell: HTMLElement): number {\n const style = getComputedStyle(cell);\n const px = (value: string) => Number.parseFloat(value) || 0;\n return px(style.paddingLeft) + px(style.paddingRight)\n + px(style.borderLeftWidth) + px(style.borderRightWidth);\n}\n\nexport interface ColumnState {\n key: string;\n width: number; // Computed pixel width\n flex?: number; // Flex ratio (shares remaining space)\n minWidth: number; // Minimum width in px\n maxWidth: number; // Maximum width in px (Infinity = no limit)\n visible: boolean;\n pinned: 'left' | 'right' | false;\n order: number; // Display order\n resizable: boolean;\n reorderable: boolean;\n hideable: boolean;\n pinnable: boolean;\n /**\n * Someone chose this width on purpose — the column definition declared one,\n * the user dragged the edge, or auto-size measured the content. Only columns\n * that never did participate in `fitVisibleColumns`, so a deliberate width is\n * never quietly overwritten by the container's arithmetic.\n */\n authored: boolean;\n}\n\nexport interface ColumnGroup {\n label: string;\n children: string[]; // Column keys\n headerClass?: string;\n}\n\nexport class TableColumnManager {\n private states: Map<string, ColumnState> = new Map();\n private groups: ColumnGroup[] = [];\n private resizeStartX = 0;\n private resizeStartWidth = 0;\n private resizingKey: string | null = null;\n private resizeOverlay: HTMLElement | null = null;\n private tableElement: HTMLElement | null = null;\n private fitMode: ColumnFit = 'scroll';\n /**\n * The content budget the last `squish` fit shared out. A drag-resize needs it\n * to know how much width the columns beside the dragged one have to give up\n * (or take back) for the total to stay on the frame.\n */\n private squishBudget: number | null = null;\n\n /** Fallback content width for a column nobody sized. */\n static readonly DEFAULT_WIDTH = 150;\n\n /**\n * The floor `squish` relaxes `minWidth` down to. Not zero: a column narrower\n * than this shows no glyph at all, only its ellipsis, and stops being a\n * column the reader can identify. A frame too narrow even for this is past\n * what the mode can honour — see `fitVisibleColumns`.\n */\n static readonly SQUISH_MIN_WIDTH = 24;\n\n /**\n * Which fitting policy `fitVisibleColumns` (and a drag-resize) follows.\n * Owned by the table's `columnFit` property; see the `ColumnFit` docs.\n */\n setFitMode(mode: ColumnFit) {\n if (mode === this.fitMode) return;\n this.fitMode = mode;\n // The budget belongs to the squish fit that recorded it.\n if (mode !== 'squish') this.squishBudget = null;\n }\n\n getFitMode(): ColumnFit {\n return this.fitMode;\n }\n\n /**\n * Routine resync, run on every render: make sure a state exists for each\n * declared column and refresh the flags that are pure declaration (min/max,\n * resizable, reorderable, hideable, pinnable, flex).\n *\n * Deliberately PRESERVES the interaction-owned members of an existing state —\n * width, visible, pinned, order — because renderBody() calls this on every\n * paint, and re-applying the declaration here would undo a drag-resize, a\n * hidden column or a user reorder on the very next render. Re-applying the\n * declaration is applyConfiguration()'s job, and only a `columns` assignment\n * calls that.\n */\n initialize(columns: ColumnDefinition[], tableEl: HTMLElement) {\n this.tableElement = tableEl;\n columns.forEach((col, index) => {\n const existing = this.states.get(col.key);\n this.states.set(col.key, this.buildState(col, index, existing));\n });\n }\n\n /**\n * A `columns` assignment (or setColumns()) delivered a NEW CONFIGURATION.\n *\n * The declaration is the source of truth here: painted order, `pinned`,\n * `width` and visibility all come from the array just assigned, and states for\n * columns the new array no longer declares are DROPPED. Without this the first\n * configuration the table ever saw won permanently — a re-ordered array kept\n * the original order, a newly declared pin or width was ignored, and a column\n * hidden through setColumnVisible() could never be brought back\n * (MATRIX-columns-2/3/4/6).\n *\n * The cost is that the assignment also discards user interaction state (a\n * drag-resize, a manual reorder, a hidden column) for the columns it\n * re-declares. That is the intended reading of the contract, and it applies to\n * EVERY assignment: `columns` declares `hasChanged: () => true`, so handing\n * back the array the table already holds — after mutating it, or unchanged —\n * re-applies the declaration exactly like a fresh array would. Mutating the\n * published definitions is therefore NOT an escape hatch; the only way to keep\n * user column state is to not assign `columns` at all and drive the change\n * through the column APIs instead (setColumnVisible / moveColumn / pinColumn /\n * unpinColumn), which mutate the state map in place. Renders triggered by this\n * go through the table's coalescing queue, so re-applying costs no extra paint.\n */\n applyConfiguration(columns: ColumnDefinition[], tableEl: HTMLElement) {\n this.tableElement = tableEl;\n const next: Map<string, ColumnState> = new Map();\n columns.forEach((col, index) => {\n next.set(col.key, this.buildState(col, index));\n });\n this.states = next;\n }\n\n /**\n * One place that turns a column definition into a state. `existing` supplies\n * the interaction-owned members on the resync path; omitting it yields the\n * pure declared state applyConfiguration() wants.\n */\n private buildState(\n col: ColumnDefinition,\n index: number,\n existing?: ColumnState,\n ): ColumnState {\n const declared = this.parseWidth(col.width);\n return {\n key: col.key,\n width: existing?.width ?? declared ?? TableColumnManager.DEFAULT_WIDTH,\n flex: (col as any).flex,\n minWidth: (col as any).minWidth ?? 50,\n maxWidth: (col as any).maxWidth ?? Infinity,\n visible: existing?.visible ?? true,\n pinned: existing?.pinned ?? ((col as any).pinned || false),\n order: existing?.order ?? index,\n resizable: (col as any).resizable !== false,\n reorderable: (col as any).reorderable !== false,\n hideable: (col as any).hideable !== false,\n pinnable: (col as any).pinnable !== false,\n authored: existing?.authored ?? declared !== undefined,\n };\n }\n\n private parseWidth(width?: string): number | undefined {\n if (!width) return undefined;\n const num = parseInt(width, 10);\n return isNaN(num) ? undefined : num;\n }\n\n /** Get ordered, visible columns */\n getVisibleColumns(): ColumnState[] {\n return Array.from(this.states.values())\n .filter(s => s.visible)\n .sort((a, b) => a.order - b.order);\n }\n\n /** Get all column states */\n getAllStates(): ColumnState[] {\n return Array.from(this.states.values()).sort((a, b) => a.order - b.order);\n }\n\n /** Get columns pinned to left */\n getPinnedLeft(): ColumnState[] {\n return this.getVisibleColumns().filter(s => s.pinned === 'left');\n }\n\n /** Get columns pinned to right */\n getPinnedRight(): ColumnState[] {\n return this.getVisibleColumns().filter(s => s.pinned === 'right');\n }\n\n /** Get unpinned columns */\n getUnpinned(): ColumnState[] {\n return this.getVisibleColumns().filter(s => !s.pinned);\n }\n\n /** Compute flex widths based on available space */\n computeFlexWidths(availableWidth: number): Map<string, number> {\n const visible = this.getVisibleColumns();\n const widths = new Map<string, number>();\n\n // First pass: allocate fixed-width columns\n let fixedTotal = 0;\n const flexCols: ColumnState[] = [];\n\n for (const col of visible) {\n if (col.flex && col.flex > 0) {\n flexCols.push(col);\n } else {\n fixedTotal += col.width;\n widths.set(col.key, col.width);\n }\n }\n\n // Second pass: distribute remaining space to flex columns\n const remaining = Math.max(0, availableWidth - fixedTotal);\n const totalFlex = flexCols.reduce((sum, c) => sum + (c.flex || 1), 0);\n\n for (const col of flexCols) {\n const flexShare = ((col.flex || 1) / totalFlex) * remaining;\n const clamped = Math.max(col.minWidth, Math.min(col.maxWidth, flexShare));\n widths.set(col.key, clamped);\n }\n\n return widths;\n }\n\n /**\n * Fit the columns nobody sized into `availableWidth` (the frame's content\n * box), reserving `chromePerColumn` for each column's own padding + border.\n *\n * A column width is a CONTENT width — the rendered column is that plus its\n * chrome — so the budget has to come off the top or the fitted table lands a\n * few pixels wider than the frame it was fitted to.\n *\n * Declared and user-chosen widths are spent first and never rewritten: a\n * table that asked for `width: '80'` keeps 80 whatever the frame does. What\n * is left is split evenly and clamped to each column's [minWidth, maxWidth],\n * so a frame too narrow for the minimums overflows into the frame's own\n * scroller instead of collapsing the columns to nothing.\n *\n * Returns whether any width actually moved, so callers can skip a repaint.\n *\n * Under `column-fit=\"squish\"` the frame stops being a suggestion: see\n * `squishVisibleColumns`.\n */\n fitVisibleColumns(availableWidth: number, chromePerColumn = 0): boolean {\n const visible = this.getVisibleColumns();\n // A layoutless (or not-yet-laid-out) frame reports 0. Fitting to that would\n // slam every column to its minimum for a measurement that means nothing.\n if (visible.length === 0 || !(availableWidth > 0)) return false;\n\n const budget = availableWidth - visible.length * chromePerColumn;\n\n if (this.fitMode === 'squish') {\n this.squishBudget = budget;\n return this.squishVisibleColumns(visible, budget);\n }\n\n const auto = visible.filter((state) => !state.authored);\n if (auto.length === 0) return false;\n\n let remaining = budget;\n for (const state of visible) {\n if (state.authored) remaining -= state.width;\n }\n\n const share = Math.floor(remaining / auto.length);\n let changed = false;\n for (const state of auto) {\n const next = Math.max(state.minWidth, Math.min(state.maxWidth, share));\n if (next !== state.width) {\n state.width = next;\n changed = true;\n }\n }\n return changed;\n }\n\n /**\n * The `squish` policy: the columns add up to the frame, whatever that costs.\n *\n * `minWidth` is a readability preference, and this mode has already decided\n * the frame outranks it, so the only floor left is SQUISH_MIN_WIDTH. Two\n * cases:\n *\n * - There is an unsized column left to absorb the difference, and the\n * authored widths still leave room for it. Those are honoured exactly (a\n * column that asked for 80, or that the user dragged to 80, keeps 80) and\n * the rest is split evenly between the unsized ones.\n *\n * - Every column is authored, or the authored widths alone already overflow\n * the frame. There is nothing left to give, so `scroll`'s escape hatch\n * (overflow into the frame's scroller) is exactly what this mode exists to\n * prevent: every column is scaled by the same factor instead. Scaling is a\n * fixed point — the second pass computes a factor of 1 — so this settles\n * on the first render rather than creeping on every repaint.\n *\n * Either way the remainder from integer division is handed back to the widest\n * columns that are free to take it, so the widths sum to the budget EXACTLY\n * and the rightmost column edge lands on the frame's inner edge instead of a\n * few pixels short of it.\n */\n private squishVisibleColumns(visible: ColumnState[], budget: number): boolean {\n const floor = TableColumnManager.SQUISH_MIN_WIDTH;\n const auto = visible.filter((state) => !state.authored);\n // What the frame has left once the authored widths are paid for.\n const spare = budget - visible.reduce(\n (spent, state) => spent + (state.authored ? state.width : 0), 0,\n );\n\n const next = new Map<string, number>();\n if (auto.length > 0 && spare >= auto.length * floor) {\n const share = Math.floor(spare / auto.length);\n for (const state of visible) {\n next.set(state.key, state.authored\n ? state.width\n : Math.max(floor, Math.min(state.maxWidth, share)));\n }\n } else {\n const current = visible.reduce((sum, state) => sum + state.width, 0) || 1;\n const scale = budget / current;\n for (const state of visible) {\n next.set(state.key, Math.max(floor, Math.floor(state.width * scale)));\n }\n }\n\n // Hand the leftover pixels to the widest column that is free to grow: it\n // absorbs a few pixels without reading as a different column, and a\n // narrower one might be sitting on its floor or its maxWidth.\n let slack = budget - Array.from(next.values()).reduce((sum, w) => sum + w, 0);\n if (slack > 0) {\n const takers = visible\n .filter((state) => (next.get(state.key) ?? 0) < state.maxWidth)\n .sort((a, b) => (next.get(b.key) ?? 0) - (next.get(a.key) ?? 0));\n for (const state of takers) {\n if (slack <= 0) break;\n const room = Math.min(slack, state.maxWidth - (next.get(state.key) ?? 0));\n next.set(state.key, (next.get(state.key) ?? 0) + room);\n slack -= room;\n }\n }\n\n let changed = false;\n for (const state of visible) {\n const width = next.get(state.key)!;\n if (width !== state.width) {\n state.width = width;\n changed = true;\n }\n }\n return changed;\n }\n\n /**\n * A drag-resize under `squish` moved one column; the others pay for it.\n *\n * The dragged column is the anchor — it keeps the width the pointer asked\n * for, capped so the remaining columns can still sit on their floor — and the\n * rest are scaled to fill exactly what is left of the frame. Without this a\n * drag would simply push the trailing column out of a frame that is not\n * allowed to scroll.\n */\n private rebalanceSquish(anchorKey: string) {\n const budget = this.squishBudget;\n const anchor = this.states.get(anchorKey);\n if (budget === null || !anchor) return;\n\n const others = this.getVisibleColumns().filter((state) => state.key !== anchorKey);\n if (others.length === 0) return;\n\n const floor = TableColumnManager.SQUISH_MIN_WIDTH;\n anchor.width = Math.max(floor, Math.min(anchor.width, budget - others.length * floor));\n\n const remaining = budget - anchor.width;\n const current = others.reduce((sum, state) => sum + state.width, 0) || 1;\n const scale = remaining / current;\n for (const state of others) {\n state.width = Math.max(floor, Math.floor(state.width * scale));\n }\n\n let slack = remaining - others.reduce((sum, state) => sum + state.width, 0);\n for (const state of [...others].sort((a, b) => b.width - a.width)) {\n if (slack <= 0) break;\n const room = Math.min(slack, state.maxWidth - state.width);\n state.width += room;\n slack -= room;\n }\n }\n\n /** Push the current widths onto the painted header and body cells. */\n private writeWidths(keys: string[]) {\n const root = this.tableElement?.shadowRoot;\n if (!root) return;\n for (const key of keys) {\n const width = this.states.get(key)?.width;\n if (width === undefined) continue;\n const th = root.querySelector(`th[data-key=\"${key}\"]`) as HTMLElement | null;\n if (th) th.style.width = `${width}px`;\n const tds = root.querySelectorAll(`td[data-key=\"${key}\"]`) as NodeListOf<HTMLElement>;\n tds.forEach((td) => { td.style.width = `${width}px`; });\n }\n }\n\n /** Apply computed widths to <col> or <th> elements */\n applyWidths(headerRow: HTMLElement, widths: Map<string, number>) {\n const ths = headerRow.querySelectorAll('th[data-key]') as NodeListOf<HTMLElement>;\n ths.forEach(th => {\n const key = th.getAttribute('data-key');\n if (key && widths.has(key)) {\n th.style.width = `${widths.get(key)}px`;\n }\n });\n }\n\n // ── Resize ──\n\n /** Start column resize. Call from mousedown on resize handle. */\n startResize(columnKey: string, startX: number) {\n const state = this.states.get(columnKey);\n if (!state || !state.resizable) return;\n\n this.resizingKey = columnKey;\n this.resizeStartX = startX;\n this.resizeStartWidth = state.width;\n\n // Create overlay to capture mouse events\n this.resizeOverlay = document.createElement('div');\n this.resizeOverlay.style.cssText = 'position:fixed;inset:0;z-index:99999;cursor:col-resize;';\n document.body.appendChild(this.resizeOverlay);\n\n const onMove = (e: MouseEvent) => {\n e.preventDefault();\n const delta = e.clientX - this.resizeStartX;\n // Squish relaxes minWidth for the fit, so it has to relax it for the drag\n // too — otherwise a column the fit already squished below its minimum\n // would jump back up to it the moment its edge was touched.\n const squish = this.fitMode === 'squish';\n const min = squish ? TableColumnManager.SQUISH_MIN_WIDTH : state.minWidth;\n state.width = Math.max(min, Math.min(state.maxWidth, this.resizeStartWidth + delta));\n // Remove flex if manually resized\n state.flex = undefined;\n // The user chose this width — the container fit must leave it alone.\n state.authored = true;\n\n // Squish cannot let the drag push the table past the frame: the columns\n // beside this one give up (or take back) the difference.\n if (squish) this.rebalanceSquish(columnKey);\n this.writeWidths(squish\n ? this.getVisibleColumns().map((column) => column.key)\n : [columnKey]);\n\n // Dispatch resize event\n this.tableElement?.dispatchEvent(new CustomEvent('column-resize', {\n detail: { key: columnKey, width: state.width },\n bubbles: true, composed: true\n }));\n };\n\n const onUp = () => {\n this.resizingKey = null;\n this.resizeOverlay?.remove();\n this.resizeOverlay = null;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n\n this.tableElement?.dispatchEvent(new CustomEvent('column-resize-end', {\n detail: { key: columnKey, width: state.width },\n bubbles: true, composed: true\n }));\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n }\n\n /** Auto-size a column to fit its content */\n autoSizeColumn(columnKey: string, tbody: HTMLElement) {\n this.autoSizeColumns([columnKey], tbody);\n }\n\n /** Auto-size all columns */\n autoSizeAll(tbody: HTMLElement) {\n this.autoSizeColumns(Array.from(this.states.keys()), tbody);\n }\n\n /** Slack added to a measured content width so the last glyph never sits on\n * the clip edge (and a sortable header keeps room for its chevron). */\n private static readonly AUTO_SIZE_SLACK = 4;\n\n /**\n * Measure the columns' content and give each the width it actually needs.\n *\n * A table cell's `scrollWidth` is NOT its content width: for content that\n * fits, it reports the padding box — the width the column already has. The\n * previous implementation took that maximum and added 16px, so every\n * \"auto-size\" pass could only GROW the column, by a chrome's worth each\n * time, until the table outgrew its own frame. Once it did, the right-pinned\n * column (`position: sticky`) parked over the columns beside it, and the\n * columns behind it read as deleted.\n *\n * The width a column NEEDS is a layout question, so ask layout: drop the\n * table into content-driven sizing (`table-layout: auto` at `max-content`)\n * with the measured columns' imposed widths removed, and read back the width\n * each header settles at. `max-content` also means no wrapping, so a long\n * cell reports its full single-line extent even though the painted column\n * ellipsises it. Everything is restored in the same task, before paint.\n */\n private autoSizeColumns(columnKeys: string[], tbody: HTMLElement) {\n const root = this.tableElement?.shadowRoot ?? null;\n const tableEl = (root?.querySelector('table')\n ?? tbody.closest('table')) as HTMLElement | null;\n const targets = columnKeys\n .map((key) => this.states.get(key))\n .filter((state): state is ColumnState => !!state);\n if (!tableEl || targets.length === 0) return;\n\n const restore: Array<() => void> = [];\n const push = (el: HTMLElement, property: 'width' | 'tableLayout') => {\n const previous = el.style[property];\n restore.push(() => { el.style[property] = previous; });\n };\n\n push(tableEl, 'tableLayout');\n push(tableEl, 'width');\n tableEl.style.tableLayout = 'auto';\n tableEl.style.width = 'max-content';\n\n const headers = new Map<string, HTMLElement>();\n for (const state of targets) {\n const header = root?.querySelector(`th[data-key=\"${state.key}\"]`) as HTMLElement | null;\n if (!header) continue;\n headers.set(state.key, header);\n // An imposed width is still a preferred width under auto layout, so it\n // has to come off before the column can report what it wants.\n push(header, 'width');\n header.style.width = 'auto';\n for (const cell of Array.from(\n tbody.querySelectorAll(`td[data-key=\"${state.key}\"]`),\n ) as HTMLElement[]) {\n push(cell, 'width');\n cell.style.width = 'auto';\n }\n }\n\n const widths = new Map<string, number>();\n for (const [key, header] of headers) {\n widths.set(key, header.getBoundingClientRect().width - horizontalCellChrome(header));\n }\n\n for (const undo of restore) undo();\n\n for (const state of targets) {\n const content = widths.get(state.key) ?? 0;\n // Nothing measurable — a layoutless DOM, or a column with no rendered\n // header. Leave the width alone rather than slamming it to the minimum.\n if (content <= 0) continue;\n state.width = Math.max(\n state.minWidth,\n Math.min(state.maxWidth, Math.ceil(content) + TableColumnManager.AUTO_SIZE_SLACK),\n );\n state.flex = undefined;\n state.authored = true;\n }\n }\n\n // ── Visibility ──\n\n setColumnVisible(key: string, visible: boolean) {\n const state = this.states.get(key);\n if (state && state.hideable) {\n state.visible = visible;\n }\n }\n\n showAllColumns() {\n for (const state of this.states.values()) {\n state.visible = true;\n }\n }\n\n hideAllColumns() {\n for (const state of this.states.values()) {\n if (state.hideable) state.visible = false;\n }\n }\n\n getVisibilityModel(): Record<string, boolean> {\n const model: Record<string, boolean> = {};\n for (const [key, state] of this.states) {\n model[key] = state.visible;\n }\n return model;\n }\n\n // ── Ordering ──\n\n moveColumn(key: string, toIndex: number) {\n const state = this.states.get(key);\n if (!state || !state.reorderable || state.pinned) return;\n\n const ordered = this.getVisibleColumns();\n const fromIndex = ordered.findIndex(s => s.key === key);\n if (fromIndex === -1 || fromIndex === toIndex) return;\n\n // Recompute order values\n ordered.splice(fromIndex, 1);\n ordered.splice(toIndex, 0, state);\n ordered.forEach((s, i) => { s.order = i; });\n }\n\n // ── Pinning ──\n\n pinColumn(key: string, side: 'left' | 'right') {\n const state = this.states.get(key);\n if (state && state.pinnable) {\n state.pinned = side;\n }\n }\n\n unpinColumn(key: string) {\n const state = this.states.get(key);\n if (state) {\n state.pinned = false;\n }\n }\n\n // ── Groups ──\n\n setColumnGroups(groups: ColumnGroup[]) {\n this.groups = groups;\n }\n\n getColumnGroups(): ColumnGroup[] {\n return this.groups;\n }\n\n /** Render group headers in the same order as the painted columns. Reordering\n * can split one declared group into multiple visual runs; repeating its\n * label for each run keeps every colspan aligned with the columns below. */\n renderGroupHeaders(columnKeys = this.getVisibleColumns().map((column) => column.key)): string {\n if (this.groups.length === 0) return '';\n\n const groupForKey = new Map<string, ColumnGroup>();\n for (const group of this.groups) {\n for (const key of group.children) groupForKey.set(key, group);\n }\n\n const runs: { group: ColumnGroup | null; span: number }[] = [];\n for (const key of columnKeys) {\n if (!this.states.get(key)?.visible) continue;\n const group = groupForKey.get(key) ?? null;\n const current = runs[runs.length - 1];\n if (current && current.group === group) current.span++;\n else runs.push({ group, span: 1 });\n }\n\n return runs.map(({ group, span }) => {\n if (!group) {\n return `<th colspan=\"${span}\" class=\"column-group-header column-group-header--ungrouped\" aria-hidden=\"true\"></th>`;\n }\n return `<th colspan=\"${span}\" class=\"column-group-header ${group.headerClass || ''}\">${group.label}</th>`;\n }).join('');\n }\n\n isResizing(): boolean {\n return this.resizingKey !== null;\n }\n\n getState(key: string): ColumnState | undefined {\n return this.states.get(key);\n }\n\n /** Get sticky left offset for pinned-left columns */\n getPinnedLeftOffsets(): Map<string, number> {\n const offsets = new Map<string, number>();\n let left = 0;\n for (const col of this.getPinnedLeft()) {\n offsets.set(col.key, left);\n left += col.width;\n }\n return offsets;\n }\n\n /** Get sticky right offset for pinned-right columns */\n getPinnedRightOffsets(): Map<string, number> {\n const offsets = new Map<string, number>();\n const pinned = this.getPinnedRight();\n let right = 0;\n for (let i = pinned.length - 1; i >= 0; i--) {\n offsets.set(pinned[i].key, right);\n right += pinned[i].width;\n }\n return offsets;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date parsing for the table's cell layer.
|
|
3
|
+
*
|
|
4
|
+
* A column of type `date` usually carries calendar dates: `'2026-03-15'` names
|
|
5
|
+
* a day, not an instant. `new Date('2026-03-15')` nevertheless resolves the
|
|
6
|
+
* ISO date-only forms as UTC midnight (ECMA-262 21.4.3.2), so every consumer
|
|
7
|
+
* in a negative-offset zone formatted the day BEFORE the authored one, while
|
|
8
|
+
* an `<input type="date">` editor holding the same string showed the authored
|
|
9
|
+
* day. Display, export, and filtering must all agree with the string the
|
|
10
|
+
* application wrote.
|
|
11
|
+
*
|
|
12
|
+
* The rule: a value that carries NO time is a calendar day and is read at
|
|
13
|
+
* local midnight; anything that carries a time (or an offset, or is already a
|
|
14
|
+
* `Date`/epoch number) is an instant and is left to the platform.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Parse a cell value into a `Date`, or `null` when there is nothing to show.
|
|
18
|
+
*
|
|
19
|
+
* `null` covers the empty cases (`null`, `undefined`, `''`) and unparseable
|
|
20
|
+
* input alike, so callers fall back to the raw value rather than rendering
|
|
21
|
+
* "Invalid Date" or the epoch.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseCellDate(value: unknown): Date | null;
|
|
24
|
+
/**
|
|
25
|
+
* Midnight on the calendar day a value falls on, in local time. Used by
|
|
26
|
+
* day-granularity comparisons (today/past/future classification) so an
|
|
27
|
+
* instant is never bumped across a day boundary by the UTC offset.
|
|
28
|
+
*/
|
|
29
|
+
export declare function startOfLocalDay(date: Date): Date;
|