@evergis/react 4.0.146 → 4.0.148

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.
@@ -2,18 +2,22 @@ import { ResizeDrag } from '../../../hooks/useResizeDrag';
2
2
  interface UseColumnResizeParams {
3
3
  /** Позиция колонки: по ней собрано имя переменной, которой колонка задаёт свою ширину. */
4
4
  index: number;
5
- onCommit: (width: number) => void;
5
+ /** Итог жеста ширины ВСЕХ колонок по их позициям. */
6
+ onResize: (widths: number[]) => void;
6
7
  }
7
8
  /**
8
9
  * Перетаскивание правой границы колонки.
9
10
  *
10
11
  * Жест — общий {@link useResizeDrag}, тот же, что двигает границы ячеек сетки дашборда. Здесь
11
- * остаётся только табличное: во время жеста ширина рисуется переменной на самой таблице, а в
12
- * состояние уходит один раз, на отпускание мыши. Так шаг жеста меняет одно свойство одного узла,
13
- * а не перерисовывает таблицу целиком.
12
+ * остаётся только табличное: во время жеста ширины рисуются переменными на самой таблице, а в
13
+ * состояние уходят один раз, на отпускание мыши.
14
14
  *
15
- * Стартовая ширина берётся с той ячейки, за границу которой потянули: у колонки без `width` её
16
- * выбрала раскладка таблицы, и тянуть надо от того, что видно.
15
+ * Снимок берётся по ВСЕМ колонкам, и все они на время жеста фиксируются так же, как сетка
16
+ * фиксирует все треки. Иначе автоматическая раскладка перераспределяла бы соседние колонки на
17
+ * первом же шаге, и таблицу дёргало бы в самом начале перетаскивания. По той же причине в
18
+ * состояние уходят ширины всех колонок: без этого соседи прыгнули бы обратно на отпускании.
19
+ *
20
+ * Ширины снимаются с ячеек шапки: колонка одна на всю таблицу, а строк в ней сколько угодно.
17
21
  */
18
- export declare const useColumnResize: ({ index, onCommit }: UseColumnResizeParams) => ResizeDrag;
22
+ export declare const useColumnResize: ({ index, onResize }: UseColumnResizeParams) => ResizeDrag;
19
23
  export {};
@@ -26,5 +26,5 @@ export declare const useTableView: (elementConfig?: ElementTableConfig) => {
26
26
  contentWidth: boolean;
27
27
  columnWidths: Record<string, number>;
28
28
  onSortToggle: (attributeName: string) => void;
29
- onColumnResize: (attributeName: string, nextWidth: number) => void;
29
+ onColumnResize: (next: number[]) => void;
30
30
  };
