@ryuzaki13/react-foundation-lib 2.31.3 → 2.32.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.
@@ -1,7 +1,15 @@
1
+ /** Числа sizing-state используют единицу, явно выбранную потребителем; по умолчанию это px. */
1
2
  export type TableColumnSizingState = Record<string, number>;
3
+ /** Единица сохранённого размера не зависит от экранных координат pointer/keyboard events. */
4
+ export type TableColumnSizingUnit = "px" | "em";
2
5
  export declare const DEFAULT_TABLE_COLUMN_MIN_WIDTH = 60;
3
- export declare function normalizeTableColumnWidth(px: number, minWidth?: number): number;
4
- export declare function normalizeTableColumnSizing(state: Readonly<Record<string, number>> | undefined, minWidth?: number): TableColumnSizingState;
5
- export declare function patchTableColumnWidth(state: Readonly<Record<string, number>>, columnId: string, width: number, minWidth?: number): TableColumnSizingState;
6
+ export declare const DEFAULT_TABLE_COLUMN_MIN_WIDTH_EM = 4;
7
+ /**
8
+ * Нормализует размер в выбранной единице. Для px сохраняется целочисленный контракт,
9
+ * для em остаются четыре знака, чтобы resize не округлялся до целого размера шрифта.
10
+ */
11
+ export declare function normalizeTableColumnWidth(width: number, minWidth?: number, unit?: TableColumnSizingUnit): number;
12
+ export declare function normalizeTableColumnSizing(state: Readonly<Record<string, number>> | undefined, minWidth?: number, unit?: TableColumnSizingUnit): TableColumnSizingState;
13
+ export declare function patchTableColumnWidth(state: Readonly<Record<string, number>>, columnId: string, width: number, minWidth?: number, unit?: TableColumnSizingUnit): TableColumnSizingState;
6
14
  export declare function removeTableColumnWidth(state: Readonly<Record<string, number>>, columnId: string): TableColumnSizingState;
7
15
  //# sourceMappingURL=columnSizing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"columnSizing.d.ts","sourceRoot":"","sources":["../../src/table/columnSizing.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE5D,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAuC,GAAG,MAAM,CAK/G;AAED,wBAAgB,0BAA0B,CACzC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,EACnD,QAAQ,GAAE,MAAuC,GAC/C,sBAAsB,CAYxB;AAED,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAuC,GAC/C,sBAAsB,CASxB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAUxH"}
