@revisium/schema-toolkit-ui 0.5.0 → 0.6.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/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as mobx from "mobx";
2
- import { comparer, computed, makeAutoObservable, observable, reaction, runInAction } from "mobx";
2
+ import { comparer, computed, makeAutoObservable, observable, reaction, runInAction, untracked } from "mobx";
3
3
  import { FIELD_NAME_ERROR_MESSAGE, SchemaParser, SystemSchemaIds, arr, createRowModel, createTableModel, fileSchema, generateDefaultValue, isForeignKeyValueNode, isValidFieldName, jsonPointerToSimplePath, num, obj, rowCreatedAtSchema, rowCreatedIdSchema, rowHashSchema, rowIdSchema, rowPublishedAtSchema, rowSchemaHashSchema, rowUpdatedAtSchema, rowVersionIdSchema, str, validateFormulaAgainstSchema } from "@revisium/schema-toolkit";
4
4
  import { createMobxProvider, setReactivityProvider } from "@revisium/schema-toolkit/core";
5
5
  import { ActionBar, Badge, Box, Button, Checkbox, Flex, HStack, HoverCard, Icon, IconButton, Image, Input, Kbd, Menu, Popover, Portal, SegmentGroup, Spinner, Text, Textarea, Tooltip as Tooltip$1, VStack } from "@chakra-ui/react";