@@ -21,8 +21,8 @@ export interface TableCellProps {
21
21
  export interface TableColumnResizerProps {
22
22
  /** Позиция колонки: по ней собрано имя переменной, которой колонка задаёт свою ширину. */
23
23
  index: number;
24
- attributeName: string;
25
- onResize: (attributeName: string, width: number) => void;
24
+ /** Итог жеста — ширины всех колонок по их позициям. */
25
+ onResize: (widths: number[]) => void;
26
26
  }
27
27
  export interface TableHeadRowProps {
28
28
  columns: StructuredDataAttribute[];
@@ -33,5 +33,5 @@ export interface TableHeadRowProps {
33
33
  /** У таблицы есть колонка действий — шапке нужна пустая ячейка над ней. */
34
34
  withActionsColumn: boolean;
35
35
  onSortToggle: (attributeName: string) => void;
36
- onColumnResize: (attributeName: string, width: number) => void;
36
+ onColumnResize: (widths: number[]) => void;
37
37
  }
@@ -3,17 +3,19 @@ import { CSSProperties } from 'react';
3
3
  * Имя переменной ширины колонки.
4
4
  *
5
5
  * Через неё идёт и предпросмотр перетаскивания, и итоговая ширина: пока переменная не задана,
6
- * работает запасное значение из стиля ячейки, а жест на время перетаскивания объявляет её на
7
- * самой таблице — одним свойством на один узел, как сетка меняет свой шаблон треков.
6
+ * работает запасное значение, а жест на время перетаскивания объявляет её на самой таблице —
7
+ * одним свойством на один узел, как сетка меняет свой шаблон треков.
8
8
  */
9
9
  export declare const getColumnWidthVariable: (index: number) => string;
10
10
  /**
11
- * Инлайн-размер ячейки колонки с заданной или изменяемой шириной.
11
+ * Инлайн-размер ячейки колонки.
12
12
  *
13
- * Раскладка таблицы автоматическая (ширину колонок выбирает содержимое), и одной `width` ей мало
14
- * она для неё лишь пожелание. Жёстко колонку держат все три предела сразу, поэтому и ставим их
15
- * втроём, на каждую ячейку колонки.
13
+ * Ставится всем колонкам, а не только тем, у кого ширина задана: жест фиксирует на время
14
+ * перетаскивания ВСЕ колонки, иначе соседние перераспределялись бы на первом же шаге и таблицу
15
+ * дёргало бы. Пока переменной нет, каждый предел падает на своё запасное значение и колонка
16
+ * ведёт себя ровно так, как вела бы без инлайн-стиля вовсе.
16
17
  *
17
- * Ни ширины, ни разрешения тянуть стиля нет: колонка остаётся на попечении раскладки, как и была.
18
+ * Раскладка таблицы автоматическая (ширину колонок выбирает содержимое), и одной `width` ей мало
19
+ * она для неё лишь пожелание. Жёстко колонку держат все три предела сразу.
18
20
  */
19
- export declare const getColumnStyle: (index: number, width?: number, resizable?: boolean) => CSSProperties | undefined;
21
+ export declare const getColumnStyle: (index: number, width?: number, isHead?: boolean) => CSSProperties;
package/dist/index.js CHANGED
@@ -15956,30 +15956,30 @@ const TableCell = React.memo(({ attribute, row, canEdit, onChange }) => {
15956
15956
  * Имя переменной ширины колонки.
15957
15957
  *
15958
15958
  * Через неё идёт и предпросмотр перетаскивания, и итоговая ширина: пока переменная не задана,
15959
- * работает запасное значение из стиля ячейки, а жест на время перетаскивания объявляет её на
15960
- * самой таблице — одним свойством на один узел, как сетка меняет свой шаблон треков.
15959
+ * работает запасное значение, а жест на время перетаскивания объявляет её на самой таблице —
15960
+ * одним свойством на один узел, как сетка меняет свой шаблон треков.
15961
15961
  */
15962
15962
  const getColumnWidthVariable = (index) => `--table-col-${index}`;
15963
15963
  /**
15964
- * Инлайн-размер ячейки колонки с заданной или изменяемой шириной.
15964
+ * Инлайн-размер ячейки колонки.
15965
15965
  *
15966
- * Раскладка таблицы автоматическая (ширину колонок выбирает содержимое), и одной `width` ей мало
15967
- * она для неё лишь пожелание. Жёстко колонку держат все три предела сразу, поэтому и ставим их
15968
- * втроём, на каждую ячейку колонки.
15966
+ * Ставится всем колонкам, а не только тем, у кого ширина задана: жест фиксирует на время
15967
+ * перетаскивания ВСЕ колонки, иначе соседние перераспределялись бы на первом же шаге и таблицу
15968
+ * дёргало бы. Пока переменной нет, каждый предел падает на своё запасное значение и колонка
15969
+ * ведёт себя ровно так, как вела бы без инлайн-стиля вовсе.
15969
15970
  *
15970
- * Ни ширины, ни разрешения тянуть стиля нет: колонка остаётся на попечении раскладки, как и была.
15971
+ * Раскладка таблицы автоматическая (ширину колонок выбирает содержимое), и одной `width` ей мало
15972
+ * она для неё лишь пожелание. Жёстко колонку держат все три предела сразу.
15971
15973
  */
15972
- const getColumnStyle = (index, width, resizable) => {
15973
- if (width == null && !resizable) {
15974
- return undefined;
15975
- }
15974
+ const getColumnStyle = (index, width, isHead) => {
15976
15975
  const variable = getColumnWidthVariable(index);
15977
15976
  const fixed = width == null ? null : `${width}px`;
15978
15977
  return {
15979
15978
  width: `var(${variable}, ${fixed ?? "auto"})`,
15980
15979
  minWidth: `var(${variable}, ${fixed ?? "0"})`,
15981
- // Без заданной ширины предел остаётся общим для всех ячеек тем, что задан стилем таблицы.
15982
- maxWidth: `var(${variable}, ${fixed ?? "var(--table-cell-max-width, 20rem)"})`,
15980
+ // Без заданной ширины предел остаётся тем, что задан стилем: у ячейки тела общий предел
15981
+ // таблицы, у заголовка его нет вовсе.
15982
+ maxWidth: `var(${variable}, ${fixed ?? (isHead ? "none" : "var(--table-cell-max-width, 20rem)")})`,
15983
15983
  };
15984
15984
  };
15985
15985
 
@@ -15987,39 +15987,41 @@ const getColumnStyle = (index, width, resizable) => {
15987
15987
  * Перетаскивание правой границы колонки.
15988
15988
  *
15989
15989
  * Жест — общий {@link useResizeDrag}, тот же, что двигает границы ячеек сетки дашборда. Здесь
15990
- * остаётся только табличное: во время жеста ширина рисуется переменной на самой таблице, а в
15991
- * состояние уходит один раз, на отпускание мыши. Так шаг жеста меняет одно свойство одного узла,
15992
- * а не перерисовывает таблицу целиком.
15990
+ * остаётся только табличное: во время жеста ширины рисуются переменными на самой таблице, а в
15991
+ * состояние уходят один раз, на отпускание мыши.
15992
+ *
15993
+ * Снимок берётся по ВСЕМ колонкам, и все они на время жеста фиксируются — так же, как сетка
15994
+ * фиксирует все треки. Иначе автоматическая раскладка перераспределяла бы соседние колонки на
15995
+ * первом же шаге, и таблицу дёргало бы в самом начале перетаскивания. По той же причине в
15996
+ * состояние уходят ширины всех колонок: без этого соседи прыгнули бы обратно на отпускании.
15993
15997
  *
15994
- * Стартовая ширина берётся с той ячейки, за границу которой потянули: у колонки без `width` её
15995
- * выбрала раскладка таблицы, и тянуть надо от того, что видно.
15998
+ * Ширины снимаются с ячеек шапки: колонка одна на всю таблицу, а строк в ней сколько угодно.
15996
15999
  */
15997
- const useColumnResize = ({ index, onCommit }) => {
15998
- const variable = getColumnWidthVariable(index);
16000
+ const useColumnResize = ({ index, onResize }) => {
15999
16001
  const onStart = React.useCallback((event) => {
16000
- // Обработчик нажатия висит на самой ручке, поэтому её ячейка и таблица достаются отсюда —
16001
- // отдельный ref на них не нужен. Ячейка любая: ручки стоят и в шапке, и в каждой строке.
16002
- const cell = event.currentTarget?.closest("th, td");
16003
- if (!cell) {
16002
+ // Обработчик нажатия висит на самой ручке, поэтому таблица достаётся отсюда — отдельный
16003
+ // ref на неё не нужен.
16004
+ const table = event.currentTarget?.closest("table");
16005
+ const head = table?.querySelector("thead tr");
16006
+ if (!head) {
16004
16007
  return null;
16005
16008
  }
16006
- return {
16007
- start: event.clientX,
16008
- width: cell.getBoundingClientRect().width,
16009
- table: cell.closest("table"),
16010
- };
16011
- }, []);
16012
- const getNextWidth = React.useCallback((state, event) => Math.max(MIN_COLUMN_WIDTH, Math.round(state.width + event.clientX - state.start)), []);
16013
- const onMove = React.useCallback((state, event) => state.table?.style.setProperty(variable, `${getNextWidth(state, event)}px`), [getNextWidth, variable]);
16009
+ const widths = Array.from(head.children).map(cell => cell.getBoundingClientRect().width);
16010
+ return widths[index] === undefined ? null : { start: event.clientX, widths, table };
16011
+ }, [index]);
16012
+ const getNextWidths = React.useCallback((state, event) => state.widths.map((width, position) => position === index
16013
+ ? Math.max(MIN_COLUMN_WIDTH, Math.round(width + event.clientX - state.start))
16014
+ : Math.round(width)), [index]);
16015
+ const onMove = React.useCallback((state, event) => getNextWidths(state, event).forEach((width, position) => state.table?.style.setProperty(getColumnWidthVariable(position), `${width}px`)), [getNextWidths]);
16014
16016
  const onEnd = React.useCallback((state, event) => {
16015
- state.table?.style.removeProperty(variable);
16016
- const next = getNextWidth(state, event);
16017
+ state.widths.forEach((_width, position) => state.table?.style.removeProperty(getColumnWidthVariable(position)));
16018
+ const widths = getNextWidths(state, event);
16017
16019
  // Клик по границе без перетаскивания ширину менять не должен.
16018
- if (next === Math.round(state.width)) {
16020
+ if (widths[index] === Math.round(state.widths[index])) {
16019
16021
  return;
16020
16022
  }
16021
- onCommit(next);
16022
- }, [getNextWidth, onCommit, variable]);
16023
+ onResize(widths);
16024
+ }, [getNextWidths, index, onResize]);
16023
16025
  return useResizeDrag({ onStart, onMove, onEnd });
16024
16026
  };
16025
16027
 
@@ -16030,9 +16032,8 @@ const useColumnResize = ({ index, onCommit }) => {
16030
16032
  * и то же действие, и выглядеть оно обязано одинаково. Поэтому и стоит она у КАЖДОЙ ячейки
16031
16033
  * колонки, как в сетке, — тянуть границу можно на любой строке, а не только в шапке.
16032
16034
  */
16033
- const TableColumnResizer = React.memo(({ index, attributeName, onResize }) => {
16034
- const onCommit = React.useCallback((width) => onResize(attributeName, width), [attributeName, onResize]);
16035
- const { setHandle, dragging } = useColumnResize({ index, onCommit });
16035
+ const TableColumnResizer = React.memo(({ index, onResize }) => {
16036
+ const { setHandle, dragging } = useColumnResize({ index, onResize });
16036
16037
  // Ручка лежит внутри ячейки, и без остановки всплытия перетаскивание границы заканчивалось бы
16037
16038
  // кликом по ней — то есть переключало бы сортировку в шапке и открывало бы правку в теле.
16038
16039
  const stopPropagation = React.useCallback((event) => event.stopPropagation(), []);
@@ -16047,7 +16048,7 @@ const TableColumnResizer = React.memo(({ index, attributeName, onResize }) => {
16047
16048
  */
16048
16049
  const TableHeadRow = ({ columns, sort, sortEnabled, columnWidths, withActionsColumn, onSortToggle, onColumnResize, }) => (jsxRuntime.jsxs("tr", { children: [columns.map(({ attributeName, alias, description, resizable }, index) => {
16049
16050
  const sorted = sort?.attributeName === attributeName;
16050
- return (jsxRuntime.jsxs(TableHeadCell, { title: description || alias, style: getColumnStyle(index, columnWidths[attributeName], resizable), "$sortable": sortEnabled, onClick: sortEnabled ? () => onSortToggle(attributeName) : undefined, children: [jsxRuntime.jsxs(TableHeadContent, { children: [alias, sortEnabled && (jsxRuntime.jsx(TableSortSlot, { "$active": sorted, children: jsxRuntime.jsx(uilibGl.Icon, { kind: sorted && sort?.direction === "desc" ? "sorting_des" : "sorting_asc" }) }))] }), resizable && jsxRuntime.jsx(TableColumnResizer, { index: index, attributeName: attributeName, onResize: onColumnResize })] }, attributeName));
16051
+ return (jsxRuntime.jsxs(TableHeadCell, { title: description || alias, style: getColumnStyle(index, columnWidths[attributeName], true), "$sortable": sortEnabled, onClick: sortEnabled ? () => onSortToggle(attributeName) : undefined, children: [jsxRuntime.jsxs(TableHeadContent, { children: [alias, sortEnabled && (jsxRuntime.jsx(TableSortSlot, { "$active": sorted, children: jsxRuntime.jsx(uilibGl.Icon, { kind: sorted && sort?.direction === "desc" ? "sorting_des" : "sorting_asc" }) }))] }), resizable && jsxRuntime.jsx(TableColumnResizer, { index: index, onResize: onColumnResize })] }, attributeName));
16051
16052
  }), withActionsColumn && jsxRuntime.jsx(TableHeadCell, {})] }));
16052
16053
 
16053
16054
  const ContainerLoading = () => (jsxRuntime.jsx(uilibGl.Flex, { alignContent: "center", justifyContent: "center", width: "100%", children: jsxRuntime.jsx(uilibGl.CircularProgress, { diameter: 1.5, mono: true }) }));
@@ -16182,7 +16183,9 @@ const useTableView = (elementConfig) => {
16182
16183
  // Растянутая мышью ширина живёт только в рантайме и перебивает конфигурационную: последнее
16183
16184
  // слово за тем, кто тянул. Обратно в конфиг она не пишется.
16184
16185
  const columnWidths = React.useMemo(() => columns.reduce((acc, attribute) => ({ ...acc, [attribute.attributeName]: widths[attribute.attributeName] ?? attribute.width }), {}), [columns, widths]);
16185
- const onColumnResize = React.useCallback((attributeName, nextWidth) => setWidths(current => ({ ...current, [attributeName]: nextWidth })), []);
16186
+ // Жест отдаёт ширины всех колонок разом: соседние он тоже фиксировал, и вернуть их к
16187
+ // автоподбору значило бы дёрнуть таблицу сразу после отпускания.
16188
+ const onColumnResize = React.useCallback((next) => setWidths(columns.reduce((acc, { attributeName }, position) => next[position] === undefined ? acc : { ...acc, [attributeName]: next[position] }, {})), [columns]);
16186
16189
  const onSortToggle = React.useCallback((attributeName) => setSort(current => getNextSort(current, attributeName)), []);
16187
16190
  return {
16188
16191
  context,
@@ -16227,9 +16230,9 @@ const ElementTable = React.memo(({ elementConfig }) => {
16227
16230
  // Стиль колонки из конфига идёт последним: шрифт задан для значений, и ширину
16228
16231
  // он не трогает — своих размеров у него нет.
16229
16232
  style: {
16230
- ...getColumnStyle(columnIndex, columnWidths[attribute.attributeName], attribute.resizable),
16233
+ ...getColumnStyle(columnIndex, columnWidths[attribute.attributeName]),
16231
16234
  ...attribute.style,
16232
- }, children: [jsxRuntime.jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }), attribute.resizable && (jsxRuntime.jsx(TableColumnResizer, { index: columnIndex, attributeName: attribute.attributeName, onResize: onColumnResize }))] }, attribute.attributeName))), context.canDelete && (jsxRuntime.jsx(TableActionsCell, { children: jsxRuntime.jsx(uilibGl.IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }) }));
16235
+ }, children: [jsxRuntime.jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }), attribute.resizable && (jsxRuntime.jsx(TableColumnResizer, { index: columnIndex, onResize: onColumnResize }))] }, attribute.attributeName))), context.canDelete && (jsxRuntime.jsx(TableActionsCell, { children: jsxRuntime.jsx(uilibGl.IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }) }));
16233
16236
  });
16234
16237
 
16235
16238
  const TooltipIcon = styled(uilibGl.Icon).withConfig({ displayName: "TooltipIcon", componentId: "sc-1lkxudm" }) `