1
+ {"version":3,"file":"columnSizing.d.ts","sourceRoot":"","sources":["../../src/table/columnSizing.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE5D,6FAA6F;AAC7F,MAAM,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD,eAAO,MAAM,8BAA8B,KAAK,CAAC;AACjD,eAAO,MAAM,iCAAiC,IAAI,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,qBAA4B,GAAG,MAAM,CAUtH;AAED,wBAAgB,0BAA0B,CACzC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,EACnD,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,GAAE,qBAA4B,GAChC,sBAAsB,CAYxB;AAED,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,GAAE,qBAA4B,GAChC,sBAAsB,CASxB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAUxH"}
@@ -1,6 +1,7 @@
1
1
  export * from "./columnLayout";
2
2
  export * from "./columnOrder";
3
3
  export * from "./columnSizing";
4
+ export { resolveTableColumnsWidth } from "./resolveTableColumnsWidth";
4
5
  export * from "./cellSelection";
5
6
  export * from "./odataAdapter";
6
7
  export * from "./selection";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/table/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,SAAS,CAAC;AACxB,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/table/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,SAAS,CAAC;AACxB,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC"}
@@ -6,7 +6,7 @@ import { columnOrderingFeature as l, columnPinningFeature as u, columnResizingFe
6
6
  function v({ ids: n, order: r }) {
7
7
  return t(e(r, n), n);
8
8
  }
9
- function y({ ids: e, getWidth: t }) {
9
+ function ee({ ids: e, getWidth: t }) {
10
10
  return e.map((e) => ({
11
11
  id: e,
12
12
  width: t(e)
@@ -14,7 +14,7 @@ function y({ ids: e, getWidth: t }) {
14
14
  }
15
15
  //#endregion
16
16
  //#region src/table/columnOrder.ts
17
- function ee(e) {
17
+ function y(e) {
18
18
  return Array.from(new Set((e ?? []).filter((e) => e.trim().length > 0)));
19
19
  }
20
20
  function b(e, t, n) {
@@ -41,42 +41,48 @@ function S(e) {
41
41
  }
42
42
  //#endregion
43
43
  //#region src/table/columnSizing.ts
44
- var C = 60;
45
- function w(e, t = 60) {
46
- let n = Number.isFinite(t) && t > 0 ? Math.floor(t) : 60;
47
- return Math.max(n, Number.isFinite(e) ? Math.floor(e) : n);
48
- }
49
- function T(e, t = 60) {
50
- let n = {};
51
- for (let [r, i] of Object.entries(e ?? {})) typeof r != "string" || r.trim().length === 0 || !Number.isFinite(i) || (n[r] = w(i, t));
52
- return n;
53
- }
54
- function E(e, t, n, r = 60) {
55
- return t.trim().length === 0 ? T(e, r) : {
56
- ...T(e, r),
57
- [t]: w(n, r)
44
+ var C = 60, w = 4;
45
+ function T(e, t, n = "px") {
46
+ let r = n === "em" ? 4 : 60, i = n === "em" ? 1e4 : 1, a = typeof t == "number" && Number.isFinite(t) && t > 0 ? Math.floor(t * i) / i : r, o = Number.isFinite(e) ? Math.floor(e * i) / i : a;
47
+ return Math.max(a, o);
48
+ }
49
+ function E(e, t, n = "px") {
50
+ let r = {};
51
+ for (let [i, a] of Object.entries(e ?? {})) typeof i != "string" || i.trim().length === 0 || !Number.isFinite(a) || (r[i] = T(a, t, n));
52
+ return r;
53
+ }
54
+ function te(e, t, n, r, i = "px") {
55
+ return t.trim().length === 0 ? E(e, r, i) : {
56
+ ...E(e, r, i),
57
+ [t]: T(n, r, i)
58
58
  };
59
59
  }
60
- function te(e, t) {
60
+ function ne(e, t) {
61
61
  let n = {};
62
62
  for (let [r, i] of Object.entries(e)) r !== t && (n[r] = i);
63
63
  return n;
64
64
  }
65
65
  //#endregion
66
+ //#region src/table/resolveTableColumnsWidth.ts
67
+ var re = /^(?:\d+(?:\.\d+)?|\.\d+)(?:em|px)$/;
68
+ function D(e) {
69
+ if (!(e.length === 0 || e.some((e) => !re.test(e)))) return e.length === 1 ? e[0] : `calc(${e.join(" + ")})`;
70
+ }
71
+ //#endregion
66
72
  //#region src/table/tableSelectionConstants.ts
67
- var D = "none", ne = "single", O = "multi", k = "direct", A = /* @__PURE__ */ new Set([k, "primary-modifier"]);
68
- function j(e) {
73
+ var O = "none", k = "single", A = "multi", j = "direct", M = /* @__PURE__ */ new Set([j, "primary-modifier"]);
74
+ function N(e) {
69
75
  return `${encodeURIComponent(e.rowId)}::${encodeURIComponent(e.columnId)}`;
70
76
  }
71
- function M(e, t) {
72
- let n = new Set(e.map(j)), r = new Set(t.map(j));
77
+ function P(e, t) {
78
+ let n = new Set(e.map(N)), r = new Set(t.map(N));
73
79
  return n.size === r.size && [...n].every((e) => r.has(e));
74
80
  }
75
- function N(e, t, n, r) {
81
+ function F(e, t, n, r) {
76
82
  if (r === "none" || !e?.length) return [];
77
83
  let i = new Map(t.map((e, t) => [e, t])), a = new Map(n.map((e, t) => [e, t])), o = /* @__PURE__ */ new Set(), s = e.filter((e) => {
78
84
  if (!(i.has(e.rowId) && a.has(e.columnId))) return !1;
79
- let t = j(e);
85
+ let t = N(e);
80
86
  return !o.has(t) && (o.add(t), !0);
81
87
  }).sort((e, t) => {
82
88
  let n = (i.get(e.rowId) ?? 0) - (i.get(t.rowId) ?? 0);
@@ -88,55 +94,55 @@ function N(e, t, n, r) {
88
94
  }
89
95
  return s;
90
96
  }
91
- function P(e, t, n) {
97
+ function I(e, t, n) {
92
98
  if (n === "none") return [];
93
- let r = j(t), i = e.some((e) => j(e) === r);
94
- return n === "single" ? i ? [] : [t] : i ? e.filter((e) => j(e) !== r) : [...e, t];
99
+ let r = N(t), i = e.some((e) => N(e) === r);
100
+ return n === "single" ? i ? [] : [t] : i ? e.filter((e) => N(e) !== r) : [...e, t];
95
101
  }
96
- function F(e, t = k) {
97
- return typeof e == "string" && A.has(e) ? e : t;
102
+ function L(e, t = j) {
103
+ return typeof e == "string" && M.has(e) ? e : t;
98
104
  }
99
- function I(e, t) {
105
+ function R(e, t) {
100
106
  return t === "direct" || (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey;
101
107
  }
102
108
  //#endregion
103
109
  //#region src/table/tableColumnConstants.ts
104
- var L = "left", R = "right";
110
+ var z = "left", B = "right";
105
111
  //#endregion
106
112
  //#region src/table/odataAdapter.ts
107
- function z(e) {
113
+ function V(e) {
108
114
  let { role: t, type: n } = e;
109
115
  return {
110
116
  role: n === "decimal" || n === "float" || n === "double" || n === "int" || n === "byte" ? r : t,
111
117
  type: n
112
118
  };
113
119
  }
114
- function B(e) {
115
- return e.role === "measure" ? R : L;
120
+ function H(e) {
121
+ return e.role === "measure" ? B : z;
116
122
  }
117
- function V(e, t) {
123
+ function ie(e, t) {
118
124
  return e.semanticType !== "code" || !e.linkedColumnId || t.get(e.linkedColumnId)?.semanticType !== "text";
119
125
  }
120
- function H(e) {
126
+ function U(e) {
121
127
  if (typeof e.id == "string" && e.id.trim()) return e.id;
122
128
  if ("accessorKey" in e && typeof e.accessorKey == "string" && e.accessorKey.trim()) return e.accessorKey;
123
129
  }
124
- function U(e, t) {
130
+ function W(e, t) {
125
131
  return e.map((e) => "columns" in e && Array.isArray(e.columns) && e.columns.length > 0 ? {
126
132
  ...e,
127
- columns: U(e.columns, t)
133
+ columns: W(e.columns, t)
128
134
  } : t(e));
129
135
  }
130
- function W(e, t) {
136
+ function G(e, t) {
131
137
  let n = new Map(e.map((e) => [e.id, e]));
132
138
  return Object.fromEntries(e.map((e) => {
133
- let r = t?.resolveVisible?.(e) ?? V(e, n);
139
+ let r = t?.resolveVisible?.(e) ?? ie(e, n);
134
140
  return [e.id, r];
135
141
  }));
136
142
  }
137
- function G(e, t) {
143
+ function K(e, t) {
138
144
  return e.map((e) => {
139
- let n = z(e), r = B(n), i = t?.resolveFormatting?.(e);
145
+ let n = V(e), r = H(n), i = t?.resolveFormatting?.(e);
140
146
  return {
141
147
  id: e.id,
142
148
  accessorKey: e.id,
@@ -153,17 +159,17 @@ function G(e, t) {
153
159
  };
154
160
  });
155
161
  }
156
- function K(e, t, n) {
162
+ function q(e, t, n) {
157
163
  let r = new Map(t.map((e) => [e.id, e]));
158
- return U(e, (e) => {
159
- let t = H(e);
164
+ return W(e, (e) => {
165
+ let t = U(e);
160
166
  if (!t) return e;
161
167
  let i = n?.resolveMetadataColumn?.({
162
168
  columnId: t,
163
169
  metadataColumnsById: r
164
170
  }) ?? r.get(t);
165
171
  if (!i || e.meta?.formatting?.role && e.meta.formatting.type) return e;
166
- let a = z(i);
172
+ let a = V(i);
167
173
  return {
168
174
  ...e,
169
175
  meta: {
@@ -180,34 +186,34 @@ function K(e, t, n) {
180
186
  }
181
187
  //#endregion
182
188
  //#region src/table/selection.ts
183
- var q = /* @__PURE__ */ new Set([
184
- D,
185
- ne,
186
- O
189
+ var J = /* @__PURE__ */ new Set([
190
+ O,
191
+ k,
192
+ A
187
193
  ]);
188
- function J(e) {
194
+ function Y(e) {
189
195
  return Object.keys(e).filter((t) => e[t]);
190
196
  }
191
- function Y(e, t) {
192
- let n = J(e), r = J(t);
197
+ function ae(e, t) {
198
+ let n = Y(e), r = Y(t);
193
199
  return n.length === r.length && n.every((e) => t[e]);
194
200
  }
195
- function X(e, t = D) {
196
- return typeof e == "string" && q.has(e) ? e : t;
201
+ function oe(e, t = O) {
202
+ return typeof e == "string" && J.has(e) ? e : t;
197
203
  }
198
- function Z(e, t, n) {
204
+ function X(e, t, n) {
199
205
  if (n === "none") return {};
200
- let r = new Set(t), i = J(e).filter((e) => r.has(e));
206
+ let r = new Set(t), i = Y(e).filter((e) => r.has(e));
201
207
  if (n === "single") {
202
208
  let e = i.at(-1);
203
209
  return e ? { [e]: !0 } : {};
204
210
  }
205
211
  return Object.fromEntries(i.map((e) => [e, !0]));
206
212
  }
207
- function Q(e, t, n) {
213
+ function Z(e, t, n) {
208
214
  if (n === "none") return {};
209
215
  if (n === "single") {
210
- let n = J(e);
216
+ let n = Y(e);
211
217
  return n.length === 1 && n[0] === t ? e : { [t]: !0 };
212
218
  }
213
219
  if (e[t]) {
@@ -221,7 +227,7 @@ function Q(e, t, n) {
221
227
  }
222
228
  //#endregion
223
229
  //#region src/table/tanStackFeatures.ts
224
- var re = _({
230
+ var se = _({
225
231
  columnOrderingFeature: l,
226
232
  columnPinningFeature: u,
227
233
  columnSizingFeature: f,
@@ -233,14 +239,14 @@ var re = _({
233
239
  });
234
240
  //#endregion
235
241
  //#region src/table/useTableRowSelection.ts
236
- function ie({ availableRowIds: e, rowById: t, selectionMode: n, selectedRowIds: r, onRowSelectionChange: l }) {
242
+ function Q({ availableRowIds: e, rowById: t, selectionMode: n, selectedRowIds: r, onRowSelectionChange: l }) {
237
243
  let [u, d] = c({}), f = s(!1), p = i((e, t) => {
238
244
  let n = Object.keys(e).filter((t) => e[t]), r = Object.keys(t).filter((e) => t[e]);
239
245
  return n.length === r.length && n.every((e) => t[e]);
240
246
  }, []), m = o((e) => {
241
- d((t) => Z(t, e, n));
247
+ d((t) => X(t, e, n));
242
248
  }), h = o((e, t) => {
243
- let r = Z(Object.fromEntries(e.map((e) => [e, !0])), t, n);
249
+ let r = X(Object.fromEntries(e.map((e) => [e, !0])), t, n);
244
250
  d((e) => p(e, r) ? e : (f.current = !0, r));
245
251
  }), g = o((e) => {
246
252
  if (!l) return;
@@ -272,23 +278,23 @@ function ie({ availableRowIds: e, rowById: t, selectionMode: n, selectedRowIds:
272
278
  rowSelection: u,
273
279
  setRowSelection: d,
274
280
  activateRowSelection: i((e, t) => {
275
- n === "none" || !t || d((t) => Q(t, e, n));
281
+ n === "none" || !t || d((t) => Z(t, e, n));
276
282
  }, [n])
277
283
  };
278
284
  }
279
285
  //#endregion
280
286
  //#region src/table/utils.ts
281
287
  var $ = (/* @__PURE__ */ "button.a.input.select.textarea.label.summary.audio[controls].video[controls].[contenteditable]:not([contenteditable=\"false\"]).[tabindex]:not(td):not(th):not(tr).[draggable=\"true\"].[role=\"button\"].[role=\"link\"].[role=\"checkbox\"].[role=\"radio\"].[role=\"switch\"].[role=\"menu\"].[role=\"menuitem\"].[role=\"menuitemcheckbox\"].[role=\"menuitemradio\"].[role=\"listbox\"].[role=\"option\"].[role=\"tab\"].[role=\"tablist\"].[role=\"tree\"].[role=\"treeitem\"].[role=\"slider\"].[role=\"spinbutton\"].[role=\"textbox\"].[role=\"searchbox\"].[role=\"combobox\"]".split(".")).join(", ");
282
- function ae(e) {
288
+ function ce(e) {
283
289
  return e.meta;
284
290
  }
285
- function oe(e) {
291
+ function le(e) {
286
292
  return e.meta?.formatting;
287
293
  }
288
- function se(e) {
294
+ function ue(e) {
289
295
  return typeof e == "number" ? `${e}em` : e;
290
296
  }
291
- function ce(e, t) {
297
+ function de(e, t) {
292
298
  if (typeof Element > "u" || !(e instanceof Element)) return !1;
293
299
  let n = t ? `${$}, ${t}` : $, r = e.closest(n);
294
300
  if (!r) return !1;
@@ -296,6 +302,6 @@ function ce(e, t) {
296
302
  return !i || i.contains(r);
297
303
  }
298
304
  //#endregion
299
- export { C as DEFAULT_TABLE_COLUMN_MIN_WIDTH, M as areTableCellSelectionsEqual, Y as areTableRowSelectionsEqual, y as buildTableColumnLayout, W as createTableColumnVisibilityFromODataMetadata, G as createTableColumnsFromODataMetadata, K as enrichTableColumnsWithODataFormatting, re as foundationTableFeatures, oe as getTableColumnFormattingMeta, ae as getTableColumnMeta, ce as isTableInteractiveElement, F as normalizeTableCellSelectionActivationMode, ee as normalizeTableColumnOrder, T as normalizeTableColumnSizing, w as normalizeTableColumnWidth, X as normalizeTableSelectionMode, E as patchTableColumnWidth, N as pruneTableCellSelection, Z as pruneTableRowSelection, te as removeTableColumnWidth, x as reorderTableHeaderColumns, S as resolveReorderedTableHeaderColumns, H as resolveStableColumnId, z as resolveTableColumnFormattingContextFromODataColumn, v as resolveTableColumnOrder, se as resolveTableLength, I as shouldActivateTableCellSelection, P as toggleTableCellSelection, Q as toggleTableRowSelection, ie as useTableRowSelection };
305
+ export { C as DEFAULT_TABLE_COLUMN_MIN_WIDTH, w as DEFAULT_TABLE_COLUMN_MIN_WIDTH_EM, P as areTableCellSelectionsEqual, ae as areTableRowSelectionsEqual, ee as buildTableColumnLayout, G as createTableColumnVisibilityFromODataMetadata, K as createTableColumnsFromODataMetadata, q as enrichTableColumnsWithODataFormatting, se as foundationTableFeatures, le as getTableColumnFormattingMeta, ce as getTableColumnMeta, de as isTableInteractiveElement, L as normalizeTableCellSelectionActivationMode, y as normalizeTableColumnOrder, E as normalizeTableColumnSizing, T as normalizeTableColumnWidth, oe as normalizeTableSelectionMode, te as patchTableColumnWidth, F as pruneTableCellSelection, X as pruneTableRowSelection, ne as removeTableColumnWidth, x as reorderTableHeaderColumns, S as resolveReorderedTableHeaderColumns, U as resolveStableColumnId, V as resolveTableColumnFormattingContextFromODataColumn, v as resolveTableColumnOrder, D as resolveTableColumnsWidth, ue as resolveTableLength, R as shouldActivateTableCellSelection, I as toggleTableCellSelection, Z as toggleTableRowSelection, Q as useTableRowSelection };
300
306
 
301
307
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/table/columnLayout.ts","../../src/table/columnOrder.ts","../../src/table/columnSizing.ts","../../src/table/tableSelectionConstants.ts","../../src/table/cellSelection.ts","../../src/table/tableColumnConstants.ts","../../src/table/odataAdapter.ts","../../src/table/selection.ts","../../src/table/tanStackFeatures.ts","../../src/table/useTableRowSelection.ts","../../src/table/utils.ts"],"sourcesContent":["import { appendMissingIds, filterAndDeduplicateIds } from \"../array\";\n\nexport type TableColumnLayoutItem<TColumnId extends string = string, TWidth = number> = {\n\tid: TColumnId;\n\twidth: TWidth;\n};\n\nexport type ResolveTableColumnOrderArgs<TColumnId extends string = string> = {\n\tids: readonly TColumnId[];\n\torder?: readonly string[];\n};\n\nexport type BuildTableColumnLayoutArgs<TColumnId extends string = string, TWidth = number> = {\n\tids: readonly TColumnId[];\n\tgetWidth: (id: TColumnId) => TWidth;\n};\n\n/**\n * Возвращает порядок колонок как в AnalyticalTable: сначала сохранённый order,\n * затем новые или отсутствующие в order id. Ширины при этом остаются привязаны\n * к columnId, а не к визуальной позиции.\n */\nexport function resolveTableColumnOrder<TColumnId extends string>({ ids, order }: ResolveTableColumnOrderArgs<TColumnId>): TColumnId[] {\n\treturn appendMissingIds(filterAndDeduplicateIds(order, ids), ids);\n}\n\n/**\n * Строит layout колонок из уже вычисленного порядка и функции ширины по id.\n */\nexport function buildTableColumnLayout<TColumnId extends string, TWidth>({\n\tids,\n\tgetWidth\n}: BuildTableColumnLayoutArgs<TColumnId, TWidth>): TableColumnLayoutItem<TColumnId, TWidth>[] {\n\treturn ids.map((id) => ({\n\t\tid,\n\t\twidth: getWidth(id)\n\t}));\n}\n","import { arraysEqual } from \"../array\";\n\nexport type ReorderTableHeaderColumnsArgs = {\n\torder: readonly string[];\n\theaderIds: readonly string[];\n\tlockedIds?: readonly string[];\n\tpinnedIds?: readonly string[];\n\tactiveId: string;\n\toverId: string;\n};\n\nexport type TableColumnOrderState = string[];\n\nexport function normalizeTableColumnOrder(order: readonly string[] | undefined): TableColumnOrderState {\n\treturn Array.from(new Set((order ?? []).filter((columnId) => columnId.trim().length > 0)));\n}\n\nfunction moveItem<T>(items: readonly T[], fromIndex: number, toIndex: number): T[] {\n\tconst nextItems = [...items];\n\tconst [item] = nextItems.splice(fromIndex, 1);\n\n\tif (item === undefined) {\n\t\treturn nextItems;\n\t}\n\n\tnextItems.splice(toIndex, 0, item);\n\treturn nextItems;\n}\n\n/**\n * Переставляет только верхнеуровневые колонки табличной шапки.\n *\n * Ограничения:\n * - дочерние колонки групп не являются самостоятельными draggable-элементами;\n * - locked-колонки остаются в фиксированном порядке;\n * - pinned-колонки не переносятся между закреплённой и обычной зонами.\n */\nexport function reorderTableHeaderColumns(args: ReorderTableHeaderColumnsArgs): string[] {\n\tconst { activeId, overId, order } = args;\n\tif (!activeId || !overId || activeId === overId) return [...order];\n\n\tconst headerSet = new Set(args.headerIds);\n\tif (!headerSet.has(activeId) || !headerSet.has(overId)) return [...order];\n\n\tconst lockedSet = new Set(args.lockedIds ?? []);\n\tif (lockedSet.has(activeId) || lockedSet.has(overId)) return [...order];\n\n\tconst pinnedSet = new Set(args.pinnedIds ?? []);\n\tif (pinnedSet.has(activeId) || pinnedSet.has(overId)) return [...order];\n\n\tconst nextOrder = [...order];\n\tif (!nextOrder.includes(activeId)) {\n\t\tnextOrder.push(activeId);\n\t}\n\tif (!nextOrder.includes(overId)) {\n\t\tnextOrder.push(overId);\n\t}\n\n\tconst fromIndex = nextOrder.indexOf(activeId);\n\tconst toIndex = nextOrder.indexOf(overId);\n\tif (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return nextOrder;\n\n\treturn moveItem(nextOrder, fromIndex, toIndex);\n}\n\nexport function resolveReorderedTableHeaderColumns(args: ReorderTableHeaderColumnsArgs): string[] | null {\n\tconst nextOrder = reorderTableHeaderColumns(args);\n\n\treturn arraysEqual(nextOrder, args.order) ? null : nextOrder;\n}\n","export type TableColumnSizingState = Record<string, number>;\n\nexport const DEFAULT_TABLE_COLUMN_MIN_WIDTH = 60;\n\nexport function normalizeTableColumnWidth(px: number, minWidth: number = DEFAULT_TABLE_COLUMN_MIN_WIDTH): number {\n\tconst normalizedMinWidth = Number.isFinite(minWidth) && minWidth > 0 ? Math.floor(minWidth) : DEFAULT_TABLE_COLUMN_MIN_WIDTH;\n\tconst normalizedWidth = Number.isFinite(px) ? Math.floor(px) : normalizedMinWidth;\n\n\treturn Math.max(normalizedMinWidth, normalizedWidth);\n}\n\nexport function normalizeTableColumnSizing(\n\tstate: Readonly<Record<string, number>> | undefined,\n\tminWidth: number = DEFAULT_TABLE_COLUMN_MIN_WIDTH\n): TableColumnSizingState {\n\tconst nextState: TableColumnSizingState = {};\n\n\tfor (const [columnId, width] of Object.entries(state ?? {})) {\n\t\tif (typeof columnId !== \"string\" || columnId.trim().length === 0 || !Number.isFinite(width)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tnextState[columnId] = normalizeTableColumnWidth(width, minWidth);\n\t}\n\n\treturn nextState;\n}\n\nexport function patchTableColumnWidth(\n\tstate: Readonly<Record<string, number>>,\n\tcolumnId: string,\n\twidth: number,\n\tminWidth: number = DEFAULT_TABLE_COLUMN_MIN_WIDTH\n): TableColumnSizingState {\n\tif (columnId.trim().length === 0) {\n\t\treturn normalizeTableColumnSizing(state, minWidth);\n\t}\n\n\treturn {\n\t\t...normalizeTableColumnSizing(state, minWidth),\n\t\t[columnId]: normalizeTableColumnWidth(width, minWidth)\n\t};\n}\n\nexport function removeTableColumnWidth(state: Readonly<Record<string, number>>, columnId: string): TableColumnSizingState {\n\tconst nextState: TableColumnSizingState = {};\n\n\tfor (const [key, width] of Object.entries(state)) {\n\t\tif (key !== columnId) {\n\t\t\tnextState[key] = width;\n\t\t}\n\t}\n\n\treturn nextState;\n}\n","/** Общие значения кардинальности выбора строк и ячеек; публичные типы используют те же константы. */\nexport const TABLE_SELECTION_MODE_NONE = \"none\";\nexport const TABLE_SELECTION_MODE_SINGLE = \"single\";\nexport const TABLE_SELECTION_MODE_MULTI = \"multi\";\n\n/** Активация выбора отделена от кардинальности и не зависит от платформы пользователя. */\nexport const TABLE_CELL_SELECTION_ACTIVATION_DIRECT = \"direct\";\nexport const TABLE_CELL_SELECTION_ACTIVATION_PRIMARY_MODIFIER = \"primary-modifier\";\n","import {\n\tTABLE_CELL_SELECTION_ACTIVATION_DIRECT,\n\tTABLE_CELL_SELECTION_ACTIVATION_PRIMARY_MODIFIER,\n\tTABLE_SELECTION_MODE_NONE,\n\tTABLE_SELECTION_MODE_SINGLE\n} from \"./tableSelectionConstants\";\nimport {\n\ttype TableCellCoordinates,\n\ttype TableCellSelectionActivationMode,\n\ttype TableCellSelectionMode,\n\ttype TableCellSelectionState,\n\ttype TableSelectionModifierEvent\n} from \"./types\";\n\nconst TABLE_CELL_SELECTION_ACTIVATION_MODES: ReadonlySet<TableCellSelectionActivationMode> = new Set([\n\tTABLE_CELL_SELECTION_ACTIVATION_DIRECT,\n\tTABLE_CELL_SELECTION_ACTIVATION_PRIMARY_MODIFIER\n]);\n\n/** Строит collision-safe identity координат для дедупликации и сравнения. */\nfunction buildTableCellKey(cell: TableCellCoordinates): string {\n\treturn `${encodeURIComponent(cell.rowId)}::${encodeURIComponent(cell.columnId)}`;\n}\n\n/** Проверяет равенство двух наборов координат без зависимости от порядка. */\nexport function areTableCellSelectionsEqual(left: TableCellSelectionState, right: TableCellSelectionState): boolean {\n\tconst leftKeys = new Set(left.map(buildTableCellKey));\n\tconst rightKeys = new Set(right.map(buildTableCellKey));\n\n\tif (leftKeys.size !== rightKeys.size) {\n\t\treturn false;\n\t}\n\n\treturn [...leftKeys].every((key) => rightKeys.has(key));\n}\n\n/**\n * Оставляет только доступные координаты и приводит их к порядку строк/колонок.\n *\n * Функция не мутирует входные массивы. В `single` последняя координата в\n * детерминированном порядке становится единственным выбранным значением.\n */\nexport function pruneTableCellSelection(\n\tselection: TableCellSelectionState | undefined,\n\tavailableRowIds: readonly string[],\n\tavailableColumnIds: readonly string[],\n\tselectionMode: TableCellSelectionMode\n): TableCellCoordinates[] {\n\tif (selectionMode === TABLE_SELECTION_MODE_NONE || !selection?.length) {\n\t\treturn [];\n\t}\n\n\tconst rowOrder = new Map(availableRowIds.map((rowId, index) => [rowId, index]));\n\tconst columnOrder = new Map(availableColumnIds.map((columnId, index) => [columnId, index]));\n\tconst seen = new Set<string>();\n\tconst nextSelection = selection\n\t\t.filter((cell) => {\n\t\t\tif (!(rowOrder.has(cell.rowId) && columnOrder.has(cell.columnId))) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst key = buildTableCellKey(cell);\n\t\t\tif (seen.has(key)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tseen.add(key);\n\t\t\treturn true;\n\t\t})\n\t\t.sort((left, right) => {\n\t\t\tconst rowDelta = (rowOrder.get(left.rowId) ?? 0) - (rowOrder.get(right.rowId) ?? 0);\n\t\t\tif (rowDelta !== 0) {\n\t\t\t\treturn rowDelta;\n\t\t\t}\n\n\t\t\treturn (columnOrder.get(left.columnId) ?? 0) - (columnOrder.get(right.columnId) ?? 0);\n\t\t});\n\n\tif (selectionMode === TABLE_SELECTION_MODE_SINGLE) {\n\t\tconst lastCell = nextSelection.at(-1);\n\t\treturn lastCell ? [lastCell] : [];\n\t}\n\n\treturn nextSelection;\n}\n\n/**\n * Вычисляет следующее состояние после активации ячейки.\n *\n * Одиночный выбор допускает явное снятие повторной активацией, а `multi`\n * переключает только переданную координату.\n */\nexport function toggleTableCellSelection(\n\tselection: TableCellSelectionState,\n\tcell: TableCellCoordinates,\n\tselectionMode: TableCellSelectionMode\n): TableCellCoordinates[] {\n\tif (selectionMode === TABLE_SELECTION_MODE_NONE) {\n\t\treturn [];\n\t}\n\n\tconst cellKey = buildTableCellKey(cell);\n\tconst hasCell = selection.some((item) => buildTableCellKey(item) === cellKey);\n\n\tif (selectionMode === TABLE_SELECTION_MODE_SINGLE) {\n\t\treturn hasCell ? [] : [cell];\n\t}\n\n\treturn hasCell ? selection.filter((item) => buildTableCellKey(item) !== cellKey) : [...selection, cell];\n}\n\n/** Нормализует способ активации ячейки на внешней config-boundary. */\nexport function normalizeTableCellSelectionActivationMode(\n\tvalue: unknown,\n\tfallback: TableCellSelectionActivationMode = TABLE_CELL_SELECTION_ACTIVATION_DIRECT\n): TableCellSelectionActivationMode {\n\treturn typeof value === \"string\" && TABLE_CELL_SELECTION_ACTIVATION_MODES.has(value as TableCellSelectionActivationMode)\n\t\t? (value as TableCellSelectionActivationMode)\n\t\t: fallback;\n}\n\n/**\n * Проверяет, должно ли событие активировать выбор ячейки.\n *\n * Для `primary-modifier` принимается Ctrl или Command, но не комбинации с\n * Shift/Alt: они зарезервированы браузером, ОС и стандартными selection-flow.\n */\nexport function shouldActivateTableCellSelection(\n\tevent: TableSelectionModifierEvent,\n\tactivationMode: TableCellSelectionActivationMode\n): boolean {\n\tif (activationMode === TABLE_CELL_SELECTION_ACTIVATION_DIRECT) {\n\t\treturn true;\n\t}\n\n\treturn (event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey;\n}\n","/** Значения выравнивания общие для metadata-адаптера и публичного типа колонки. */\nexport const TABLE_COLUMN_ALIGN_LEFT = \"left\";\nexport const TABLE_COLUMN_ALIGN_CENTER = \"center\";\nexport const TABLE_COLUMN_ALIGN_RIGHT = \"right\";\n","import { type FormattersPipelineTypedValueContext } from \"../formatters/pipeline\";\nimport { SCALAR_ROLE_MEASURE } from \"../metadata/scalarTypeConstants\";\nimport { type EntityColumnProperty } from \"../odata-service\";\n\nimport { TABLE_COLUMN_ALIGN_LEFT, TABLE_COLUMN_ALIGN_RIGHT } from \"./tableColumnConstants\";\nimport { type TableColumnAlign, type TableColumnDef, type TableColumnFormattingMetaInput } from \"./types\";\n\n/**\n * Опции генерации колонок по OData metadata.\n */\nexport interface CreateTableColumnsFromODataMetadataOptions {\n\t/**\n\t * Позволяет переопределить заголовок колонки.\n\t */\n\tresolveHeader?: (column: EntityColumnProperty) => string;\n\t/**\n\t * Позволяет сразу навесить formatting-конфиг на generated column.\n\t *\n\t * `id`, `role` и `type` будут автоматически получены из metadata.\n\t */\n\tresolveFormatting?: (column: EntityColumnProperty) => TableColumnFormattingMetaInput | undefined;\n}\n\n/**\n * Опции обогащения уже существующих колонок данными OData metadata.\n */\nexport interface EnrichTableColumnsWithODataFormattingOptions {\n\t/**\n\t * Позволяет подменить стратегию поиска metadata по колонке.\n\t */\n\tresolveMetadataColumn?: (args: {\n\t\tcolumnId: string;\n\t\tmetadataColumnsById: ReadonlyMap<string, EntityColumnProperty>;\n\t}) => EntityColumnProperty | undefined;\n}\n\n/**\n * Опции построения стартовой карты видимости колонок по OData metadata.\n */\nexport interface CreateTableColumnVisibilityFromODataMetadataOptions {\n\t/**\n\t * Позволяет явно переопределить стартовую видимость колонки.\n\t */\n\tresolveVisible?: (column: EntityColumnProperty) => boolean;\n}\n\n/**\n * Возвращает typed-formatting контекст по metadata OData-колонки.\n */\nexport function resolveTableColumnFormattingContextFromODataColumn(column: EntityColumnProperty): FormattersPipelineTypedValueContext {\n\tconst { role, type } = column;\n\tconst forceMeasure = type === \"decimal\" || type === \"float\" || type === \"double\" || type === \"int\" || type === \"byte\";\n\n\treturn {\n\t\trole: forceMeasure ? SCALAR_ROLE_MEASURE : role,\n\t\ttype: type\n\t};\n}\n\n/**\n * Создаёт базовое выравнивание по семантике OData-колонки.\n *\n * NOTE: \"не аналитические\" все поля возвращают как \"dimension\"...\n */\nfunction resolveTableColumnAlignFromODataColumn(columnContext: FormattersPipelineTypedValueContext): TableColumnAlign {\n\treturn columnContext.role === SCALAR_ROLE_MEASURE ? TABLE_COLUMN_ALIGN_RIGHT : TABLE_COLUMN_ALIGN_LEFT;\n}\n\n/**\n * Определяет видимость metadata-колонки по умолчанию.\n *\n * Кодовые поля скрываются только если у них есть явная text-пара,\n * чтобы экран по умолчанию показывал человекочитаемое значение.\n */\nfunction resolveMetadataColumnVisibleByDefault(\n\tcolumn: EntityColumnProperty,\n\tmetadataColumnsById: ReadonlyMap<string, EntityColumnProperty>\n): boolean {\n\tif (column.semanticType !== \"code\" || !column.linkedColumnId) {\n\t\treturn true;\n\t}\n\n\tconst linkedColumn = metadataColumnsById.get(column.linkedColumnId);\n\n\treturn linkedColumn?.semanticType !== \"text\";\n}\n\n/**\n * Определяет стабильный идентификатор колонки для сопоставления с metadata.\n */\nexport function resolveStableColumnId<TData extends object>(column: TableColumnDef<TData>): string | undefined {\n\tif (typeof column.id === \"string\" && column.id.trim()) {\n\t\treturn column.id;\n\t}\n\n\tif (\"accessorKey\" in column && typeof column.accessorKey === \"string\" && column.accessorKey.trim()) {\n\t\treturn column.accessorKey;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Рекурсивно обходит только leaf-колонки.\n */\nfunction mapLeafTableColumns<TData extends object>(\n\tcolumns: readonly TableColumnDef<TData>[],\n\tmapper: (column: TableColumnDef<TData>) => TableColumnDef<TData>\n): TableColumnDef<TData>[] {\n\treturn columns.map((column) => {\n\t\tif (\"columns\" in column && Array.isArray(column.columns) && column.columns.length > 0) {\n\t\t\treturn {\n\t\t\t\t...column,\n\t\t\t\tcolumns: mapLeafTableColumns(column.columns as TableColumnDef<TData>[], mapper)\n\t\t\t};\n\t\t}\n\n\t\treturn mapper(column);\n\t});\n}\n\n/**\n * Строит стартовую карту видимости колонок из metadata OData-сущности.\n *\n * Возвращает visibility-state для TanStack Table, не удаляя сами колонки\n * из результата build-режима.\n */\nexport function createTableColumnVisibilityFromODataMetadata(\n\tmetadataColumns: readonly EntityColumnProperty[],\n\toptions?: CreateTableColumnVisibilityFromODataMetadataOptions\n): Record<string, boolean> {\n\tconst metadataColumnsById = new Map(metadataColumns.map((column) => [column.id, column]));\n\n\treturn Object.fromEntries(\n\t\tmetadataColumns.map((column) => {\n\t\t\tconst visible = options?.resolveVisible?.(column) ?? resolveMetadataColumnVisibleByDefault(column, metadataColumnsById);\n\n\t\t\treturn [column.id, visible];\n\t\t})\n\t);\n}\n\n/**\n * Создаёт базовые generic-колонки из metadata OData-сущности.\n */\nexport function createTableColumnsFromODataMetadata<TData extends object = Record<string, unknown>>(\n\tmetadataColumns: readonly EntityColumnProperty[],\n\toptions?: CreateTableColumnsFromODataMetadataOptions\n): TableColumnDef<TData>[] {\n\treturn metadataColumns.map((metadataColumn) => {\n\t\t// NOTE: Ячейка сама определит выравнивание, `align` только для переопределения\n\t\tconst columnContext = resolveTableColumnFormattingContextFromODataColumn(metadataColumn);\n\t\tconst align = resolveTableColumnAlignFromODataColumn(columnContext);\n\t\tconst resolvedFormatting = options?.resolveFormatting?.(metadataColumn);\n\n\t\treturn {\n\t\t\tid: metadataColumn.id,\n\t\t\taccessorKey: metadataColumn.id,\n\t\t\theader: options?.resolveHeader?.(metadataColumn) ?? metadataColumn.label ?? metadataColumn.id,\n\t\t\tmeta: {\n\t\t\t\talign,\n\t\t\t\tformatting: {\n\t\t\t\t\t...resolvedFormatting,\n\t\t\t\t\tid: metadataColumn.id,\n\t\t\t\t\trole: columnContext.role,\n\t\t\t\t\ttype: columnContext.type\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}) as TableColumnDef<TData>[];\n}\n\n/**\n * Дозаполняет уже существующие колонки typed-formatting контекстом из OData metadata.\n */\nexport function enrichTableColumnsWithODataFormatting<TData extends object>(\n\tcolumns: readonly TableColumnDef<TData>[],\n\tmetadataColumns: readonly EntityColumnProperty[],\n\toptions?: EnrichTableColumnsWithODataFormattingOptions\n): TableColumnDef<TData>[] {\n\tconst metadataColumnsById = new Map(metadataColumns.map((column) => [column.id, column]));\n\n\treturn mapLeafTableColumns(columns, (column) => {\n\t\tconst columnId = resolveStableColumnId(column);\n\t\tif (!columnId) {\n\t\t\treturn column;\n\t\t}\n\n\t\tconst metadataColumn =\n\t\t\toptions?.resolveMetadataColumn?.({\n\t\t\t\tcolumnId,\n\t\t\t\tmetadataColumnsById\n\t\t\t}) ?? metadataColumnsById.get(columnId);\n\n\t\tif (!metadataColumn) {\n\t\t\treturn column;\n\t\t}\n\n\t\tif (column.meta?.formatting?.role && column.meta.formatting.type) {\n\t\t\treturn column;\n\t\t}\n\t\tconst columnContext = resolveTableColumnFormattingContextFromODataColumn(metadataColumn);\n\n\t\treturn {\n\t\t\t...column,\n\t\t\tmeta: {\n\t\t\t\t...column.meta,\n\t\t\t\tformatting: {\n\t\t\t\t\t...column.meta?.formatting,\n\t\t\t\t\tid: columnId,\n\t\t\t\t\trole: columnContext.role,\n\t\t\t\t\ttype: columnContext.type\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n","import { type RowSelectionState } from \"@tanstack/react-table\";\n\nimport { TABLE_SELECTION_MODE_MULTI, TABLE_SELECTION_MODE_NONE, TABLE_SELECTION_MODE_SINGLE } from \"./tableSelectionConstants\";\nimport { type TableSelectionMode } from \"./types\";\n\nconst TABLE_SELECTION_MODES: ReadonlySet<TableSelectionMode> = new Set([\n\tTABLE_SELECTION_MODE_NONE,\n\tTABLE_SELECTION_MODE_SINGLE,\n\tTABLE_SELECTION_MODE_MULTI\n]);\n\n/**\n * Возвращает только активные идентификаторы выбранных строк.\n */\nfunction getSelectedRowIds(selection: RowSelectionState): string[] {\n\treturn Object.keys(selection).filter((rowId) => selection[rowId]);\n}\n\n/** Проверяет равенство активных row-selection идентификаторов без учёта порядка ключей. */\nexport function areTableRowSelectionsEqual(left: RowSelectionState, right: RowSelectionState): boolean {\n\tconst leftRowIds = getSelectedRowIds(left);\n\tconst rightRowIds = getSelectedRowIds(right);\n\n\tif (leftRowIds.length !== rightRowIds.length) {\n\t\treturn false;\n\t}\n\n\treturn leftRowIds.every((rowId) => right[rowId]);\n}\n\n/** Нормализует неизвестное значение режима выбора строк на внешней config-boundary. */\nexport function normalizeTableSelectionMode(value: unknown, fallback: TableSelectionMode = TABLE_SELECTION_MODE_NONE): TableSelectionMode {\n\treturn typeof value === \"string\" && TABLE_SELECTION_MODES.has(value as TableSelectionMode) ? (value as TableSelectionMode) : fallback;\n}\n\n/**\n * Нормализует состояние выбора относительно списка доступных строк и текущего режима.\n */\nexport function pruneTableRowSelection(\n\tselection: RowSelectionState,\n\tavailableRowIds: readonly string[],\n\tselectionMode: TableSelectionMode\n): RowSelectionState {\n\tif (selectionMode === TABLE_SELECTION_MODE_NONE) {\n\t\treturn {};\n\t}\n\n\tconst availableRowIdSet = new Set(availableRowIds);\n\tconst selectedRowIds = getSelectedRowIds(selection).filter((rowId) => availableRowIdSet.has(rowId));\n\n\tif (selectionMode === TABLE_SELECTION_MODE_SINGLE) {\n\t\tconst lastSelectedRowId = selectedRowIds.at(-1);\n\n\t\treturn lastSelectedRowId ? { [lastSelectedRowId]: true } : {};\n\t}\n\n\treturn Object.fromEntries(selectedRowIds.map((rowId) => [rowId, true]));\n}\n\n/**\n * Вычисляет следующее состояние выбора после активации строки пользователем.\n *\n * Семантика:\n * - `none` не хранит выбор;\n * - `single` всегда оставляет только одну строку и не снимает выбор повторным кликом;\n * - `multi` переключает строку как toggle.\n */\nexport function toggleTableRowSelection(selection: RowSelectionState, rowId: string, selectionMode: TableSelectionMode): RowSelectionState {\n\tif (selectionMode === TABLE_SELECTION_MODE_NONE) {\n\t\treturn {};\n\t}\n\n\tif (selectionMode === TABLE_SELECTION_MODE_SINGLE) {\n\t\tconst selectedRowIds = getSelectedRowIds(selection);\n\t\treturn selectedRowIds.length === 1 && selectedRowIds[0] === rowId ? selection : { [rowId]: true };\n\t}\n\n\tif (selection[rowId]) {\n\t\tconst nextSelection = { ...selection };\n\n\t\tdelete nextSelection[rowId];\n\n\t\treturn nextSelection;\n\t}\n\n\treturn {\n\t\t...selection,\n\t\t[rowId]: true\n\t};\n}\n","import {\n\tcolumnOrderingFeature,\n\tcolumnPinningFeature,\n\tcolumnResizingFeature,\n\tcolumnSizingFeature,\n\tcolumnVisibilityFeature,\n\tcreateExpandedRowModel,\n\trowExpandingFeature,\n\trowSelectionFeature,\n\ttableFeatures\n} from \"@tanstack/react-table\";\n\n/**\n * Единый набор TanStack Table v9 features для foundation-таблиц.\n *\n * Контракт хранится в `lib`, чтобы определения колонок, строк и экземпляров\n * таблицы в `lib` и `ui` всегда использовали один и тот же набор generic-типов.\n */\nexport const foundationTableFeatures = tableFeatures({\n\tcolumnOrderingFeature,\n\tcolumnPinningFeature,\n\tcolumnSizingFeature,\n\tcolumnResizingFeature,\n\tcolumnVisibilityFeature,\n\trowSelectionFeature,\n\trowExpandingFeature,\n\texpandedRowModel: createExpandedRowModel()\n});\n\n/** Generic-контракт features для публичных типов foundation-таблиц. */\nexport type FoundationTableFeatures = typeof foundationTableFeatures;\n","import { useCallback, useEffect, useEffectEvent, useRef, useState } from \"react\";\n\nimport { type RowSelectionState } from \"@tanstack/react-table\";\n\nimport { pruneTableRowSelection, toggleTableRowSelection } from \"./selection\";\nimport { TABLE_SELECTION_MODE_NONE } from \"./tableSelectionConstants\";\nimport { type TableSelectionMode } from \"./types\";\n\ninterface UseTableRowSelectionParams<TData extends object> {\n\tavailableRowIds: readonly string[];\n\trowById: ReadonlyMap<string, TData>;\n\tselectionMode: TableSelectionMode;\n\tselectedRowIds?: readonly string[];\n\tonRowSelectionChange?: (rows: TData[]) => void;\n}\n\n/**\n * Общая модель выбора строк для плоской и древовидной таблиц.\n */\nexport function useTableRowSelection<TData extends object>({\n\tavailableRowIds,\n\trowById,\n\tselectionMode,\n\tselectedRowIds,\n\tonRowSelectionChange\n}: UseTableRowSelectionParams<TData>) {\n\tconst [rowSelection, setRowSelection] = useState<RowSelectionState>({});\n\tconst shouldSkipNextSelectionEmitRef = useRef(false);\n\n\t/**\n\t * Сравнивает состояния выбора без лишних перерисовок.\n\t */\n\tconst areSelectionsEqual = useCallback((left: RowSelectionState, right: RowSelectionState) => {\n\t\tconst leftRowIds = Object.keys(left).filter((rowId) => left[rowId]);\n\t\tconst rightRowIds = Object.keys(right).filter((rowId) => right[rowId]);\n\n\t\tif (leftRowIds.length !== rightRowIds.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn leftRowIds.every((rowId) => right[rowId]);\n\n\t\t/*\n\n Более оптимизированная версия, но для текущего случая может быть практически незначительной\n\n let leftCount = 0;\n\t\tlet rightCount = 0;\n\n\t\tfor (const rowId of Object.keys(left)) {\n\t\t\tif (!left[rowId]) continue;\n\t\t\tleftCount += 1;\n\t\t\tif (!right[rowId]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (const rowId of Object.keys(right)) {\n\t\t\tif (right[rowId]) {\n\t\t\t\trightCount += 1;\n\t\t\t}\n\t\t}\n\n\t\tif (leftCount !== rightCount) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\n */\n\t}, []);\n\n\tconst syncRowSelectionState = useEffectEvent((nextAvailableRowIds: readonly string[]) => {\n\t\tsetRowSelection((currentSelection) => pruneTableRowSelection(currentSelection, nextAvailableRowIds, selectionMode));\n\t});\n\n\tconst syncControlledRowSelectionState = useEffectEvent(\n\t\t(nextSelectedRowIds: readonly string[], nextAvailableRowIds: readonly string[]) => {\n\t\t\tconst nextSelection = pruneTableRowSelection(\n\t\t\t\tObject.fromEntries(nextSelectedRowIds.map((rowId) => [rowId, true])),\n\t\t\t\tnextAvailableRowIds,\n\t\t\t\tselectionMode\n\t\t\t);\n\n\t\t\tsetRowSelection((currentSelection) => {\n\t\t\t\tif (areSelectionsEqual(currentSelection, nextSelection)) {\n\t\t\t\t\treturn currentSelection;\n\t\t\t\t}\n\n\t\t\t\t// Пропускаем следующий emit, потому что это синхронизация от внешнего controlled-состояния,\n\t\t\t\t// а не пользовательское изменение выбора внутри таблицы.\n\t\t\t\tshouldSkipNextSelectionEmitRef.current = true;\n\n\t\t\t\treturn nextSelection;\n\t\t\t});\n\t\t}\n\t);\n\n\tconst emitRowSelectionChange = useEffectEvent((currentSelection: RowSelectionState) => {\n\t\tif (!onRowSelectionChange) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selectedRows: TData[] = [];\n\n\t\tfor (const rowId of Object.keys(currentSelection)) {\n\t\t\tif (!currentSelection[rowId]) continue;\n\n\t\t\tconst row = rowById.get(rowId);\n\t\t\tif (row) {\n\t\t\t\tselectedRows.push(row);\n\t\t\t}\n\t\t}\n\n\t\tonRowSelectionChange(selectedRows);\n\t});\n\n\tuseEffect(() => {\n\t\tif (selectedRowIds !== undefined) {\n\t\t\tsyncControlledRowSelectionState(selectedRowIds, availableRowIds);\n\t\t\treturn;\n\t\t}\n\n\t\tsyncRowSelectionState(availableRowIds);\n\t}, [availableRowIds, selectedRowIds, selectionMode]);\n\n\tuseEffect(() => {\n\t\tif (shouldSkipNextSelectionEmitRef.current) {\n\t\t\tshouldSkipNextSelectionEmitRef.current = false;\n\t\t\treturn;\n\t\t}\n\n\t\temitRowSelectionChange(rowSelection);\n\t}, [rowSelection]);\n\n\t/**\n\t * Применяет изменение выбора при активации конкретной строки.\n\t */\n\tconst activateRowSelection = useCallback(\n\t\t(rowId: string, canSelect: boolean) => {\n\t\t\tif (selectionMode === TABLE_SELECTION_MODE_NONE || !canSelect) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetRowSelection((currentSelection) => toggleTableRowSelection(currentSelection, rowId, selectionMode));\n\t\t},\n\t\t[selectionMode]\n\t);\n\n\treturn {\n\t\trowSelection,\n\t\tsetRowSelection,\n\t\tactivateRowSelection\n\t};\n}\n","import { TableColumnDef, TableColumnFormattingMeta, TableColumnMeta } from \"./types\";\n\n/**\n * Интерактивные descendants, действие которых таблица не должна подменять\n * выбором строки или ячейки.\n *\n * `td`, `th` и `tr` намеренно исключены из tabindex-ветки: сама таблица может\n * использовать roving tabindex для selection, не превращая ячейку в nested control.\n */\nconst TABLE_INTERACTIVE_ELEMENT_SELECTOR = [\n\t\"button\",\n\t\"a\",\n\t\"input\",\n\t\"select\",\n\t\"textarea\",\n\t\"label\",\n\t\"summary\",\n\t\"audio[controls]\",\n\t\"video[controls]\",\n\t'[contenteditable]:not([contenteditable=\"false\"])',\n\t\"[tabindex]:not(td):not(th):not(tr)\",\n\t'[draggable=\"true\"]',\n\t'[role=\"button\"]',\n\t'[role=\"link\"]',\n\t'[role=\"checkbox\"]',\n\t'[role=\"radio\"]',\n\t'[role=\"switch\"]',\n\t'[role=\"menu\"]',\n\t'[role=\"menuitem\"]',\n\t'[role=\"menuitemcheckbox\"]',\n\t'[role=\"menuitemradio\"]',\n\t'[role=\"listbox\"]',\n\t'[role=\"option\"]',\n\t'[role=\"tab\"]',\n\t'[role=\"tablist\"]',\n\t'[role=\"tree\"]',\n\t'[role=\"treeitem\"]',\n\t'[role=\"slider\"]',\n\t'[role=\"spinbutton\"]',\n\t'[role=\"textbox\"]',\n\t'[role=\"searchbox\"]',\n\t'[role=\"combobox\"]'\n].join(\", \");\n\n/**\n * Возвращает метаданные колонки таблицы.\n */\nexport function getTableColumnMeta<TData extends object>(column: TableColumnDef<TData>): TableColumnMeta | undefined {\n\treturn column.meta;\n}\n\n/**\n * Возвращает форматирующий блок метаданных колонки.\n */\nexport function getTableColumnFormattingMeta<TData extends object>(column: TableColumnDef<TData>): TableColumnFormattingMeta | undefined {\n\treturn column.meta?.formatting;\n}\n\n/**\n * Нормализует размер таблицы.\n *\n * Числовое значение трактуется как `em`, чтобы разметка масштабировалась вместе со шрифтом.\n */\nexport function resolveTableLength(length: string | number): string {\n\tif (typeof length === \"number\") {\n\t\treturn `${length}em`;\n\t}\n\n\treturn length;\n}\n\n/**\n * Определяет, пришёл ли клик из интерактивного элемента внутри таблицы.\n * Учитывает только элементы внутри ближайшей строки: фокусируемая вкладка или\n * диалог вокруг таблицы не должны перехватывать выбор её строк.\n */\nexport function isTableInteractiveElement(target: EventTarget | null, extraSelector?: string): boolean {\n\tif (typeof Element === \"undefined\" || !(target instanceof Element)) {\n\t\treturn false;\n\t}\n\n\tconst selector = extraSelector ? `${TABLE_INTERACTIVE_ELEMENT_SELECTOR}, ${extraSelector}` : TABLE_INTERACTIVE_ELEMENT_SELECTOR;\n\tconst interactiveElement = target.closest(selector);\n\tif (!interactiveElement) return false;\n\n\tconst row = target.closest(\"tr\");\n\treturn !row || row.contains(interactiveElement);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/table/columnLayout.ts","../../src/table/columnOrder.ts","../../src/table/columnSizing.ts","../../src/table/resolveTableColumnsWidth.ts","../../src/table/tableSelectionConstants.ts","../../src/table/cellSelection.ts","../../src/table/tableColumnConstants.ts","../../src/table/odataAdapter.ts","../../src/table/selection.ts","../../src/table/tanStackFeatures.ts","../../src/table/useTableRowSelection.ts","../../src/table/utils.ts"],"sourcesContent":["import { appendMissingIds, filterAndDeduplicateIds } from \"../array\";\n\nexport type TableColumnLayoutItem<TColumnId extends string = string, TWidth = number> = {\n\tid: TColumnId;\n\twidth: TWidth;\n};\n\nexport type ResolveTableColumnOrderArgs<TColumnId extends string = string> = {\n\tids: readonly TColumnId[];\n\torder?: readonly string[];\n};\n\nexport type BuildTableColumnLayoutArgs<TColumnId extends string = string, TWidth = number> = {\n\tids: readonly TColumnId[];\n\tgetWidth: (id: TColumnId) => TWidth;\n};\n\n/**\n * Возвращает порядок колонок как в AnalyticalTable: сначала сохранённый order,\n * затем новые или отсутствующие в order id. Ширины при этом остаются привязаны\n * к columnId, а не к визуальной позиции.\n */\nexport function resolveTableColumnOrder<TColumnId extends string>({ ids, order }: ResolveTableColumnOrderArgs<TColumnId>): TColumnId[] {\n\treturn appendMissingIds(filterAndDeduplicateIds(order, ids), ids);\n}\n\n/**\n * Строит layout колонок из уже вычисленного порядка и функции ширины по id.\n */\nexport function buildTableColumnLayout<TColumnId extends string, TWidth>({\n\tids,\n\tgetWidth\n}: BuildTableColumnLayoutArgs<TColumnId, TWidth>): TableColumnLayoutItem<TColumnId, TWidth>[] {\n\treturn ids.map((id) => ({\n\t\tid,\n\t\twidth: getWidth(id)\n\t}));\n}\n","import { arraysEqual } from \"../array\";\n\nexport type ReorderTableHeaderColumnsArgs = {\n\torder: readonly string[];\n\theaderIds: readonly string[];\n\tlockedIds?: readonly string[];\n\tpinnedIds?: readonly string[];\n\tactiveId: string;\n\toverId: string;\n};\n\nexport type TableColumnOrderState = string[];\n\nexport function normalizeTableColumnOrder(order: readonly string[] | undefined): TableColumnOrderState {\n\treturn Array.from(new Set((order ?? []).filter((columnId) => columnId.trim().length > 0)));\n}\n\nfunction moveItem<T>(items: readonly T[], fromIndex: number, toIndex: number): T[] {\n\tconst nextItems = [...items];\n\tconst [item] = nextItems.splice(fromIndex, 1);\n\n\tif (item === undefined) {\n\t\treturn nextItems;\n\t}\n\n\tnextItems.splice(toIndex, 0, item);\n\treturn nextItems;\n}\n\n/**\n * Переставляет только верхнеуровневые колонки табличной шапки.\n *\n * Ограничения:\n * - дочерние колонки групп не являются самостоятельными draggable-элементами;\n * - locked-колонки остаются в фиксированном порядке;\n * - pinned-колонки не переносятся между закреплённой и обычной зонами.\n */\nexport function reorderTableHeaderColumns(args: ReorderTableHeaderColumnsArgs): string[] {\n\tconst { activeId, overId, order } = args;\n\tif (!activeId || !overId || activeId === overId) return [...order];\n\n\tconst headerSet = new Set(args.headerIds);\n\tif (!headerSet.has(activeId) || !headerSet.has(overId)) return [...order];\n\n\tconst lockedSet = new Set(args.lockedIds ?? []);\n\tif (lockedSet.has(activeId) || lockedSet.has(overId)) return [...order];\n\n\tconst pinnedSet = new Set(args.pinnedIds ?? []);\n\tif (pinnedSet.has(activeId) || pinnedSet.has(overId)) return [...order];\n\n\tconst nextOrder = [...order];\n\tif (!nextOrder.includes(activeId)) {\n\t\tnextOrder.push(activeId);\n\t}\n\tif (!nextOrder.includes(overId)) {\n\t\tnextOrder.push(overId);\n\t}\n\n\tconst fromIndex = nextOrder.indexOf(activeId);\n\tconst toIndex = nextOrder.indexOf(overId);\n\tif (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return nextOrder;\n\n\treturn moveItem(nextOrder, fromIndex, toIndex);\n}\n\nexport function resolveReorderedTableHeaderColumns(args: ReorderTableHeaderColumnsArgs): string[] | null {\n\tconst nextOrder = reorderTableHeaderColumns(args);\n\n\treturn arraysEqual(nextOrder, args.order) ? null : nextOrder;\n}\n","/** Числа sizing-state используют единицу, явно выбранную потребителем; по умолчанию это px. */\nexport type TableColumnSizingState = Record<string, number>;\n\n/** Единица сохранённого размера не зависит от экранных координат pointer/keyboard events. */\nexport type TableColumnSizingUnit = \"px\" | \"em\";\n\nexport const DEFAULT_TABLE_COLUMN_MIN_WIDTH = 60;\nexport const DEFAULT_TABLE_COLUMN_MIN_WIDTH_EM = 4;\n\n/**\n * Нормализует размер в выбранной единице. Для px сохраняется целочисленный контракт,\n * для em остаются четыре знака, чтобы resize не округлялся до целого размера шрифта.\n */\nexport function normalizeTableColumnWidth(width: number, minWidth?: number, unit: TableColumnSizingUnit = \"px\"): number {\n\tconst defaultMinWidth = unit === \"em\" ? DEFAULT_TABLE_COLUMN_MIN_WIDTH_EM : DEFAULT_TABLE_COLUMN_MIN_WIDTH;\n\tconst precision = unit === \"em\" ? 10_000 : 1;\n\tconst normalizedMinWidth =\n\t\ttypeof minWidth === \"number\" && Number.isFinite(minWidth) && minWidth > 0\n\t\t\t? Math.floor(minWidth * precision) / precision\n\t\t\t: defaultMinWidth;\n\tconst normalizedWidth = Number.isFinite(width) ? Math.floor(width * precision) / precision : normalizedMinWidth;\n\n\treturn Math.max(normalizedMinWidth, normalizedWidth);\n}\n\nexport function normalizeTableColumnSizing(\n\tstate: Readonly<Record<string, number>> | undefined,\n\tminWidth?: number,\n\tunit: TableColumnSizingUnit = \"px\"\n): TableColumnSizingState {\n\tconst nextState: TableColumnSizingState = {};\n\n\tfor (const [columnId, width] of Object.entries(state ?? {})) {\n\t\tif (typeof columnId !== \"string\" || columnId.trim().length === 0 || !Number.isFinite(width)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tnextState[columnId] = normalizeTableColumnWidth(width, minWidth, unit);\n\t}\n\n\treturn nextState;\n}\n\nexport function patchTableColumnWidth(\n\tstate: Readonly<Record<string, number>>,\n\tcolumnId: string,\n\twidth: number,\n\tminWidth?: number,\n\tunit: TableColumnSizingUnit = \"px\"\n): TableColumnSizingState {\n\tif (columnId.trim().length === 0) {\n\t\treturn normalizeTableColumnSizing(state, minWidth, unit);\n\t}\n\n\treturn {\n\t\t...normalizeTableColumnSizing(state, minWidth, unit),\n\t\t[columnId]: normalizeTableColumnWidth(width, minWidth, unit)\n\t};\n}\n\nexport function removeTableColumnWidth(state: Readonly<Record<string, number>>, columnId: string): TableColumnSizingState {\n\tconst nextState: TableColumnSizingState = {};\n\n\tfor (const [key, width] of Object.entries(state)) {\n\t\tif (key !== columnId) {\n\t\t\tnextState[key] = width;\n\t\t}\n\t}\n\n\treturn nextState;\n}\n","const TABLE_COLUMN_FIXED_WIDTH_PATTERN = /^(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:em|px)$/;\n\n/**\n * Возвращает сумму определённых ширин колонок без измерения DOM.\n *\n * em сохраняются в CSS, поэтому таблица масштабируется вместе со шрифтом уже\n * при SSR. auto и проценты требуют доступной ширины и остаются в ведении\n * браузерной раскладки: для них нельзя получить независимую сумму колонок.\n */\nexport function resolveTableColumnsWidth(widths: readonly string[]): string | undefined {\n\tif (widths.length === 0 || widths.some((width) => !TABLE_COLUMN_FIXED_WIDTH_PATTERN.test(width))) {\n\t\treturn undefined;\n\t}\n\n\treturn widths.length === 1 ? widths[0] : `calc(${widths.join(\" + \")})`;\n}\n","/** Общие значения кардинальности выбора строк и ячеек; публичные типы используют те же константы. */\nexport const TABLE_SELECTION_MODE_NONE = \"none\";\nexport const TABLE_SELECTION_MODE_SINGLE = \"single\";\nexport const TABLE_SELECTION_MODE_MULTI = \"multi\";\n\n/** Активация выбора отделена от кардинальности и не зависит от платформы пользователя. */\nexport const TABLE_CELL_SELECTION_ACTIVATION_DIRECT = \"direct\";\nexport const TABLE_CELL_SELECTION_ACTIVATION_PRIMARY_MODIFIER = \"primary-modifier\";\n","import {\n\tTABLE_CELL_SELECTION_ACTIVATION_DIRECT,\n\tTABLE_CELL_SELECTION_ACTIVATION_PRIMARY_MODIFIER,\n\tTABLE_SELECTION_MODE_NONE,\n\tTABLE_SELECTION_MODE_SINGLE\n} from \"./tableSelectionConstants\";\nimport {\n\ttype TableCellCoordinates,\n\ttype TableCellSelectionActivationMode,\n\ttype TableCellSelectionMode,\n\ttype TableCellSelectionState,\n\ttype TableSelectionModifierEvent\n} from \"./types\";\n\nconst TABLE_CELL_SELECTION_ACTIVATION_MODES: ReadonlySet<TableCellSelectionActivationMode> = new Set([\n\tTABLE_CELL_SELECTION_ACTIVATION_DIRECT,\n\tTABLE_CELL_SELECTION_ACTIVATION_PRIMARY_MODIFIER\n]);\n\n/** Строит collision-safe identity координат для дедупликации и сравнения. */\nfunction buildTableCellKey(cell: TableCellCoordinates): string {\n\treturn `${encodeURIComponent(cell.rowId)}::${encodeURIComponent(cell.columnId)}`;\n}\n\n/** Проверяет равенство двух наборов координат без зависимости от порядка. */\nexport function areTableCellSelectionsEqual(left: TableCellSelectionState, right: TableCellSelectionState): boolean {\n\tconst leftKeys = new Set(left.map(buildTableCellKey));\n\tconst rightKeys = new Set(right.map(buildTableCellKey));\n\n\tif (leftKeys.size !== rightKeys.size) {\n\t\treturn false;\n\t}\n\n\treturn [...leftKeys].every((key) => rightKeys.has(key));\n}\n\n/**\n * Оставляет только доступные координаты и приводит их к порядку строк/колонок.\n *\n * Функция не мутирует входные массивы. В `single` последняя координата в\n * детерминированном порядке становится единственным выбранным значением.\n */\nexport function pruneTableCellSelection(\n\tselection: TableCellSelectionState | undefined,\n\tavailableRowIds: readonly string[],\n\tavailableColumnIds: readonly string[],\n\tselectionMode: TableCellSelectionMode\n): TableCellCoordinates[] {\n\tif (selectionMode === TABLE_SELECTION_MODE_NONE || !selection?.length) {\n\t\treturn [];\n\t}\n\n\tconst rowOrder = new Map(availableRowIds.map((rowId, index) => [rowId, index]));\n\tconst columnOrder = new Map(availableColumnIds.map((columnId, index) => [columnId, index]));\n\tconst seen = new Set<string>();\n\tconst nextSelection = selection\n\t\t.filter((cell) => {\n\t\t\tif (!(rowOrder.has(cell.rowId) && columnOrder.has(cell.columnId))) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst key = buildTableCellKey(cell);\n\t\t\tif (seen.has(key)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tseen.add(key);\n\t\t\treturn true;\n\t\t})\n\t\t.sort((left, right) => {\n\t\t\tconst rowDelta = (rowOrder.get(left.rowId) ?? 0) - (rowOrder.get(right.rowId) ?? 0);\n\t\t\tif (rowDelta !== 0) {\n\t\t\t\treturn rowDelta;\n\t\t\t}\n\n\t\t\treturn (columnOrder.get(left.columnId) ?? 0) - (columnOrder.get(right.columnId) ?? 0);\n\t\t});\n\n\tif (selectionMode === TABLE_SELECTION_MODE_SINGLE) {\n\t\tconst lastCell = nextSelection.at(-1);\n\t\treturn lastCell ? [lastCell] : [];\n\t}\n\n\treturn nextSelection;\n}\n\n/**\n * Вычисляет следующее состояние после активации ячейки.\n *\n * Одиночный выбор допускает явное снятие повторной активацией, а `multi`\n * переключает только переданную координату.\n */\nexport function toggleTableCellSelection(\n\tselection: TableCellSelectionState,\n\tcell: TableCellCoordinates,\n\tselectionMode: TableCellSelectionMode\n): TableCellCoordinates[] {\n\tif (selectionMode === TABLE_SELECTION_MODE_NONE) {\n\t\treturn [];\n\t}\n\n\tconst cellKey = buildTableCellKey(cell);\n\tconst hasCell = selection.some((item) => buildTableCellKey(item) === cellKey);\n\n\tif (selectionMode === TABLE_SELECTION_MODE_SINGLE) {\n\t\treturn hasCell ? [] : [cell];\n\t}\n\n\treturn hasCell ? selection.filter((item) => buildTableCellKey(item) !== cellKey) : [...selection, cell];\n}\n\n/** Нормализует способ активации ячейки на внешней config-boundary. */\nexport function normalizeTableCellSelectionActivationMode(\n\tvalue: unknown,\n\tfallback: TableCellSelectionActivationMode = TABLE_CELL_SELECTION_ACTIVATION_DIRECT\n): TableCellSelectionActivationMode {\n\treturn typeof value === \"string\" && TABLE_CELL_SELECTION_ACTIVATION_MODES.has(value as TableCellSelectionActivationMode)\n\t\t? (value as TableCellSelectionActivationMode)\n\t\t: fallback;\n}\n\n/**\n * Проверяет, должно ли событие активировать выбор ячейки.\n *\n * Для `primary-modifier` принимается Ctrl или Command, но не комбинации с\n * Shift/Alt: они зарезервированы браузером, ОС и стандартными selection-flow.\n */\nexport function shouldActivateTableCellSelection(\n\tevent: TableSelectionModifierEvent,\n\tactivationMode: TableCellSelectionActivationMode\n): boolean {\n\tif (activationMode === TABLE_CELL_SELECTION_ACTIVATION_DIRECT) {\n\t\treturn true;\n\t}\n\n\treturn (event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey;\n}\n","/** Значения выравнивания общие для metadata-адаптера и публичного типа колонки. */\nexport const TABLE_COLUMN_ALIGN_LEFT = \"left\";\nexport const TABLE_COLUMN_ALIGN_CENTER = \"center\";\nexport const TABLE_COLUMN_ALIGN_RIGHT = \"right\";\n","import { type FormattersPipelineTypedValueContext } from \"../formatters/pipeline\";\nimport { SCALAR_ROLE_MEASURE } from \"../metadata/scalarTypeConstants\";\nimport { type EntityColumnProperty } from \"../odata-service\";\n\nimport { TABLE_COLUMN_ALIGN_LEFT, TABLE_COLUMN_ALIGN_RIGHT } from \"./tableColumnConstants\";\nimport { type TableColumnAlign, type TableColumnDef, type TableColumnFormattingMetaInput } from \"./types\";\n\n/**\n * Опции генерации колонок по OData metadata.\n */\nexport interface CreateTableColumnsFromODataMetadataOptions {\n\t/**\n\t * Позволяет переопределить заголовок колонки.\n\t */\n\tresolveHeader?: (column: EntityColumnProperty) => string;\n\t/**\n\t * Позволяет сразу навесить formatting-конфиг на generated column.\n\t *\n\t * `id`, `role` и `type` будут автоматически получены из metadata.\n\t */\n\tresolveFormatting?: (column: EntityColumnProperty) => TableColumnFormattingMetaInput | undefined;\n}\n\n/**\n * Опции обогащения уже существующих колонок данными OData metadata.\n */\nexport interface EnrichTableColumnsWithODataFormattingOptions {\n\t/**\n\t * Позволяет подменить стратегию поиска metadata по колонке.\n\t */\n\tresolveMetadataColumn?: (args: {\n\t\tcolumnId: string;\n\t\tmetadataColumnsById: ReadonlyMap<string, EntityColumnProperty>;\n\t}) => EntityColumnProperty | undefined;\n}\n\n/**\n * Опции построения стартовой карты видимости колонок по OData metadata.\n */\nexport interface CreateTableColumnVisibilityFromODataMetadataOptions {\n\t/**\n\t * Позволяет явно переопределить стартовую видимость колонки.\n\t */\n\tresolveVisible?: (column: EntityColumnProperty) => boolean;\n}\n\n/**\n * Возвращает typed-formatting контекст по metadata OData-колонки.\n */\nexport function resolveTableColumnFormattingContextFromODataColumn(column: EntityColumnProperty): FormattersPipelineTypedValueContext {\n\tconst { role, type } = column;\n\tconst forceMeasure = type === \"decimal\" || type === \"float\" || type === \"double\" || type === \"int\" || type === \"byte\";\n\n\treturn {\n\t\trole: forceMeasure ? SCALAR_ROLE_MEASURE : role,\n\t\ttype: type\n\t};\n}\n\n/**\n * Создаёт базовое выравнивание по семантике OData-колонки.\n *\n * NOTE: \"не аналитические\" все поля возвращают как \"dimension\"...\n */\nfunction resolveTableColumnAlignFromODataColumn(columnContext: FormattersPipelineTypedValueContext): TableColumnAlign {\n\treturn columnContext.role === SCALAR_ROLE_MEASURE ? TABLE_COLUMN_ALIGN_RIGHT : TABLE_COLUMN_ALIGN_LEFT;\n}\n\n/**\n * Определяет видимость metadata-колонки по умолчанию.\n *\n * Кодовые поля скрываются только если у них есть явная text-пара,\n * чтобы экран по умолчанию показывал человекочитаемое значение.\n */\nfunction resolveMetadataColumnVisibleByDefault(\n\tcolumn: EntityColumnProperty,\n\tmetadataColumnsById: ReadonlyMap<string, EntityColumnProperty>\n): boolean {\n\tif (column.semanticType !== \"code\" || !column.linkedColumnId) {\n\t\treturn true;\n\t}\n\n\tconst linkedColumn = metadataColumnsById.get(column.linkedColumnId);\n\n\treturn linkedColumn?.semanticType !== \"text\";\n}\n\n/**\n * Определяет стабильный идентификатор колонки для сопоставления с metadata.\n */\nexport function resolveStableColumnId<TData extends object>(column: TableColumnDef<TData>): string | undefined {\n\tif (typeof column.id === \"string\" && column.id.trim()) {\n\t\treturn column.id;\n\t}\n\n\tif (\"accessorKey\" in column && typeof column.accessorKey === \"string\" && column.accessorKey.trim()) {\n\t\treturn column.accessorKey;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Рекурсивно обходит только leaf-колонки.\n */\nfunction mapLeafTableColumns<TData extends object>(\n\tcolumns: readonly TableColumnDef<TData>[],\n\tmapper: (column: TableColumnDef<TData>) => TableColumnDef<TData>\n): TableColumnDef<TData>[] {\n\treturn columns.map((column) => {\n\t\tif (\"columns\" in column && Array.isArray(column.columns) && column.columns.length > 0) {\n\t\t\treturn {\n\t\t\t\t...column,\n\t\t\t\tcolumns: mapLeafTableColumns(column.columns as TableColumnDef<TData>[], mapper)\n\t\t\t};\n\t\t}\n\n\t\treturn mapper(column);\n\t});\n}\n\n/**\n * Строит стартовую карту видимости колонок из metadata OData-сущности.\n *\n * Возвращает visibility-state для TanStack Table, не удаляя сами колонки\n * из результата build-режима.\n */\nexport function createTableColumnVisibilityFromODataMetadata(\n\tmetadataColumns: readonly EntityColumnProperty[],\n\toptions?: CreateTableColumnVisibilityFromODataMetadataOptions\n): Record<string, boolean> {\n\tconst metadataColumnsById = new Map(metadataColumns.map((column) => [column.id, column]));\n\n\treturn Object.fromEntries(\n\t\tmetadataColumns.map((column) => {\n\t\t\tconst visible = options?.resolveVisible?.(column) ?? resolveMetadataColumnVisibleByDefault(column, metadataColumnsById);\n\n\t\t\treturn [column.id, visible];\n\t\t})\n\t);\n}\n\n/**\n * Создаёт базовые generic-колонки из metadata OData-сущности.\n */\nexport function createTableColumnsFromODataMetadata<TData extends object = Record<string, unknown>>(\n\tmetadataColumns: readonly EntityColumnProperty[],\n\toptions?: CreateTableColumnsFromODataMetadataOptions\n): TableColumnDef<TData>[] {\n\treturn metadataColumns.map((metadataColumn) => {\n\t\t// NOTE: Ячейка сама определит выравнивание, `align` только для переопределения\n\t\tconst columnContext = resolveTableColumnFormattingContextFromODataColumn(metadataColumn);\n\t\tconst align = resolveTableColumnAlignFromODataColumn(columnContext);\n\t\tconst resolvedFormatting = options?.resolveFormatting?.(metadataColumn);\n\n\t\treturn {\n\t\t\tid: metadataColumn.id,\n\t\t\taccessorKey: metadataColumn.id,\n\t\t\theader: options?.resolveHeader?.(metadataColumn) ?? metadataColumn.label ?? metadataColumn.id,\n\t\t\tmeta: {\n\t\t\t\talign,\n\t\t\t\tformatting: {\n\t\t\t\t\t...resolvedFormatting,\n\t\t\t\t\tid: metadataColumn.id,\n\t\t\t\t\trole: columnContext.role,\n\t\t\t\t\ttype: columnContext.type\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}) as TableColumnDef<TData>[];\n}\n\n/**\n * Дозаполняет уже существующие колонки typed-formatting контекстом из OData metadata.\n */\nexport function enrichTableColumnsWithODataFormatting<TData extends object>(\n\tcolumns: readonly TableColumnDef<TData>[],\n\tmetadataColumns: readonly EntityColumnProperty[],\n\toptions?: EnrichTableColumnsWithODataFormattingOptions\n): TableColumnDef<TData>[] {\n\tconst metadataColumnsById = new Map(metadataColumns.map((column) => [column.id, column]));\n\n\treturn mapLeafTableColumns(columns, (column) => {\n\t\tconst columnId = resolveStableColumnId(column);\n\t\tif (!columnId) {\n\t\t\treturn column;\n\t\t}\n\n\t\tconst metadataColumn =\n\t\t\toptions?.resolveMetadataColumn?.({\n\t\t\t\tcolumnId,\n\t\t\t\tmetadataColumnsById\n\t\t\t}) ?? metadataColumnsById.get(columnId);\n\n\t\tif (!metadataColumn) {\n\t\t\treturn column;\n\t\t}\n\n\t\tif (column.meta?.formatting?.role && column.meta.formatting.type) {\n\t\t\treturn column;\n\t\t}\n\t\tconst columnContext = resolveTableColumnFormattingContextFromODataColumn(metadataColumn);\n\n\t\treturn {\n\t\t\t...column,\n\t\t\tmeta: {\n\t\t\t\t...column.meta,\n\t\t\t\tformatting: {\n\t\t\t\t\t...column.meta?.formatting,\n\t\t\t\t\tid: columnId,\n\t\t\t\t\trole: columnContext.role,\n\t\t\t\t\ttype: columnContext.type\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n","import { type RowSelectionState } from \"@tanstack/react-table\";\n\nimport { TABLE_SELECTION_MODE_MULTI, TABLE_SELECTION_MODE_NONE, TABLE_SELECTION_MODE_SINGLE } from \"./tableSelectionConstants\";\nimport { type TableSelectionMode } from \"./types\";\n\nconst TABLE_SELECTION_MODES: ReadonlySet<TableSelectionMode> = new Set([\n\tTABLE_SELECTION_MODE_NONE,\n\tTABLE_SELECTION_MODE_SINGLE,\n\tTABLE_SELECTION_MODE_MULTI\n]);\n\n/**\n * Возвращает только активные идентификаторы выбранных строк.\n */\nfunction getSelectedRowIds(selection: RowSelectionState): string[] {\n\treturn Object.keys(selection).filter((rowId) => selection[rowId]);\n}\n\n/** Проверяет равенство активных row-selection идентификаторов без учёта порядка ключей. */\nexport function areTableRowSelectionsEqual(left: RowSelectionState, right: RowSelectionState): boolean {\n\tconst leftRowIds = getSelectedRowIds(left);\n\tconst rightRowIds = getSelectedRowIds(right);\n\n\tif (leftRowIds.length !== rightRowIds.length) {\n\t\treturn false;\n\t}\n\n\treturn leftRowIds.every((rowId) => right[rowId]);\n}\n\n/** Нормализует неизвестное значение режима выбора строк на внешней config-boundary. */\nexport function normalizeTableSelectionMode(value: unknown, fallback: TableSelectionMode = TABLE_SELECTION_MODE_NONE): TableSelectionMode {\n\treturn typeof value === \"string\" && TABLE_SELECTION_MODES.has(value as TableSelectionMode) ? (value as TableSelectionMode) : fallback;\n}\n\n/**\n * Нормализует состояние выбора относительно списка доступных строк и текущего режима.\n */\nexport function pruneTableRowSelection(\n\tselection: RowSelectionState,\n\tavailableRowIds: readonly string[],\n\tselectionMode: TableSelectionMode\n): RowSelectionState {\n\tif (selectionMode === TABLE_SELECTION_MODE_NONE) {\n\t\treturn {};\n\t}\n\n\tconst availableRowIdSet = new Set(availableRowIds);\n\tconst selectedRowIds = getSelectedRowIds(selection).filter((rowId) => availableRowIdSet.has(rowId));\n\n\tif (selectionMode === TABLE_SELECTION_MODE_SINGLE) {\n\t\tconst lastSelectedRowId = selectedRowIds.at(-1);\n\n\t\treturn lastSelectedRowId ? { [lastSelectedRowId]: true } : {};\n\t}\n\n\treturn Object.fromEntries(selectedRowIds.map((rowId) => [rowId, true]));\n}\n\n/**\n * Вычисляет следующее состояние выбора после активации строки пользователем.\n *\n * Семантика:\n * - `none` не хранит выбор;\n * - `single` всегда оставляет только одну строку и не снимает выбор повторным кликом;\n * - `multi` переключает строку как toggle.\n */\nexport function toggleTableRowSelection(selection: RowSelectionState, rowId: string, selectionMode: TableSelectionMode): RowSelectionState {\n\tif (selectionMode === TABLE_SELECTION_MODE_NONE) {\n\t\treturn {};\n\t}\n\n\tif (selectionMode === TABLE_SELECTION_MODE_SINGLE) {\n\t\tconst selectedRowIds = getSelectedRowIds(selection);\n\t\treturn selectedRowIds.length === 1 && selectedRowIds[0] === rowId ? selection : { [rowId]: true };\n\t}\n\n\tif (selection[rowId]) {\n\t\tconst nextSelection = { ...selection };\n\n\t\tdelete nextSelection[rowId];\n\n\t\treturn nextSelection;\n\t}\n\n\treturn {\n\t\t...selection,\n\t\t[rowId]: true\n\t};\n}\n","import {\n\tcolumnOrderingFeature,\n\tcolumnPinningFeature,\n\tcolumnResizingFeature,\n\tcolumnSizingFeature,\n\tcolumnVisibilityFeature,\n\tcreateExpandedRowModel,\n\trowExpandingFeature,\n\trowSelectionFeature,\n\ttableFeatures\n} from \"@tanstack/react-table\";\n\n/**\n * Единый набор TanStack Table v9 features для foundation-таблиц.\n *\n * Контракт хранится в `lib`, чтобы определения колонок, строк и экземпляров\n * таблицы в `lib` и `ui` всегда использовали один и тот же набор generic-типов.\n */\nexport const foundationTableFeatures = tableFeatures({\n\tcolumnOrderingFeature,\n\tcolumnPinningFeature,\n\tcolumnSizingFeature,\n\tcolumnResizingFeature,\n\tcolumnVisibilityFeature,\n\trowSelectionFeature,\n\trowExpandingFeature,\n\texpandedRowModel: createExpandedRowModel()\n});\n\n/** Generic-контракт features для публичных типов foundation-таблиц. */\nexport type FoundationTableFeatures = typeof foundationTableFeatures;\n","import { useCallback, useEffect, useEffectEvent, useRef, useState } from \"react\";\n\nimport { type RowSelectionState } from \"@tanstack/react-table\";\n\nimport { pruneTableRowSelection, toggleTableRowSelection } from \"./selection\";\nimport { TABLE_SELECTION_MODE_NONE } from \"./tableSelectionConstants\";\nimport { type TableSelectionMode } from \"./types\";\n\ninterface UseTableRowSelectionParams<TData extends object> {\n\tavailableRowIds: readonly string[];\n\trowById: ReadonlyMap<string, TData>;\n\tselectionMode: TableSelectionMode;\n\tselectedRowIds?: readonly string[];\n\tonRowSelectionChange?: (rows: TData[]) => void;\n}\n\n/**\n * Общая модель выбора строк для плоской и древовидной таблиц.\n */\nexport function useTableRowSelection<TData extends object>({\n\tavailableRowIds,\n\trowById,\n\tselectionMode,\n\tselectedRowIds,\n\tonRowSelectionChange\n}: UseTableRowSelectionParams<TData>) {\n\tconst [rowSelection, setRowSelection] = useState<RowSelectionState>({});\n\tconst shouldSkipNextSelectionEmitRef = useRef(false);\n\n\t/**\n\t * Сравнивает состояния выбора без лишних перерисовок.\n\t */\n\tconst areSelectionsEqual = useCallback((left: RowSelectionState, right: RowSelectionState) => {\n\t\tconst leftRowIds = Object.keys(left).filter((rowId) => left[rowId]);\n\t\tconst rightRowIds = Object.keys(right).filter((rowId) => right[rowId]);\n\n\t\tif (leftRowIds.length !== rightRowIds.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn leftRowIds.every((rowId) => right[rowId]);\n\n\t\t/*\n\n Более оптимизированная версия, но для текущего случая может быть практически незначительной\n\n let leftCount = 0;\n\t\tlet rightCount = 0;\n\n\t\tfor (const rowId of Object.keys(left)) {\n\t\t\tif (!left[rowId]) continue;\n\t\t\tleftCount += 1;\n\t\t\tif (!right[rowId]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (const rowId of Object.keys(right)) {\n\t\t\tif (right[rowId]) {\n\t\t\t\trightCount += 1;\n\t\t\t}\n\t\t}\n\n\t\tif (leftCount !== rightCount) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\n */\n\t}, []);\n\n\tconst syncRowSelectionState = useEffectEvent((nextAvailableRowIds: readonly string[]) => {\n\t\tsetRowSelection((currentSelection) => pruneTableRowSelection(currentSelection, nextAvailableRowIds, selectionMode));\n\t});\n\n\tconst syncControlledRowSelectionState = useEffectEvent(\n\t\t(nextSelectedRowIds: readonly string[], nextAvailableRowIds: readonly string[]) => {\n\t\t\tconst nextSelection = pruneTableRowSelection(\n\t\t\t\tObject.fromEntries(nextSelectedRowIds.map((rowId) => [rowId, true])),\n\t\t\t\tnextAvailableRowIds,\n\t\t\t\tselectionMode\n\t\t\t);\n\n\t\t\tsetRowSelection((currentSelection) => {\n\t\t\t\tif (areSelectionsEqual(currentSelection, nextSelection)) {\n\t\t\t\t\treturn currentSelection;\n\t\t\t\t}\n\n\t\t\t\t// Пропускаем следующий emit, потому что это синхронизация от внешнего controlled-состояния,\n\t\t\t\t// а не пользовательское изменение выбора внутри таблицы.\n\t\t\t\tshouldSkipNextSelectionEmitRef.current = true;\n\n\t\t\t\treturn nextSelection;\n\t\t\t});\n\t\t}\n\t);\n\n\tconst emitRowSelectionChange = useEffectEvent((currentSelection: RowSelectionState) => {\n\t\tif (!onRowSelectionChange) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selectedRows: TData[] = [];\n\n\t\tfor (const rowId of Object.keys(currentSelection)) {\n\t\t\tif (!currentSelection[rowId]) continue;\n\n\t\t\tconst row = rowById.get(rowId);\n\t\t\tif (row) {\n\t\t\t\tselectedRows.push(row);\n\t\t\t}\n\t\t}\n\n\t\tonRowSelectionChange(selectedRows);\n\t});\n\n\tuseEffect(() => {\n\t\tif (selectedRowIds !== undefined) {\n\t\t\tsyncControlledRowSelectionState(selectedRowIds, availableRowIds);\n\t\t\treturn;\n\t\t}\n\n\t\tsyncRowSelectionState(availableRowIds);\n\t}, [availableRowIds, selectedRowIds, selectionMode]);\n\n\tuseEffect(() => {\n\t\tif (shouldSkipNextSelectionEmitRef.current) {\n\t\t\tshouldSkipNextSelectionEmitRef.current = false;\n\t\t\treturn;\n\t\t}\n\n\t\temitRowSelectionChange(rowSelection);\n\t}, [rowSelection]);\n\n\t/**\n\t * Применяет изменение выбора при активации конкретной строки.\n\t */\n\tconst activateRowSelection = useCallback(\n\t\t(rowId: string, canSelect: boolean) => {\n\t\t\tif (selectionMode === TABLE_SELECTION_MODE_NONE || !canSelect) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetRowSelection((currentSelection) => toggleTableRowSelection(currentSelection, rowId, selectionMode));\n\t\t},\n\t\t[selectionMode]\n\t);\n\n\treturn {\n\t\trowSelection,\n\t\tsetRowSelection,\n\t\tactivateRowSelection\n\t};\n}\n","import { TableColumnDef, TableColumnFormattingMeta, TableColumnMeta } from \"./types\";\n\n/**\n * Интерактивные descendants, действие которых таблица не должна подменять\n * выбором строки или ячейки.\n *\n * `td`, `th` и `tr` намеренно исключены из tabindex-ветки: сама таблица может\n * использовать roving tabindex для selection, не превращая ячейку в nested control.\n */\nconst TABLE_INTERACTIVE_ELEMENT_SELECTOR = [\n\t\"button\",\n\t\"a\",\n\t\"input\",\n\t\"select\",\n\t\"textarea\",\n\t\"label\",\n\t\"summary\",\n\t\"audio[controls]\",\n\t\"video[controls]\",\n\t'[contenteditable]:not([contenteditable=\"false\"])',\n\t\"[tabindex]:not(td):not(th):not(tr)\",\n\t'[draggable=\"true\"]',\n\t'[role=\"button\"]',\n\t'[role=\"link\"]',\n\t'[role=\"checkbox\"]',\n\t'[role=\"radio\"]',\n\t'[role=\"switch\"]',\n\t'[role=\"menu\"]',\n\t'[role=\"menuitem\"]',\n\t'[role=\"menuitemcheckbox\"]',\n\t'[role=\"menuitemradio\"]',\n\t'[role=\"listbox\"]',\n\t'[role=\"option\"]',\n\t'[role=\"tab\"]',\n\t'[role=\"tablist\"]',\n\t'[role=\"tree\"]',\n\t'[role=\"treeitem\"]',\n\t'[role=\"slider\"]',\n\t'[role=\"spinbutton\"]',\n\t'[role=\"textbox\"]',\n\t'[role=\"searchbox\"]',\n\t'[role=\"combobox\"]'\n].join(\", \");\n\n/**\n * Возвращает метаданные колонки таблицы.\n */\nexport function getTableColumnMeta<TData extends object>(column: TableColumnDef<TData>): TableColumnMeta | undefined {\n\treturn column.meta;\n}\n\n/**\n * Возвращает форматирующий блок метаданных колонки.\n */\nexport function getTableColumnFormattingMeta<TData extends object>(column: TableColumnDef<TData>): TableColumnFormattingMeta | undefined {\n\treturn column.meta?.formatting;\n}\n\n/**\n * Нормализует размер таблицы.\n *\n * Числовое значение трактуется как `em`, чтобы разметка масштабировалась вместе со шрифтом.\n */\nexport function resolveTableLength(length: string | number): string {\n\tif (typeof length === \"number\") {\n\t\treturn `${length}em`;\n\t}\n\n\treturn length;\n}\n\n/**\n * Определяет, пришёл ли клик из интерактивного элемента внутри таблицы.\n * Учитывает только элементы внутри ближайшей строки: фокусируемая вкладка или\n * диалог вокруг таблицы не должны перехватывать выбор её строк.\n */\nexport function isTableInteractiveElement(target: EventTarget | null, extraSelector?: string): boolean {\n\tif (typeof Element === \"undefined\" || !(target instanceof Element)) {\n\t\treturn false;\n\t}\n\n\tconst selector = extraSelector ? `${TABLE_INTERACTIVE_ELEMENT_SELECTOR}, ${extraSelector}` : TABLE_INTERACTIVE_ELEMENT_SELECTOR;\n\tconst interactiveElement = target.closest(selector);\n\tif (!interactiveElement) return false;\n\n\tconst row = target.closest(\"tr\");\n\treturn !row || row.contains(interactiveElement);\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Возвращает сумму определённых ширин колонок без измерения DOM.
3
+ *
4
+ * em сохраняются в CSS, поэтому таблица масштабируется вместе со шрифтом уже
5
+ * при SSR. auto и проценты требуют доступной ширины и остаются в ведении
6
+ * браузерной раскладки: для них нельзя получить независимую сумму колонок.
7
+ */
8
+ export declare function resolveTableColumnsWidth(widths: readonly string[]): string | undefined;
9
+ //# sourceMappingURL=resolveTableColumnsWidth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveTableColumnsWidth.d.ts","sourceRoot":"","sources":["../../src/table/resolveTableColumnsWidth.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAMtF"}
@@ -66,7 +66,7 @@ export interface TableColumnMeta {
66
66
  *
67
67
  * Строка используется как CSS-значение, число трактуется как `em`.
68
68
  */
69
- width?: number | "auto" | `${number}%`;
69
+ width?: number | "auto" | `${number}%` | `${number}px` | `${number}em`;
70
70
  /**
71
71
  * Выравнивание содержимого заголовка и ячеек.
72
72
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/table/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/table/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuzaki13/react-foundation-lib",
3
- "version": "2.31.3",
3
+ "version": "2.32.0",
4
4
  "description": "Reusable React and TypeScript foundation utilities, hooks, and primitives.",
5
5
  "license": "MIT",
6
6
  "author": "Ryuzaki13",
@@ -394,7 +394,7 @@ const orderColumns = [
394
394
  ] satisfies TableColumnDef<Order>[];
395
395
  ```
396
396
 
397
- Число `24` в `meta.width` означает `24em`, а не `24px`. Runtime px-ширины resize хранятся отдельно в `TableColumnSizingState`.
397
+ Число `24` в `meta.width` означает `24em`, а не `24px`. Размеры resize хранятся отдельно в `TableColumnSizingState`; по умолчанию это px, при явном выборе единицы поддерживаются em.
398
398
 
399
399
  ### 3. Вычислите selection
400
400
 
@@ -538,7 +538,7 @@ const fullNameColumn: TableColumnDef<Person, string> = {
538
538
 
539
539
  ```ts
540
540
  interface TableColumnMeta {
541
- width?: number | "auto" | `${number}%`;
541
+ width?: number | "auto" | `${number}%` | `${number}px` | `${number}em`;
542
542
  align?: "left" | "center" | "right";
543
543
  mergeDuplicates?: boolean;
544
544
  formatting?: TableColumnFormattingMeta;
@@ -547,13 +547,15 @@ interface TableColumnMeta {
547
547
 
548
548
  #### `width`
549
549
 
550
- | Значение | Смысл |
551
- | -------- | --------------------------------------- |
552
- | `12` | `12em` в декларативной metadata колонки |
553
- | `"auto"` | автоматическая CSS-ширина |
554
- | `"25%"` | процентная CSS-ширина |
550
+ | Значение | Смысл |
551
+ | ---------- | --------------------------------------- |
552
+ | `12` | `12em` в декларативной metadata колонки |
553
+ | `"auto"` | автоматическая CSS-ширина |
554
+ | `"25%"` | процентная CSS-ширина |
555
+ | `"120px"` | фиксированная ширина в px |
556
+ | `"12.5em"` | явная относительная ширина |
555
557
 
556
- Это не то же самое, что `TableColumnSizingState`: sizing state хранит число пикселей, полученное от resize runtime.
558
+ Это не то же самое, что `TableColumnSizingState`: sizing state хранит размеры resize runtime в выбранной единице (`px` по умолчанию, `em` при явном включении).
557
559
 
558
560
  #### `align`
559
561
 
@@ -904,12 +906,33 @@ if (nextOrder) {
904
906
 
905
907
  Не смешивайте:
906
908
 
907
- | Представление | Пример | Единица |
908
- | ------------------------ | ----------------------- | ------------------- |
909
- | `TableColumnMeta.width` | `12`, `"auto"`, `"25%"` | число означает `em` |
910
- | `TableColumnSizingState` | `{ amount: 160 }` | число означает px |
909
+ | Представление | Пример | Единица |
910
+ | ------------------------ | ----------------------- | ------------------------------------ |
911
+ | `TableColumnMeta.width` | `12`, `"auto"`, `"25%"` | число означает `em` |
912
+ | `TableColumnSizingState` | `{ amount: 160 }` | px по умолчанию; em при явном выборе |
911
913
 
912
- Helpers этого раздела работают со вторым представлением — px sizing state.
914
+ Helpers этого раздела работают со вторым представлением. Необязательный аргумент `unit: TableColumnSizingUnit` выбирает `"px"` (по умолчанию) или `"em"`. Единица должна совпадать у нормализации, UI и сохранённого профиля; изменение единицы не конвертирует существующие числа.
915
+
916
+ Для `em` минимальная ширина по умолчанию равна `DEFAULT_TABLE_COLUMN_MIN_WIDTH_EM` (`4em`); размеры и явно переданный minimum сохраняют до четырёх знаков после запятой:
917
+
918
+ ```ts
919
+ normalizeTableColumnWidth(12.345678, undefined, "em"); // 12.3456
920
+ normalizeTableColumnSizing({ name: 20.5 }, undefined, "em"); // { name: 20.5 }
921
+ patchTableColumnWidth({ name: 20.5 }, "amount", 10.25, undefined, "em");
922
+ // { name: 20.5, amount: 10.25 }
923
+ ```
924
+
925
+ ### `resolveTableColumnsWidth`
926
+
927
+ Суммирует определённые ширины видимых колонок в `em` и `px`, сохраняя CSS-единицы для SSR и масштабирования шрифта:
928
+
929
+ ```ts
930
+ resolveTableColumnsWidth(["20em", "10.5em"]); // "calc(20em + 10.5em)"
931
+ resolveTableColumnsWidth(["20em", "120px"]); // "calc(20em + 120px)"
932
+ resolveTableColumnsWidth(["auto", "20em"]); // undefined
933
+ ```
934
+
935
+ Пустой набор, проценты и неподдерживаемые значения возвращают `undefined`: для них общей шириной управляет браузер. Результат предназначен для `width` таблицы с `table-layout: fixed`.
913
936
 
914
937
  ### `DEFAULT_TABLE_COLUMN_MIN_WIDTH`
915
938
 
@@ -927,7 +950,7 @@ normalizeTableColumnWidth(12); // 60
927
950
  normalizeTableColumnWidth(Number.NaN, 80); // 80
928
951
  ```
929
952
 
930
- Алгоритм:
953
+ Алгоритм для единицы `px`:
931
954
 
932
955
  1. Проверяет `minWidth`.
933
956
  2. Если minimum не finite или не больше нуля, использует `60`.
@@ -2773,14 +2796,17 @@ it("не активирует строку по клику на кнопку", (
2773
2796
 
2774
2797
  ### Column sizing
2775
2798
 
2776
- | API | Вид | Назначение |
2777
- | -------------------------------- | -------- | -------------------------------------- |
2778
- | `TableColumnSizingState` | type | `Record<columnId, widthPx>` |
2779
- | `DEFAULT_TABLE_COLUMN_MIN_WIDTH` | constant | default minimum `60` px |
2780
- | `normalizeTableColumnWidth` | function | finite integer width не меньше minimum |
2781
- | `normalizeTableColumnSizing` | function | очищает весь sizing state |
2782
- | `patchTableColumnWidth` | function | immutable add/update одной ширины |
2783
- | `removeTableColumnWidth` | function | immutable delete одной ширины |
2799
+ | API | Вид | Назначение |
2800
+ | ----------------------------------- | -------- | --------------------------------------------- |
2801
+ | `TableColumnSizingState` | type | `Record<columnId, width>` в выбранной единице |
2802
+ | `TableColumnSizingUnit` | type | `"px"` или `"em"` |
2803
+ | `DEFAULT_TABLE_COLUMN_MIN_WIDTH_EM` | constant | default minimum `4em` |
2804
+ | `resolveTableColumnsWidth` | function | сумма определённых ширин колонок в CSS |
2805
+ | `DEFAULT_TABLE_COLUMN_MIN_WIDTH` | constant | default minimum `60` px |
2806
+ | `normalizeTableColumnWidth` | function | размер в выбранной единице не меньше minimum |
2807
+ | `normalizeTableColumnSizing` | function | очищает весь sizing state |
2808
+ | `patchTableColumnWidth` | function | immutable add/update одной ширины |
2809
+ | `removeTableColumnWidth` | function | immutable delete одной ширины |
2784
2810
 
2785
2811
  ### Row selection
2786
2812
 
@@ -2935,7 +2961,7 @@ const column = {
2935
2961
  };
2936
2962
  ```
2937
2963
 
2938
- Здесь `120em`, а не `120px`. Resize px храните в `TableColumnSizingState`.
2964
+ Здесь `120em`, а не `120px`. Размеры resize храните в `TableColumnSizingState`, сохраняя выбранную единицу.
2939
2965
 
2940
2966
  ### Считать `normalizeTableColumnOrder` полным restore
2941
2967