@@ -2918,6 +2918,7 @@ const PlusButton = ({ onClick, tooltip, disabled, dataTestId }) => {
2918
2918
  variant: "ghost",
2919
2919
  color: "gray.400",
2920
2920
  disabled,
2921
+ focusRing: "none",
2921
2922
  _hover: {
2922
2923
  bg: "gray.100",
2923
2924
  color: "gray.600"
@@ -7005,12 +7006,29 @@ function selectDefaultColumns(columns, maxVisible = 4) {
7005
7006
  //#endregion
7006
7007
  //#region src/table-editor/Columns/model/ColumnsModel.ts
7007
7008
  const DEFAULT_COLUMN_WIDTH = 150;
7009
+ const DEFAULT_ID_COLUMN_WIDTH = 240;
7010
+ function isValidPinZoneOrder(fields, pins) {
7011
+ let zone = "left";
7012
+ for (const field of fields) {
7013
+ const pin = pins.get(field);
7014
+ if (zone === "left") {
7015
+ if (pin === "right") zone = "right";
7016
+ else if (pin === void 0) zone = "none";
7017
+ } else if (zone === "none") {
7018
+ if (pin === "left") return false;
7019
+ if (pin === "right") zone = "right";
7020
+ } else if (pin !== "right") return false;
7021
+ }
7022
+ return true;
7023
+ }
7008
7024
  var ColumnsModel = class {
7009
7025
  _allColumns = [];
7010
7026
  _visibleFields = [];
7011
7027
  _columnWidths = observable.map();
7012
7028
  _pinnedColumns = observable.map();
7013
7029
  _onChange = null;
7030
+ _isResizing = false;
7031
+ _wrapperElement = null;
7014
7032
  constructor() {
7015
7033
  makeAutoObservable(this, {}, { autoBind: true });
7016
7034
  }
@@ -7169,17 +7187,36 @@ var ColumnsModel = class {
7169
7187
  this._visibleFields = fields;
7170
7188
  this._notifyChange();
7171
7189
  }
7190
+ get isResizing() {
7191
+ return this._isResizing;
7192
+ }
7193
+ setWrapperElement(el) {
7194
+ this._wrapperElement = el;
7195
+ }
7172
7196
  setColumnWidth(field, width) {
7197
+ this._isResizing = true;
7173
7198
  this._columnWidths.set(field, width);
7199
+ if (this._wrapperElement) this._wrapperElement.style.setProperty(`--cw-${field}`, `${width}px`);
7174
7200
  }
7175
7201
  commitColumnWidth() {
7202
+ this._isResizing = false;
7176
7203
  this._notifyChange();
7177
7204
  }
7178
7205
  getColumnWidth(field) {
7179
7206
  return this._columnWidths.get(field);
7180
7207
  }
7181
7208
  resolveColumnWidth(field) {
7182
- return this._columnWidths.get(field) ?? DEFAULT_COLUMN_WIDTH;
7209
+ return this._resolveWidthUntracked(field);
7210
+ }
7211
+ get columnWidthCssVars() {
7212
+ if (this._isResizing) return this._buildCssVarsUntracked();
7213
+ return this._buildCssVarsTracked();
7214
+ }
7215
+ getWidthCssVarsDuringResize() {
7216
+ return this._buildCssVarsUntracked();
7217
+ }
7218
+ columnWidthCssVar(field) {
7219
+ return `var(--cw-${field}, ${field === "id" ? DEFAULT_ID_COLUMN_WIDTH : DEFAULT_COLUMN_WIDTH}px)`;
7183
7220
  }
7184
7221
  getPinState(field) {
7185
7222
  return this._pinnedColumns.get(field);
@@ -7237,7 +7274,7 @@ var ColumnsModel = class {
7237
7274
  let offset = selectionWidth;
7238
7275
  for (const f of this._visibleFields) {
7239
7276
  if (f === field) break;
7240
- if (this._pinnedColumns.get(f) === "left") offset += this.resolveColumnWidth(f);
7277
+ if (this._pinnedColumns.get(f) === "left") offset += this._resolveWidthUntracked(f);
7241
7278
  }
7242
7279
  return offset;
7243
7280
  }
@@ -7250,10 +7287,37 @@ var ColumnsModel = class {
7250
7287
  found = true;
7251
7288
  continue;
7252
7289
  }
7253
- if (found && this._pinnedColumns.get(f) === "right") offset += this.resolveColumnWidth(f);
7290
+ if (found && this._pinnedColumns.get(f) === "right") offset += this._resolveWidthUntracked(f);
7254
7291
  }
7255
7292
  return offset;
7256
7293
  }
7294
+ getColumnStickyLeftCss(field, selectionWidth) {
7295
+ if (this._pinnedColumns.get(field) !== "left") return;
7296
+ const parts = [];
7297
+ if (selectionWidth > 0) parts.push(`${selectionWidth}px`);
7298
+ for (const f of this._visibleFields) {
7299
+ if (f === field) break;
7300
+ if (this._pinnedColumns.get(f) === "left") parts.push(this.columnWidthCssVar(f));
7301
+ }
7302
+ if (parts.length === 0) return "0px";
7303
+ if (parts.length === 1) return parts[0];
7304
+ return `calc(${parts.join(" + ")})`;
7305
+ }
7306
+ getColumnStickyRightCss(field) {
7307
+ if (this._pinnedColumns.get(field) !== "right") return;
7308
+ const parts = [];
7309
+ let found = false;
7310
+ for (const f of this._visibleFields) {
7311
+ if (f === field) {
7312
+ found = true;
7313
+ continue;
7314
+ }
7315
+ if (found && this._pinnedColumns.get(f) === "right") parts.push(this.columnWidthCssVar(f));
7316
+ }
7317
+ if (parts.length === 0) return "0px";
7318
+ if (parts.length === 1) return parts[0];
7319
+ return `calc(${parts.join(" + ")})`;
7320
+ }
7257
7321
  isStickyLeftBoundary(field) {
7258
7322
  if (this._pinnedColumns.get(field) !== "left") return false;
7259
7323
  const index = this.getColumnIndex(field);
@@ -7289,16 +7353,20 @@ var ColumnsModel = class {
7289
7353
  applyViewColumns(viewColumns) {
7290
7354
  const lookup = this._columnLookup;
7291
7355
  const fields = [];
7292
- this._columnWidths.clear();
7293
- this._pinnedColumns.clear();
7356
+ const widths = /* @__PURE__ */ new Map();
7357
+ const pins = /* @__PURE__ */ new Map();
7294
7358
  for (const vc of viewColumns) {
7295
7359
  const field = this._fromViewField(vc.field);
7296
7360
  if (lookup.has(field)) {
7297
7361
  fields.push(field);
7298
- if (vc.width !== void 0) this._columnWidths.set(field, vc.width);
7299
- if (vc.pinned !== void 0) this._pinnedColumns.set(field, vc.pinned);
7362
+ if (vc.width !== void 0) widths.set(field, vc.width);
7363
+ if (vc.pinned !== void 0) pins.set(field, vc.pinned);
7300
7364
  }
7301
7365
  }
7366
+ this._columnWidths.clear();
7367
+ this._pinnedColumns.clear();
7368
+ for (const [field, width] of widths) this._columnWidths.set(field, width);
7369
+ if (isValidPinZoneOrder(fields, pins)) for (const [field, side] of pins) this._pinnedColumns.set(field, side);
7302
7370
  if (fields.length === 0) this._visibleFields = selectDefaultColumns(this._allColumns).map((col) => col.field);
7303
7371
  else this._visibleFields = fields;
7304
7372
  }
@@ -7368,6 +7436,27 @@ var ColumnsModel = class {
7368
7436
  if (viewField.startsWith("data.")) return viewField.slice(5);
7369
7437
  return viewField;
7370
7438
  }
7439
+ _resolveWidthUntracked(field) {
7440
+ return untracked(() => this._columnWidths.get(field) ?? (field === "id" ? DEFAULT_ID_COLUMN_WIDTH : DEFAULT_COLUMN_WIDTH));
7441
+ }
7442
+ _buildCssVarsTracked() {
7443
+ const vars = {};
7444
+ for (const field of this._visibleFields) {
7445
+ const width = this._columnWidths.get(field) ?? (field === "id" ? DEFAULT_ID_COLUMN_WIDTH : DEFAULT_COLUMN_WIDTH);
7446
+ vars[`--cw-${field}`] = `${width}px`;
7447
+ }
7448
+ return vars;
7449
+ }
7450
+ _buildCssVarsUntracked() {
7451
+ return untracked(() => {
7452
+ const vars = {};
7453
+ for (const field of this._visibleFields) {
7454
+ const width = this._columnWidths.get(field) ?? (field === "id" ? DEFAULT_ID_COLUMN_WIDTH : DEFAULT_COLUMN_WIDTH);
7455
+ vars[`--cw-${field}`] = `${width}px`;
7456
+ }
7457
+ return vars;
7458
+ });
7459
+ }
7371
7460
  _notifyChange() {
7372
7461
  if (this._onChange) this._onChange();
7373
7462
  }
@@ -9782,15 +9871,6 @@ function cellAt(ctx, colIndex, rowIndex) {
9782
9871
  field
9783
9872
  };
9784
9873
  }
9785
- function cellPosition(ctx, cell) {
9786
- const colIndex = ctx.columns.indexOf(cell.field);
9787
- const rowIndex = ctx.rowIds.indexOf(cell.rowId);
9788
- if (colIndex === -1 || rowIndex === -1) return null;
9789
- return {
9790
- colIndex,
9791
- rowIndex
9792
- };
9793
- }
9794
9874
  function createConfig() {
9795
9875
  return {
9796
9876
  initial: "idle",
@@ -9954,11 +10034,37 @@ function createConfig() {
9954
10034
 
9955
10035
  //#endregion
9956
10036
  //#region src/table-editor/Table/model/CellFSM.ts
10037
+ const READONLY_TOAST_THROTTLE_MS = 2e3;
10038
+ function buildIndexMap(arr) {
10039
+ const map = /* @__PURE__ */ new Map();
10040
+ arr.forEach((value, i) => {
10041
+ map.set(value, i);
10042
+ });
10043
+ return map;
10044
+ }
10045
+ function selectedRangeEquals(a, b) {
10046
+ if (a === b) return true;
10047
+ if (!a || !b) return false;
10048
+ return a.startCol === b.startCol && a.endCol === b.endCol && a.startRow === b.startRow && a.endRow === b.endRow;
10049
+ }
9957
10050
  var CellFSM = class {
9958
10051
  _fsm;
10052
+ _onReadonlyEditAttempt = null;
10053
+ _lastReadonlyToastAt = 0;
10054
+ _columnIndexMap = /* @__PURE__ */ new Map();
10055
+ _rowIndexMap = /* @__PURE__ */ new Map();
9959
10056
  constructor() {
9960
10057
  this._fsm = new ObservableFSM(createConfig());
9961
- makeAutoObservable(this, {}, { autoBind: true });
10058
+ makeAutoObservable(this, { selectedRange: computed({ equals: selectedRangeEquals }) }, { autoBind: true });
10059
+ }
10060
+ setOnReadonlyEditAttempt(cb) {
10061
+ this._onReadonlyEditAttempt = cb;
10062
+ }
10063
+ notifyReadonlyEditAttempt() {
10064
+ const now = Date.now();
10065
+ if (now - this._lastReadonlyToastAt < READONLY_TOAST_THROTTLE_MS) return;
10066
+ this._lastReadonlyToastAt = now;
10067
+ this._onReadonlyEditAttempt?.();
9962
10068
  }
9963
10069
  get state() {
9964
10070
  return this._fsm.state;
@@ -9981,8 +10087,14 @@ var CellFSM = class {
9981
10087
  get navigationVersion() {
9982
10088
  return this._fsm.context.navigationVersion;
9983
10089
  }
10090
+ get columnIndexMap() {
10091
+ return this._columnIndexMap;
10092
+ }
10093
+ get rowIndexMap() {
10094
+ return this._rowIndexMap;
10095
+ }
9984
10096
  get hasSelection() {
9985
- return this.getSelectedRange() !== null;
10097
+ return this.selectedRange !== null;
9986
10098
  }
9987
10099
  isCellFocused(rowId, field) {
9988
10100
  const cell = this._fsm.context.focusedCell;
@@ -9998,54 +10110,53 @@ var CellFSM = class {
9998
10110
  return this._fsm.matches("editing") && this.isCellFocused(rowId, field);
9999
10111
  }
10000
10112
  isCellInSelection(rowId, field) {
10001
- const range = this.getSelectedRange();
10113
+ const range = this.selectedRange;
10002
10114
  if (!range) return false;
10003
- const pos = this._getCellPosition(rowId, field);
10004
- if (!pos) return false;
10005
- return pos.colIndex >= range.startCol && pos.colIndex <= range.endCol && pos.rowIndex >= range.startRow && pos.rowIndex <= range.endRow;
10115
+ const colIndex = this._columnIndexMap.get(field);
10116
+ const rowIndex = this._rowIndexMap.get(rowId);
10117
+ if (colIndex === void 0 || rowIndex === void 0) return false;
10118
+ return colIndex >= range.startCol && colIndex <= range.endCol && rowIndex >= range.startRow && rowIndex <= range.endRow;
10006
10119
  }
10007
10120
  getCellSelectionEdges(rowId, field) {
10008
- const range = this.getSelectedRange();
10121
+ const range = this.selectedRange;
10009
10122
  if (!range) return null;
10010
- const pos = this._getCellPosition(rowId, field);
10011
- if (!pos) return null;
10012
- if (pos.colIndex < range.startCol || pos.colIndex > range.endCol || pos.rowIndex < range.startRow || pos.rowIndex > range.endRow) return null;
10123
+ const colIndex = this._columnIndexMap.get(field);
10124
+ const rowIndex = this._rowIndexMap.get(rowId);
10125
+ if (colIndex === void 0 || rowIndex === void 0) return null;
10126
+ if (colIndex < range.startCol || colIndex > range.endCol || rowIndex < range.startRow || rowIndex > range.endRow) return null;
10013
10127
  return {
10014
- top: pos.rowIndex === range.startRow,
10015
- bottom: pos.rowIndex === range.endRow,
10016
- left: pos.colIndex === range.startCol,
10017
- right: pos.colIndex === range.endCol
10128
+ top: rowIndex === range.startRow,
10129
+ bottom: rowIndex === range.endRow,
10130
+ left: colIndex === range.startCol,
10131
+ right: colIndex === range.endCol
10018
10132
  };
10019
10133
  }
10020
- _getCellPosition(rowId, field) {
10021
- const ctx = this._fsm.context;
10022
- const colIndex = ctx.columns.indexOf(field);
10023
- const rowIndex = ctx.rowIds.indexOf(rowId);
10024
- if (colIndex === -1 || rowIndex === -1) return null;
10025
- return {
10026
- colIndex,
10027
- rowIndex
10028
- };
10029
- }
10030
- getSelectedRange() {
10134
+ get selectedRange() {
10031
10135
  const ctx = this._fsm.context;
10032
10136
  if (!ctx.anchorCell || !ctx.focusedCell) return null;
10033
10137
  if (ctx.anchorCell.rowId === ctx.focusedCell.rowId && ctx.anchorCell.field === ctx.focusedCell.field) return null;
10034
- const anchorPos = cellPosition(ctx, ctx.anchorCell);
10035
- const focusPos = cellPosition(ctx, ctx.focusedCell);
10036
- if (!anchorPos || !focusPos) return null;
10138
+ const anchorCol = this._columnIndexMap.get(ctx.anchorCell.field);
10139
+ const anchorRow = this._rowIndexMap.get(ctx.anchorCell.rowId);
10140
+ const focusCol = this._columnIndexMap.get(ctx.focusedCell.field);
10141
+ const focusRow = this._rowIndexMap.get(ctx.focusedCell.rowId);
10142
+ if (anchorCol === void 0 || anchorRow === void 0 || focusCol === void 0 || focusRow === void 0) return null;
10037
10143
  return {
10038
- startCol: Math.min(anchorPos.colIndex, focusPos.colIndex),
10039
- endCol: Math.max(anchorPos.colIndex, focusPos.colIndex),
10040
- startRow: Math.min(anchorPos.rowIndex, focusPos.rowIndex),
10041
- endRow: Math.max(anchorPos.rowIndex, focusPos.rowIndex)
10144
+ startCol: Math.min(anchorCol, focusCol),
10145
+ endCol: Math.max(anchorCol, focusCol),
10146
+ startRow: Math.min(anchorRow, focusRow),
10147
+ endRow: Math.max(anchorRow, focusRow)
10042
10148
  };
10043
10149
  }
10150
+ getSelectedRange() {
10151
+ return this.selectedRange;
10152
+ }
10044
10153
  setNavigationContext(columns, rowIds) {
10045
10154
  Object.assign(this._fsm.context, {
10046
10155
  columns,
10047
10156
  rowIds
10048
10157
  });
10158
+ this._columnIndexMap = buildIndexMap(columns);
10159
+ this._rowIndexMap = buildIndexMap(rowIds);
10049
10160
  }
10050
10161
  updateNavigationContext(columns, rowIds) {
10051
10162
  const ctx = this._fsm.context;
@@ -10053,8 +10164,10 @@ var CellFSM = class {
10053
10164
  ctx.columns = columns;
10054
10165
  ctx.rowIds = rowIds;
10055
10166
  ctx.navigationVersion++;
10167
+ this._columnIndexMap = buildIndexMap(columns);
10168
+ this._rowIndexMap = buildIndexMap(rowIds);
10056
10169
  if (!focused) return;
10057
- if (columns.includes(focused.field) && rowIds.includes(focused.rowId)) ctx.anchorCell = null;
10170
+ if (this._columnIndexMap.has(focused.field) && this._rowIndexMap.has(focused.rowId)) ctx.anchorCell = null;
10058
10171
  else this.blur();
10059
10172
  }
10060
10173
  focusCell(cell) {
@@ -10338,6 +10451,9 @@ var CellVM = class {
10338
10451
  const newValue = node.getPlainValue();
10339
10452
  if (newValue !== previousValue) this._onCommit?.(this._rowId, this._column.field, newValue, previousValue);
10340
10453
  }
10454
+ notifyReadonlyEditAttempt() {
10455
+ this._cellFSM.notifyReadonlyEditAttempt();
10456
+ }
10341
10457
  blur() {
10342
10458
  this._cellFSM.blur();
10343
10459
  }
@@ -10763,34 +10879,52 @@ function useDeferredMenuEdit(editFn) {
10763
10879
  };
10764
10880
  }
10765
10881
 
10882
+ //#endregion
10883
+ //#region src/table-editor/Table/ui/borderConstants.ts
10884
+ const CELL_BORDER_COLOR = "#ededed";
10885
+ const BOTTOM_BORDER_SHADOW = `inset 0 -1px 0 0 ${CELL_BORDER_COLOR}`;
10886
+ function buildAddColumnShadowCss() {
10887
+ return { "&::after": {
10888
+ content: "\"\"",
10889
+ position: "absolute",
10890
+ top: 0,
10891
+ bottom: 0,
10892
+ width: "8px",
10893
+ left: "-8px",
10894
+ pointerEvents: "none",
10895
+ transition: "opacity 0.15s",
10896
+ opacity: "var(--shadow-right-opacity, 0)",
10897
+ boxShadow: "inset -8px 0 12px -8px rgba(0,0,0,0.1)"
10898
+ } };
10899
+ }
10900
+ function adjustRightOffsetCss(rightCss, addColOffset) {
10901
+ if (addColOffset <= 0) return rightCss;
10902
+ if (rightCss === "0px") return `${addColOffset}px`;
10903
+ return `calc(${rightCss} + ${addColOffset}px)`;
10904
+ }
10905
+
10766
10906
  //#endregion
10767
10907
  //#region src/table-editor/Table/ui/Cell/cellStyles.ts
10768
10908
  const FOCUS_RING_RESET = {
10769
10909
  outline: "none",
10770
10910
  boxShadow: "none"
10771
10911
  };
10772
- const RANGE_BORDER_COLOR = "blue.400";
10773
- function buildSelectionBorderStyle(edges) {
10774
- return {
10775
- content: "\"\"",
10776
- position: "absolute",
10777
- top: edges.top ? "-1px" : 0,
10778
- bottom: edges.bottom ? "-1px" : 0,
10779
- left: edges.left ? "-1px" : 0,
10780
- right: edges.right ? "-1px" : 0,
10781
- borderTop: edges.top ? "2px solid" : "none",
10782
- borderBottom: edges.bottom ? "2px solid" : "none",
10783
- borderLeft: edges.left ? "2px solid" : "none",
10784
- borderRight: edges.right ? "2px solid" : "none",
10785
- borderColor: RANGE_BORDER_COLOR,
10786
- pointerEvents: "none",
10787
- zIndex: 2
10788
- };
10912
+ const SELECTION_BORDER_COLOR = "#3b82f6";
10913
+ function buildSelectionBoxShadow(edges) {
10914
+ const shadows = [];
10915
+ if (edges.top) shadows.push(`inset 0 2px 0 0 ${SELECTION_BORDER_COLOR}`);
10916
+ if (edges.bottom) shadows.push(`inset 0 -2px 0 0 ${SELECTION_BORDER_COLOR}`);
10917
+ if (edges.left) shadows.push(`inset 2px 0 0 0 ${SELECTION_BORDER_COLOR}`);
10918
+ if (edges.right) shadows.push(`inset -2px 0 0 0 ${SELECTION_BORDER_COLOR}`);
10919
+ return shadows.length > 0 ? shadows.join(", ") : null;
10789
10920
  }
10790
10921
  const stateStyles = {
10791
10922
  display: {
10792
10923
  cursor: "cell",
10793
- _hover: { bg: "gray.50" }
10924
+ _hover: {
10925
+ bg: "gray.50",
10926
+ boxShadow: BOTTOM_BORDER_SHADOW
10927
+ }
10794
10928
  },
10795
10929
  focused: {
10796
10930
  cursor: "cell",
@@ -10824,11 +10958,14 @@ const stateStyles = {
10824
10958
  _focusVisible: FOCUS_RING_RESET
10825
10959
  },
10826
10960
  readonly: {
10827
- cursor: "default",
10828
- color: "gray.500"
10961
+ cursor: "cell",
10962
+ _hover: {
10963
+ bg: "gray.50",
10964
+ boxShadow: BOTTOM_BORDER_SHADOW
10965
+ }
10829
10966
  },
10830
10967
  readonlyFocused: {
10831
- cursor: "default",
10968
+ cursor: "cell",
10832
10969
  bg: "gray.50",
10833
10970
  _before: {
10834
10971
  content: "\"\"",
@@ -10872,7 +11009,10 @@ function handleArrowKey(cell, e, shiftAction, moveAction) {
10872
11009
  else moveAction();
10873
11010
  }
10874
11011
  function handleEditableKeys(cell, e, onStartEdit, onDoubleClick, onTypeChar, onDelete) {
10875
- if (cell.isReadOnly) return;
11012
+ if (cell.isReadOnly) {
11013
+ if (e.key === "Enter" || e.key === "Delete" || e.key === "Backspace" || isPrintableKey(e)) cell.notifyReadonlyEditAttempt();
11014
+ return;
11015
+ }
10876
11016
  const hasRange = cell.hasRangeSelection;
10877
11017
  if (!hasRange && e.key === "Enter") {
10878
11018
  e.preventDefault();
@@ -10920,8 +11060,16 @@ const CellWrapper = observer(({ cell, children, onDoubleClick, onStartEdit, onTy
10920
11060
  if (e.buttons === 1) cell.dragExtend();
10921
11061
  }, [cell]);
10922
11062
  const handleDoubleClick = useCallback((e) => {
10923
- if (state !== "readonly" && state !== "readonlyFocused") onDoubleClick?.(e.clientX);
10924
- }, [state, onDoubleClick]);
11063
+ if (state === "readonly" || state === "readonlyFocused") {
11064
+ cell.notifyReadonlyEditAttempt();
11065
+ return;
11066
+ }
11067
+ onDoubleClick?.(e.clientX);
11068
+ }, [
11069
+ state,
11070
+ cell,
11071
+ onDoubleClick
11072
+ ]);
10925
11073
  const handleKeyDown = useCallback((e) => {
10926
11074
  if (!(state === "focused" || state === "readonlyFocused" || isAnchorInRange)) return;
10927
11075
  const isMod = e.ctrlKey || e.metaKey;
@@ -10952,7 +11100,7 @@ const CellWrapper = observer(({ cell, children, onDoubleClick, onStartEdit, onTy
10952
11100
  onTypeChar,
10953
11101
  onDelete
10954
11102
  ]);
10955
- const afterStyle = selectionEdges ? buildSelectionBorderStyle(selectionEdges) : void 0;
11103
+ const selectionShadow = selectionEdges ? buildSelectionBoxShadow(selectionEdges) : null;
10956
11104
  const needsFocus = state === "focused" || state === "editing" || state === "readonlyFocused" || isAnchorInRange;
10957
11105
  const handleBlur = useCallback((e) => {
10958
11106
  if (!cell.isFocused || cell.isEditing) return;
@@ -10980,8 +11128,7 @@ const CellWrapper = observer(({ cell, children, onDoubleClick, onStartEdit, onTy
10980
11128
  border: "2px solid",
10981
11129
  borderColor: "blue.400",
10982
11130
  borderRadius: "1px",
10983
- pointerEvents: "none",
10984
- zIndex: 3
11131
+ pointerEvents: "none"
10985
11132
  };
10986
11133
  extraStyles._focus = FOCUS_RING_RESET;
10987
11134
  extraStyles._focusVisible = FOCUS_RING_RESET;
@@ -10990,12 +11137,12 @@ const CellWrapper = observer(({ cell, children, onDoubleClick, onStartEdit, onTy
10990
11137
  onOpenChange: handleMenuOpenChange,
10991
11138
  children: [/* @__PURE__ */ jsx(Menu.ContextTrigger, {
10992
11139
  asChild: true,
10993
- children: /* @__PURE__ */ jsxs(Box, {
11140
+ children: /* @__PURE__ */ jsx(Box, {
10994
11141
  ref: cellRef,
10995
11142
  height: "40px",
10996
11143
  px: "8px",
10997
11144
  position: "relative",
10998
- overflow: selectionEdges ? "visible" : "hidden",
11145
+ overflow: "hidden",
10999
11146
  onClick: handleClick,
11000
11147
  onMouseDown: handleMouseDown,
11001
11148
  onMouseEnter: handleMouseEnter,
@@ -11008,8 +11155,8 @@ const CellWrapper = observer(({ cell, children, onDoubleClick, onStartEdit, onTy
11008
11155
  "data-testid": `cell-${cell.rowId}-${cell.field}`,
11009
11156
  ...stateStyles[state],
11010
11157
  ...extraStyles,
11011
- _after: afterStyle,
11012
- children: [/* @__PURE__ */ jsx(Box, {
11158
+ boxShadow: selectionShadow || void 0,
11159
+ children: /* @__PURE__ */ jsx(Box, {
11013
11160
  display: "flex",
11014
11161
  alignItems: "center",
11015
11162
  height: "100%",
@@ -11017,21 +11164,7 @@ const CellWrapper = observer(({ cell, children, onDoubleClick, onStartEdit, onTy
11017
11164
  minWidth: 0,
11018
11165
  overflow: "hidden",
11019
11166
  children
11020
- }), state === "readonlyFocused" && /* @__PURE__ */ jsx(Box, {
11021
- position: "absolute",
11022
- top: "1px",
11023
- right: "4px",
11024
- fontSize: "9px",
11025
- lineHeight: "1",
11026
- color: "gray.500",
11027
- bg: "gray.100",
11028
- px: "3px",
11029
- py: "1px",
11030
- borderRadius: "2px",
11031
- userSelect: "none",
11032
- pointerEvents: "none",
11033
- children: "readonly"
11034
- })]
11167
+ })
11035
11168
  })
11036
11169
  }), /* @__PURE__ */ jsx(CellContextMenu, {
11037
11170
  cell,
@@ -11315,7 +11448,6 @@ const ForeignKeyCell = observer(({ cell, onSearchForeignKey }) => {
11315
11448
  textOverflow: "ellipsis",
11316
11449
  overflow: "hidden",
11317
11450
  fontWeight: "300",
11318
- color: "blue.500",
11319
11451
  flex: 1,
11320
11452
  minWidth: 0,
11321
11453
  children: cell.displayValue
@@ -11523,8 +11655,8 @@ const ReadonlyCell = observer(({ cell }) => {
11523
11655
  whiteSpace: "nowrap",
11524
11656
  textOverflow: "ellipsis",
11525
11657
  overflow: "hidden",
11526
- fontWeight: "300",
11527
- color: "gray.400",
11658
+ fontSize: "14px",
11659
+ color: "text/primary",
11528
11660
  children: cell.displayValue
11529
11661
  })
11530
11662
  });
@@ -11698,7 +11830,7 @@ const ResizeHandle = observer(({ field, columnsModel }) => {
11698
11830
  onMouseDown: useCallback((e) => {
11699
11831
  e.preventDefault();
11700
11832
  e.stopPropagation();
11701
- const currentWidth = columnsModel.getColumnWidth(field) ?? 150;
11833
+ const currentWidth = columnsModel.resolveColumnWidth(field);
11702
11834
  startXRef.current = e.clientX;
11703
11835
  startWidthRef.current = currentWidth;
11704
11836
  setIsResizing(true);
@@ -12057,7 +12189,8 @@ const ColumnHeaderMenu = observer(({ column, columnsModel, sortModel, filterMode
12057
12189
 
12058
12190
  //#endregion
12059
12191
  //#region src/table-editor/Table/ui/Header/ColumnHeader.tsx
12060
- function buildHeaderShadowCss(position, showShadow) {
12192
+ function buildHeaderShadowCss(position) {
12193
+ const cssVar = position.side === "left" ? "var(--shadow-left-opacity, 0)" : "var(--shadow-right-opacity, 0)";
12061
12194
  return { "&::after": {
12062
12195
  content: "\"\"",
12063
12196
  position: "absolute",
@@ -12066,7 +12199,7 @@ function buildHeaderShadowCss(position, showShadow) {
12066
12199
  width: "8px",
12067
12200
  pointerEvents: "none",
12068
12201
  transition: "opacity 0.15s",
12069
- opacity: showShadow ? 1 : 0,
12202
+ opacity: cssVar,
12070
12203
  ...position.side === "left" ? {
12071
12204
  right: "-8px",
12072
12205
  boxShadow: "inset 8px 0 12px -8px rgba(0,0,0,0.1)"
@@ -12076,22 +12209,19 @@ function buildHeaderShadowCss(position, showShadow) {
12076
12209
  }
12077
12210
  } };
12078
12211
  }
12079
- const BOTTOM_BORDER_SHADOW$2 = "inset 0 -1px 0 0 var(--chakra-colors-gray-100)";
12080
12212
  function getHeaderBoxShadow(stickyPosition) {
12081
- if (!stickyPosition) return BOTTOM_BORDER_SHADOW$2;
12082
- return `${BOTTOM_BORDER_SHADOW$2}, ${stickyPosition.side === "left" ? "inset -1px 0 0 0 var(--chakra-colors-gray-100)" : "inset 1px 0 0 0 var(--chakra-colors-gray-100)"}`;
12213
+ if (!stickyPosition) return BOTTOM_BORDER_SHADOW;
12214
+ return `${BOTTOM_BORDER_SHADOW}, ${stickyPosition.side === "left" ? `inset -1px 0 0 0 ${CELL_BORDER_COLOR}` : `inset 1px 0 0 0 ${CELL_BORDER_COLOR}`}`;
12083
12215
  }
12084
- const ColumnHeader = observer(({ column, columnsModel, sortModel, filterModel, onCopyPath, stickyPosition, showLeftShadow, showRightShadow }) => {
12216
+ const ColumnHeader = observer(({ column, columnsModel, sortModel, filterModel, onCopyPath, stickyPosition }) => {
12085
12217
  const [isMenuOpen, setIsMenuOpen] = useState(false);
12086
- const width = columnsModel.getColumnWidth(column.field);
12087
- const w = width ? `${width}px` : "150px";
12218
+ const w = columnsModel.columnWidthCssVar(column.field);
12088
12219
  const isSticky = Boolean(stickyPosition);
12089
- const showShadow = stickyPosition?.isBoundary ? stickyPosition.side === "left" && Boolean(showLeftShadow) || stickyPosition.side === "right" && Boolean(showRightShadow) : false;
12090
12220
  return /* @__PURE__ */ jsxs(Box, {
12091
12221
  as: "th",
12092
12222
  position: isSticky ? "sticky" : "relative",
12093
- left: stickyPosition?.side === "left" ? `${stickyPosition.offset}px` : void 0,
12094
- right: stickyPosition?.side === "right" ? `${stickyPosition.offset}px` : void 0,
12223
+ left: stickyPosition?.side === "left" ? stickyPosition.offsetCss : void 0,
12224
+ right: stickyPosition?.side === "right" ? stickyPosition.offsetCss : void 0,
12095
12225
  zIndex: isSticky ? 2 : void 0,
12096
12226
  width: w,
12097
12227
  minWidth: w,
@@ -12102,7 +12232,7 @@ const ColumnHeader = observer(({ column, columnsModel, sortModel, filterModel, o
12102
12232
  textAlign: "left",
12103
12233
  fontWeight: "normal",
12104
12234
  p: 0,
12105
- css: stickyPosition?.isBoundary ? buildHeaderShadowCss(stickyPosition, showShadow) : void 0,
12235
+ css: stickyPosition?.isBoundary ? buildHeaderShadowCss(stickyPosition) : void 0,
12106
12236
  children: [/* @__PURE__ */ jsxs(Menu.Root, {
12107
12237
  positioning: { placement: "bottom-end" },
12108
12238
  lazyMount: true,
@@ -12198,6 +12328,7 @@ const AddColumnButton = observer(({ columnsModel }) => {
12198
12328
  bg: "gray.100",
12199
12329
  color: "gray.600"
12200
12330
  },
12331
+ focusRing: "none",
12201
12332
  "data-testid": "add-column-button",
12202
12333
  children: /* @__PURE__ */ jsx(PiPlus, {})
12203
12334
  })
@@ -12243,8 +12374,7 @@ const AddColumnButton = observer(({ columnsModel }) => {
12243
12374
  //#region src/table-editor/Table/ui/HeaderRow.tsx
12244
12375
  const SELECTION_COLUMN_WIDTH$1 = 40;
12245
12376
  const ADD_COLUMN_BUTTON_WIDTH$1 = 40;
12246
- const BOTTOM_BORDER_SHADOW$1 = "inset 0 -1px 0 0 var(--chakra-colors-gray-100)";
12247
- const HeaderRow = observer(({ columnsModel, sortModel, filterModel, onCopyPath, showSelection, scrollShadow }) => {
12377
+ const HeaderRow = observer(({ columnsModel, sortModel, filterModel, onCopyPath, showSelection }) => {
12248
12378
  const selectionWidth = showSelection ? SELECTION_COLUMN_WIDTH$1 : 0;
12249
12379
  const addColumnStickyRight = columnsModel.hasHiddenColumns;
12250
12380
  return /* @__PURE__ */ jsxs(Box, {
@@ -12261,7 +12391,7 @@ const HeaderRow = observer(({ columnsModel, sortModel, filterModel, onCopyPath,
12261
12391
  position: "sticky",
12262
12392
  left: 0,
12263
12393
  zIndex: 2,
12264
- boxShadow: BOTTOM_BORDER_SHADOW$1
12394
+ boxShadow: BOTTOM_BORDER_SHADOW
12265
12395
  }),
12266
12396
  columnsModel.visibleColumns.map((col) => {
12267
12397
  return /* @__PURE__ */ jsx(ColumnHeader, {
@@ -12270,42 +12400,42 @@ const HeaderRow = observer(({ columnsModel, sortModel, filterModel, onCopyPath,
12270
12400
  sortModel,
12271
12401
  filterModel,
12272
12402
  onCopyPath,
12273
- stickyPosition: getStickyPosition(col.field, columnsModel, selectionWidth, addColumnStickyRight),
12274
- showLeftShadow: scrollShadow?.showLeftShadow,
12275
- showRightShadow: scrollShadow?.showRightShadow
12403
+ stickyPosition: getStickyPosition(col.field, columnsModel, selectionWidth, addColumnStickyRight)
12276
12404
  }, col.field);
12277
12405
  }),
12278
- /* @__PURE__ */ jsx(Box, {
12406
+ addColumnStickyRight ? /* @__PURE__ */ jsx(Box, {
12279
12407
  as: "th",
12280
12408
  width: "100%",
12409
+ minWidth: `${ADD_COLUMN_BUTTON_WIDTH$1}px`,
12281
12410
  bg: "white",
12282
12411
  p: 0,
12283
- boxShadow: BOTTOM_BORDER_SHADOW$1
12284
- }),
12285
- /* @__PURE__ */ jsx(Box, {
12412
+ position: "sticky",
12413
+ right: 0,
12414
+ zIndex: 2,
12415
+ boxShadow: BOTTOM_BORDER_SHADOW,
12416
+ css: columnsModel.pinnedRightCount === 0 ? buildAddColumnShadowCss() : void 0,
12417
+ children: /* @__PURE__ */ jsx(AddColumnButton, { columnsModel })
12418
+ }) : /* @__PURE__ */ jsx(Box, {
12286
12419
  as: "th",
12420
+ width: "100%",
12287
12421
  bg: "white",
12288
12422
  p: 0,
12289
- position: addColumnStickyRight ? "sticky" : void 0,
12290
- right: addColumnStickyRight ? 0 : void 0,
12291
- zIndex: addColumnStickyRight ? 2 : void 0,
12292
- boxShadow: BOTTOM_BORDER_SHADOW$1,
12293
- children: /* @__PURE__ */ jsx(AddColumnButton, { columnsModel })
12423
+ boxShadow: BOTTOM_BORDER_SHADOW
12294
12424
  })
12295
12425
  ]
12296
12426
  });
12297
12427
  });
12298
12428
  function getStickyPosition(field, columnsModel, selectionWidth, addColumnStickyRight) {
12299
- const leftOffset = columnsModel.getColumnStickyLeft(field, selectionWidth);
12300
- if (leftOffset !== void 0) return {
12429
+ const leftCss = columnsModel.getColumnStickyLeftCss(field, selectionWidth);
12430
+ if (leftCss !== void 0) return {
12301
12431
  side: "left",
12302
- offset: leftOffset,
12432
+ offsetCss: leftCss,
12303
12433
  isBoundary: columnsModel.isStickyLeftBoundary(field)
12304
12434
  };
12305
- const rightBase = columnsModel.getColumnStickyRight(field);
12306
- if (rightBase !== void 0) return {
12435
+ const rightCss = columnsModel.getColumnStickyRightCss(field);
12436
+ if (rightCss !== void 0) return {
12307
12437
  side: "right",
12308
- offset: rightBase + (addColumnStickyRight ? ADD_COLUMN_BUTTON_WIDTH$1 : 0),
12438
+ offsetCss: adjustRightOffsetCss(rightCss, addColumnStickyRight ? ADD_COLUMN_BUTTON_WIDTH$1 : 0),
12309
12439
  isBoundary: columnsModel.isStickyRightBoundary(field)
12310
12440
  };
12311
12441
  }
@@ -12440,7 +12570,7 @@ const SelectionCheckboxCell = ({ rowId, isSelected, onToggleSelection }) => {
12440
12570
  left: 0,
12441
12571
  zIndex: 1,
12442
12572
  bg: "white",
12443
- boxShadow: "inset 0 -1px 0 0 var(--chakra-colors-gray-100), inset -1px 0 0 0 var(--chakra-colors-gray-100)",
12573
+ boxShadow: `inset 0 -1px 0 0 ${CELL_BORDER_COLOR}, inset -1px 0 0 0 ${CELL_BORDER_COLOR}`,
12444
12574
  children: /* @__PURE__ */ jsx(Flex, {
12445
12575
  alignItems: "center",
12446
12576
  justifyContent: "center",
@@ -12460,7 +12590,8 @@ const SelectionCheckboxCell = ({ rowId, isSelected, onToggleSelection }) => {
12460
12590
  //#region src/table-editor/Table/ui/DataRow.tsx
12461
12591
  const SELECTION_COLUMN_WIDTH = 40;
12462
12592
  const ADD_COLUMN_BUTTON_WIDTH = 40;
12463
- function buildShadowCss(side, showShadow) {
12593
+ function buildShadowCss(side) {
12594
+ const cssVar = side === "left" ? "var(--shadow-left-opacity, 0)" : "var(--shadow-right-opacity, 0)";
12464
12595
  return { "&::after": {
12465
12596
  content: "\"\"",
12466
12597
  position: "absolute",
@@ -12469,7 +12600,7 @@ function buildShadowCss(side, showShadow) {
12469
12600
  width: "8px",
12470
12601
  pointerEvents: "none",
12471
12602
  transition: "opacity 0.15s",
12472
- opacity: showShadow ? 1 : 0,
12603
+ opacity: cssVar,
12473
12604
  ...side === "left" ? {
12474
12605
  right: "-8px",
12475
12606
  boxShadow: "inset 8px 0 12px -8px rgba(0,0,0,0.1)"
@@ -12479,7 +12610,7 @@ function buildShadowCss(side, showShadow) {
12479
12610
  }
12480
12611
  } };
12481
12612
  }
12482
- function buildCellCss(isBoundary, boundarySide, showShadow, hasRowActions, isFirstColumn) {
12613
+ function buildCellCss(isBoundary, boundarySide, hasRowActions, isFirstColumn) {
12483
12614
  const needsHover = isFirstColumn && hasRowActions;
12484
12615
  const hoverCss = needsHover ? {
12485
12616
  "& .row-action-buttons": { opacity: 0 },
@@ -12490,34 +12621,33 @@ function buildCellCss(isBoundary, boundarySide, showShadow, hasRowActions, isFir
12490
12621
  } : {};
12491
12622
  if (isBoundary) return {
12492
12623
  ...hoverCss,
12493
- ...buildShadowCss(boundarySide, showShadow)
12624
+ ...buildShadowCss(boundarySide)
12494
12625
  };
12495
12626
  if (needsHover) return hoverCss;
12496
12627
  }
12497
- function computeStickyProps(col, columnsModel, selectionWidth, addColOffset, showLeftShadow, showRightShadow) {
12498
- const leftOffset = columnsModel.getColumnStickyLeft(col.field, selectionWidth);
12499
- const rightBase = columnsModel.getColumnStickyRight(col.field);
12500
- const isStickyLeft = leftOffset !== void 0;
12501
- const isStickyRight = rightBase !== void 0;
12628
+ function computeStickyProps(col, columnsModel, selectionWidth, addColOffset) {
12629
+ const leftCss = columnsModel.getColumnStickyLeftCss(col.field, selectionWidth);
12630
+ const rightCss = columnsModel.getColumnStickyRightCss(col.field);
12631
+ const isStickyLeft = leftCss !== void 0;
12632
+ const isStickyRight = rightCss !== void 0;
12502
12633
  const isSticky = isStickyLeft || isStickyRight;
12503
12634
  const isLeftBoundary = columnsModel.isStickyLeftBoundary(col.field);
12504
12635
  const isRightBoundary = columnsModel.isStickyRightBoundary(col.field);
12636
+ const finalRightCss = isStickyRight && rightCss !== void 0 ? adjustRightOffsetCss(rightCss, addColOffset) : rightCss;
12505
12637
  return {
12506
12638
  isSticky,
12507
12639
  isBoundary: isLeftBoundary || isRightBoundary,
12508
12640
  boundarySide: isStickyLeft ? "left" : "right",
12509
- showShadow: isLeftBoundary && Boolean(showLeftShadow) || isRightBoundary && Boolean(showRightShadow),
12510
- leftOffset: isStickyLeft ? leftOffset : void 0,
12511
- rightOffset: isStickyRight ? rightBase + addColOffset : void 0,
12512
- colWidth: isSticky ? `${columnsModel.resolveColumnWidth(col.field)}px` : void 0
12641
+ leftCss: isStickyLeft ? leftCss : void 0,
12642
+ rightCss: isStickyRight ? finalRightCss : void 0,
12643
+ colWidth: isSticky ? columnsModel.columnWidthCssVar(col.field) : void 0
12513
12644
  };
12514
12645
  }
12515
- const BOTTOM_BORDER_SHADOW = "inset 0 -1px 0 0 var(--chakra-colors-gray-100)";
12516
12646
  function getCellBoxShadow(isSticky, side) {
12517
12647
  if (!isSticky) return BOTTOM_BORDER_SHADOW;
12518
- return `${BOTTOM_BORDER_SHADOW}, ${side === "left" ? "inset -1px 0 0 0 var(--chakra-colors-gray-100)" : "inset 1px 0 0 0 var(--chakra-colors-gray-100)"}`;
12648
+ return `${BOTTOM_BORDER_SHADOW}, ${side === "left" ? `inset -1px 0 0 0 ${CELL_BORDER_COLOR}` : `inset 1px 0 0 0 ${CELL_BORDER_COLOR}`}`;
12519
12649
  }
12520
- const DataRow = observer(({ row, columnsModel, showSelection, scrollShadow, onSearchForeignKey, onUploadFile, onOpenFile, onOpenRow, onSelectRow, onDuplicateRow, onDeleteRow }) => {
12650
+ const DataRow = observer(({ row, columnsModel, showSelection, onSearchForeignKey, onUploadFile, onOpenFile, onOpenRow, onSelectRow, onDuplicateRow, onDeleteRow }) => {
12521
12651
  const hasRowActions = Boolean(onOpenRow || onSelectRow || onDuplicateRow || onDeleteRow);
12522
12652
  const selectionWidth = showSelection ? SELECTION_COLUMN_WIDTH : 0;
12523
12653
  const addColumnStickyRight = columnsModel.hasHiddenColumns;
@@ -12532,7 +12662,7 @@ const DataRow = observer(({ row, columnsModel, showSelection, scrollShadow, onSe
12532
12662
  const cellVM = row.getCellVM(col);
12533
12663
  const isFirstColumn = index === 0;
12534
12664
  const showOverlay = isFirstColumn && hasRowActions && !cellVM.isEditing;
12535
- const sticky = computeStickyProps(col, columnsModel, selectionWidth, addColOffset, scrollShadow?.showLeftShadow, scrollShadow?.showRightShadow);
12665
+ const sticky = computeStickyProps(col, columnsModel, selectionWidth, addColOffset);
12536
12666
  return /* @__PURE__ */ jsxs(Box, {
12537
12667
  as: "td",
12538
12668
  width: sticky.colWidth,
@@ -12540,15 +12670,15 @@ const DataRow = observer(({ row, columnsModel, showSelection, scrollShadow, onSe
12540
12670
  maxWidth: sticky.isSticky ? sticky.colWidth : "0",
12541
12671
  overflow: sticky.isBoundary ? "visible" : "hidden",
12542
12672
  borderRight: sticky.isSticky ? void 0 : "1px solid",
12543
- borderColor: sticky.isSticky ? void 0 : "gray.100",
12673
+ borderColor: sticky.isSticky ? void 0 : CELL_BORDER_COLOR,
12544
12674
  p: 0,
12545
12675
  position: sticky.isSticky ? "sticky" : "relative",
12546
- left: sticky.leftOffset !== void 0 ? `${sticky.leftOffset}px` : void 0,
12547
- right: sticky.rightOffset !== void 0 ? `${sticky.rightOffset}px` : void 0,
12676
+ left: sticky.leftCss,
12677
+ right: sticky.rightCss,
12548
12678
  zIndex: sticky.isSticky ? 1 : void 0,
12549
12679
  bg: sticky.isSticky ? "white" : void 0,
12550
12680
  boxShadow: getCellBoxShadow(sticky.isSticky, sticky.boundarySide),
12551
- css: buildCellCss(sticky.isBoundary, sticky.boundarySide, sticky.showShadow, hasRowActions, isFirstColumn),
12681
+ css: buildCellCss(sticky.isBoundary, sticky.boundarySide, hasRowActions, isFirstColumn),
12552
12682
  children: [sticky.isBoundary ? /* @__PURE__ */ jsx(Box, {
12553
12683
  overflow: "hidden",
12554
12684
  children: /* @__PURE__ */ jsx(CellRenderer, {
@@ -12571,23 +12701,22 @@ const DataRow = observer(({ row, columnsModel, showSelection, scrollShadow, onSe
12571
12701
  })]
12572
12702
  }, col.field);
12573
12703
  }),
12574
- /* @__PURE__ */ jsx(Box, {
12704
+ addColumnStickyRight ? /* @__PURE__ */ jsx(Box, {
12575
12705
  as: "td",
12576
12706
  width: "100%",
12577
- p: 0,
12578
- boxShadow: BOTTOM_BORDER_SHADOW
12579
- }),
12580
- addColumnStickyRight && /* @__PURE__ */ jsx(Box, {
12581
- as: "td",
12582
- width: `${ADD_COLUMN_BUTTON_WIDTH}px`,
12583
12707
  minWidth: `${ADD_COLUMN_BUTTON_WIDTH}px`,
12584
- maxWidth: `${ADD_COLUMN_BUTTON_WIDTH}px`,
12585
12708
  p: 0,
12586
12709
  position: "sticky",
12587
12710
  right: 0,
12588
12711
  zIndex: 1,
12589
12712
  bg: "white",
12590
- boxShadow: `${BOTTOM_BORDER_SHADOW}, inset 1px 0 0 0 var(--chakra-colors-gray-100)`
12713
+ boxShadow: BOTTOM_BORDER_SHADOW,
12714
+ css: columnsModel.pinnedRightCount === 0 ? buildAddColumnShadowCss() : void 0
12715
+ }) : /* @__PURE__ */ jsx(Box, {
12716
+ as: "td",
12717
+ width: "100%",
12718
+ p: 0,
12719
+ boxShadow: BOTTOM_BORDER_SHADOW
12591
12720
  })
12592
12721
  ] });
12593
12722
  });
@@ -12713,19 +12842,61 @@ const TableRowComponent = ({ "data-index": index, context, style, children, ...p
12713
12842
 
12714
12843
  //#endregion
12715
12844
  //#region src/table-editor/Table/ui/hooks/useScrollShadow.ts
12845
+ const INITIAL_SHADOW = {
12846
+ left: false,
12847
+ right: false
12848
+ };
12716
12849
  var ScrollShadowModel = class {
12717
- showLeftShadow = false;
12718
- showRightShadow = false;
12719
- constructor() {
12720
- makeAutoObservable(this);
12850
+ _left = false;
12851
+ _right = false;
12852
+ _paused = false;
12853
+ _dirty = false;
12854
+ _onChange = null;
12855
+ get showLeftShadow() {
12856
+ return this._left;
12857
+ }
12858
+ get showRightShadow() {
12859
+ return this._right;
12860
+ }
12861
+ setOnChange(cb) {
12862
+ this._onChange = cb;
12863
+ }
12864
+ pause() {
12865
+ this._paused = true;
12866
+ this._dirty = false;
12867
+ }
12868
+ resume() {
12869
+ this._paused = false;
12870
+ if (this._dirty) {
12871
+ this._dirty = false;
12872
+ this._notify();
12873
+ }
12721
12874
  }
12722
12875
  update(left, right) {
12723
- this.showLeftShadow = left;
12724
- this.showRightShadow = right;
12876
+ if (this._left === left && this._right === right) return;
12877
+ this._left = left;
12878
+ this._right = right;
12879
+ if (this._paused) {
12880
+ this._dirty = true;
12881
+ return;
12882
+ }
12883
+ this._notify();
12725
12884
  }
12726
12885
  reset() {
12727
- this.showLeftShadow = false;
12728
- this.showRightShadow = false;
12886
+ if (!this._left && !this._right) return;
12887
+ this._left = false;
12888
+ this._right = false;
12889
+ if (this._paused) {
12890
+ this._dirty = true;
12891
+ return;
12892
+ }
12893
+ this._notify();
12894
+ }
12895
+ _notify() {
12896
+ if (this._onChange) this._onChange({
12897
+ left: this._left,
12898
+ right: this._right
12899
+ });
12729
12900
  }
12730
12901
  };
12731
12902
  function getScrollElement(target) {
@@ -12736,8 +12907,20 @@ function useScrollShadow() {
12736
12907
  const modelRef = useRef(null);
12737
12908
  if (!modelRef.current) modelRef.current = new ScrollShadowModel();
12738
12909
  const model = modelRef.current;
12910
+ const [shadow, setShadow] = useState(INITIAL_SHADOW);
12911
+ model.setOnChange(setShadow);
12912
+ useEffect(() => {
12913
+ return () => {
12914
+ model.setOnChange(null);
12915
+ };
12916
+ }, [model]);
12917
+ const shadowCssVars = {
12918
+ "--shadow-left-opacity": shadow.left ? "1" : "0",
12919
+ "--shadow-right-opacity": shadow.right ? "1" : "0"
12920
+ };
12739
12921
  const targetRef = useRef(null);
12740
12922
  const rafRef = useRef(0);
12923
+ const roRef = useRef(null);
12741
12924
  const update = useCallback(() => {
12742
12925
  const target = targetRef.current;
12743
12926
  if (!target) return;
@@ -12745,9 +12928,7 @@ function useScrollShadow() {
12745
12928
  if (!el) return;
12746
12929
  const scrollLeft = el.scrollLeft;
12747
12930
  const maxScroll = el.scrollWidth - el.clientWidth;
12748
- runInAction(() => {
12749
- model.update(scrollLeft > 0, maxScroll > 1 && scrollLeft < maxScroll - 1);
12750
- });
12931
+ model.update(scrollLeft > 0, maxScroll > 1 && scrollLeft < maxScroll - 1);
12751
12932
  }, [model]);
12752
12933
  const handleScroll = useCallback(() => {
12753
12934
  if (rafRef.current) cancelAnimationFrame(rafRef.current);
@@ -12756,15 +12937,24 @@ function useScrollShadow() {
12756
12937
  const setScrollerRef = useCallback((el) => {
12757
12938
  const prev = targetRef.current;
12758
12939
  if (prev) prev.removeEventListener("scroll", handleScroll);
12940
+ if (roRef.current) {
12941
+ roRef.current.disconnect();
12942
+ roRef.current = null;
12943
+ }
12759
12944
  if (el) {
12760
12945
  targetRef.current = el;
12761
12946
  el.addEventListener("scroll", handleScroll, { passive: true });
12762
12947
  rafRef.current = requestAnimationFrame(update);
12948
+ const scrollEl = getScrollElement(el);
12949
+ if (scrollEl) {
12950
+ const ro = new ResizeObserver(handleScroll);
12951
+ const table = scrollEl.querySelector("table");
12952
+ if (table) ro.observe(table);
12953
+ roRef.current = ro;
12954
+ }
12763
12955
  } else {
12764
12956
  targetRef.current = null;
12765
- runInAction(() => {
12766
- model.reset();
12767
- });
12957
+ model.reset();
12768
12958
  }
12769
12959
  }, [
12770
12960
  handleScroll,
@@ -12775,11 +12965,13 @@ function useScrollShadow() {
12775
12965
  return () => {
12776
12966
  const prev = targetRef.current;
12777
12967
  if (prev) prev.removeEventListener("scroll", handleScroll);
12968
+ if (roRef.current) roRef.current.disconnect();
12778
12969
  if (rafRef.current) cancelAnimationFrame(rafRef.current);
12779
12970
  };
12780
12971
  }, [handleScroll]);
12781
12972
  return {
12782
- model,
12973
+ shadowCssVars,
12974
+ shadowModel: model,
12783
12975
  setScrollerRef
12784
12976
  };
12785
12977
  }
@@ -12794,7 +12986,20 @@ const TableWidget = observer(({ rows, columnsModel, cellFSM, selection, sortMode
12794
12986
  const showSelection = selection.isSelectionMode;
12795
12987
  const allRowIds = rows.map((r) => r.rowId);
12796
12988
  const [deleteConfirm, setDeleteConfirm] = useState(null);
12797
- const { model: scrollShadow, setScrollerRef } = useScrollShadow();
12989
+ const { shadowCssVars, shadowModel, setScrollerRef } = useScrollShadow();
12990
+ const isResizing = columnsModel.isResizing;
12991
+ useEffect(() => {
12992
+ if (isResizing) shadowModel.pause();
12993
+ else shadowModel.resume();
12994
+ }, [isResizing, shadowModel]);
12995
+ const wrapperRefCallback = useCallback((el) => {
12996
+ columnsModel.setWrapperElement(el);
12997
+ if (useWindowScrollProp) setScrollerRef(el);
12998
+ }, [
12999
+ columnsModel,
13000
+ useWindowScrollProp,
13001
+ setScrollerRef
13002
+ ]);
12798
13003
  const handleSelectRow = useCallback((rowId) => {
12799
13004
  selection.enterSelectionMode(rowId);
12800
13005
  }, [selection]);
@@ -12892,7 +13097,6 @@ const TableWidget = observer(({ rows, columnsModel, cellFSM, selection, sortMode
12892
13097
  row,
12893
13098
  columnsModel,
12894
13099
  showSelection,
12895
- scrollShadow,
12896
13100
  onSearchForeignKey,
12897
13101
  onUploadFile,
12898
13102
  onOpenFile,
@@ -12903,7 +13107,6 @@ const TableWidget = observer(({ rows, columnsModel, cellFSM, selection, sortMode
12903
13107
  }), [
12904
13108
  columnsModel,
12905
13109
  showSelection,
12906
- scrollShadow,
12907
13110
  onSearchForeignKey,
12908
13111
  onUploadFile,
12909
13112
  onOpenFile,
@@ -12920,18 +13123,16 @@ const TableWidget = observer(({ rows, columnsModel, cellFSM, selection, sortMode
12920
13123
  sortModel,
12921
13124
  filterModel,
12922
13125
  onCopyPath,
12923
- showSelection,
12924
- scrollShadow
13126
+ showSelection
12925
13127
  }), [
12926
13128
  columnsModel,
12927
13129
  sortModel,
12928
13130
  filterModel,
12929
13131
  onCopyPath,
12930
- showSelection,
12931
- scrollShadow
13132
+ showSelection
12932
13133
  ]);
12933
13134
  const virtuosoContext = useMemo(() => ({ rows }), [rows]);
12934
- const totalColumns = columnsModel.visibleColumns.length + (showSelection ? 4 : 3);
13135
+ const totalColumns = columnsModel.visibleColumns.length + (showSelection ? 2 : 1);
12935
13136
  const LoadingMoreFooter = useCallback(() => isLoadingMore ? /* @__PURE__ */ jsx("tfoot", { children: /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
12936
13137
  colSpan: totalColumns,
12937
13138
  style: {
@@ -12958,10 +13159,17 @@ const TableWidget = observer(({ rows, columnsModel, cellFSM, selection, sortMode
12958
13159
  return /* @__PURE__ */ jsxs(CellContextActionsContext.Provider, {
12959
13160
  value: cellFSM ? contextActions : null,
12960
13161
  children: [/* @__PURE__ */ jsxs(Box, {
13162
+ ref: wrapperRefCallback,
12961
13163
  position: "relative",
12962
13164
  height: useWindowScrollProp ? void 0 : "100%",
13165
+ overflowX: "auto",
13166
+ overflowY: useWindowScrollProp ? "clip" : void 0,
12963
13167
  "data-testid": "table-widget",
12964
13168
  onKeyDown: handleKeyDown,
13169
+ style: {
13170
+ ...columnsModel.columnWidthCssVars,
13171
+ ...shadowCssVars
13172
+ },
12965
13173
  children: [rows.length === 0 ? /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx("table", {
12966
13174
  style: {
12967
13175
  width: "max-content",
@@ -12996,7 +13204,7 @@ const TableWidget = observer(({ rows, columnsModel, cellFSM, selection, sortMode
12996
13204
  fixedHeaderContent,
12997
13205
  itemContent,
12998
13206
  components: tableComponents,
12999
- scrollerRef: setScrollerRef
13207
+ scrollerRef: useWindowScrollProp ? void 0 : setScrollerRef
13000
13208
  }), /* @__PURE__ */ jsx(SelectionToolbar, {
13001
13209
  selection,
13002
13210
  allRowIds,
@@ -13289,6 +13497,7 @@ var TableEditorCore = class {
13289
13497
  this.sorts.setOnApply((_sorts) => this._handleSortApply());
13290
13498
  this.viewBadge.setOnSave(() => this._handleViewSave());
13291
13499
  this.viewBadge.setOnRevert(() => this._handleViewRevert());
13500
+ this.cellFSM.setOnReadonlyEditAttempt(this._callbacks.onReadonlyEditAttempt ?? null);
13292
13501
  makeAutoObservable(this, {}, { autoBind: true });
13293
13502
  queueMicrotask(() => void this._bootstrap());
13294
13503
  }
@@ -13316,17 +13525,14 @@ var TableEditorCore = class {
13316
13525
  getViewState() {
13317
13526
  return {
13318
13527
  columns: this.columns.serializeToViewColumns(),
13319
- filters: this.filters.hasActiveFilters ? JSON.stringify(this.filters.serializeRootGroup()) : null,
13528
+ filters: null,
13320
13529
  sorts: this.sorts.serializeToViewSorts(),
13321
- search: this.search.debouncedQuery
13530
+ search: ""
13322
13531
  };
13323
13532
  }
13324
13533
  applyViewState(state) {
13325
13534
  this.columns.applyViewColumns(state.columns);
13326
13535
  this.sorts.applyViewSorts(state.sorts);
13327
- if (state.filters) this.filters.applySnapshot(state.filters);
13328
- else this.filters.clearAll();
13329
- this.search.setQuery(state.search);
13330
13536
  }
13331
13537
  async loadMore() {
13332
13538
  if (!this._hasNextPage || this._isLoadingMore) return;
@@ -13469,12 +13675,9 @@ var TableEditorCore = class {
13469
13675
  this.cellFSM.updateNavigationContext(this.columns.visibleColumns.map((c) => c.field), this.cellFSM.rowIds);
13470
13676
  this._checkViewChanges();
13471
13677
  }
13472
- _handleFilterChange() {
13473
- this._checkViewChanges();
13474
- }
13678
+ _handleFilterChange() {}
13475
13679
  _handleFilterApply() {
13476
13680
  this._reloadRows();
13477
- this._checkViewChanges();
13478
13681
  }
13479
13682
  _handleSortChange() {
13480
13683
  this._checkViewChanges();
@@ -13485,7 +13688,6 @@ var TableEditorCore = class {
13485
13688
  }
13486
13689
  _handleSearch(_query) {
13487
13690
  this._reloadRows();
13488
- this._checkViewChanges();
13489
13691
  }
13490
13692
  async _handleViewSave() {
13491
13693
  try {
@@ -13732,14 +13934,21 @@ const TableEditor = observer(({ viewModel, useWindowScroll }) => {
13732
13934
  return /* @__PURE__ */ jsxs(Box, {
13733
13935
  display: "flex",
13734
13936
  flexDirection: "column",
13735
- height: "100%",
13937
+ height: useWindowScroll ? void 0 : "100%",
13938
+ flex: useWindowScroll ? 1 : void 0,
13736
13939
  children: [
13737
13940
  /* @__PURE__ */ jsxs(Flex, {
13738
13941
  px: 3,
13739
- pt: 2,
13740
- mb: "48px",
13942
+ pt: "32px",
13943
+ pb: "48px",
13741
13944
  alignItems: "center",
13742
13945
  justifyContent: "space-between",
13946
+ ...useWindowScroll && {
13947
+ position: "sticky",
13948
+ top: 0,
13949
+ zIndex: 3,
13950
+ bg: "white"
13951
+ },
13743
13952
  children: [breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Breadcrumbs, {
13744
13953
  segments: breadcrumbs,
13745
13954
  highlightLast: false,
@@ -13793,6 +14002,12 @@ const TableEditor = observer(({ viewModel, useWindowScroll }) => {
13793
14002
  px: 3,
13794
14003
  py: 2,
13795
14004
  justifyContent: "space-between",
14005
+ ...useWindowScroll && {
14006
+ position: "sticky",
14007
+ bottom: 0,
14008
+ bg: "white",
14009
+ zIndex: 3
14010
+ },
13796
14011
  children: [/* @__PURE__ */ jsx(RowCountWidget, { model: viewModel.rowCount }), /* @__PURE__ */ jsx(ViewSettingsBadge, { model: viewModel.viewBadge })]
13797
14012
  })
13798
14013
  ]