@evergis/react 4.0.145 → 4.0.147
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Dashboard/elements/ElementTable/components/TableColumnResizer.d.ts +3 -2
- package/dist/components/Dashboard/elements/ElementTable/hooks/useColumnResize.d.ts +11 -7
- package/dist/components/Dashboard/elements/ElementTable/hooks/useTableView.d.ts +1 -1
- package/dist/components/Dashboard/elements/ElementTable/styled.d.ts +9 -5
- package/dist/components/Dashboard/elements/ElementTable/types.d.ts +3 -2
- package/dist/components/Dashboard/elements/ElementTable/utils/columnStyle.d.ts +10 -8
- package/dist/index.js +110 -62
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +110 -62
- package/dist/react.esm.js.map +1 -1
- package/package.json +2 -2
package/dist/react.esm.js
CHANGED
|
@@ -8168,6 +8168,23 @@ const useProjectDashboardInit = () => {
|
|
|
8168
8168
|
}, [projectInfo, updateProject]);
|
|
8169
8169
|
};
|
|
8170
8170
|
|
|
8171
|
+
/**
|
|
8172
|
+
* Съесть клик, которым закончилось перетаскивание.
|
|
8173
|
+
*
|
|
8174
|
+
* Мышь отпускают уже за пределами ручки, поэтому браузер шлёт `click` не ей, а общему предку —
|
|
8175
|
+
* ячейке или заголовку. Без этого перетаскивание границы заканчивалось бы сортировкой таблицы
|
|
8176
|
+
* по колонке или сменой выделения в сетке.
|
|
8177
|
+
*/
|
|
8178
|
+
const swallowNextClick = () => {
|
|
8179
|
+
const swallow = (event) => {
|
|
8180
|
+
event.stopPropagation();
|
|
8181
|
+
event.preventDefault();
|
|
8182
|
+
};
|
|
8183
|
+
window.addEventListener("click", swallow, { capture: true, once: true });
|
|
8184
|
+
// Клика может и не быть — например, мышь отпустили за пределами окна. Тогда снимаем слушатель
|
|
8185
|
+
// сами, иначе он съел бы следующий, уже осмысленный клик.
|
|
8186
|
+
window.setTimeout(() => window.removeEventListener("click", swallow, { capture: true }), 0);
|
|
8187
|
+
};
|
|
8171
8188
|
/**
|
|
8172
8189
|
* Перетаскивание границы: подписка на ручку, снимок на старте, предпросмотр на движении,
|
|
8173
8190
|
* запись результата на отпускании.
|
|
@@ -8180,6 +8197,7 @@ const useResizeDrag = ({ onStart, onMove, onEnd }) => {
|
|
|
8180
8197
|
const [handle, setHandle] = useState(null);
|
|
8181
8198
|
const [dragging, setDragging] = useState(false);
|
|
8182
8199
|
const stateRef = useRef(null);
|
|
8200
|
+
const movedRef = useRef(false);
|
|
8183
8201
|
const mouseDown = useCallback((event) => {
|
|
8184
8202
|
const state = onStart(event);
|
|
8185
8203
|
if (state === null) {
|
|
@@ -8189,10 +8207,12 @@ const useResizeDrag = ({ onStart, onMove, onEnd }) => {
|
|
|
8189
8207
|
// над чем проходит курсор.
|
|
8190
8208
|
event.preventDefault();
|
|
8191
8209
|
stateRef.current = state;
|
|
8210
|
+
movedRef.current = false;
|
|
8192
8211
|
setDragging(true);
|
|
8193
8212
|
}, [onStart]);
|
|
8194
8213
|
const mouseMove = useCallback((event) => {
|
|
8195
8214
|
if (stateRef.current !== null) {
|
|
8215
|
+
movedRef.current = true;
|
|
8196
8216
|
onMove(stateRef.current, event);
|
|
8197
8217
|
}
|
|
8198
8218
|
}, [onMove]);
|
|
@@ -8203,6 +8223,9 @@ const useResizeDrag = ({ onStart, onMove, onEnd }) => {
|
|
|
8203
8223
|
}
|
|
8204
8224
|
stateRef.current = null;
|
|
8205
8225
|
setDragging(false);
|
|
8226
|
+
if (movedRef.current) {
|
|
8227
|
+
swallowNextClick();
|
|
8228
|
+
}
|
|
8206
8229
|
onEnd(state, event);
|
|
8207
8230
|
}, [onEnd]);
|
|
8208
8231
|
useDragAndDropEffect(handle, { mouseDown, mouseMove, mouseUp });
|
|
@@ -15529,14 +15552,26 @@ const TableHead = styled.thead.withConfig({ displayName: "TableHead", componentI
|
|
|
15529
15552
|
top: 0;
|
|
15530
15553
|
z-index: 1;
|
|
15531
15554
|
`;
|
|
15532
|
-
|
|
15555
|
+
/**
|
|
15556
|
+
* Содержимое заголовка: псевдоним и место под значок сортировки.
|
|
15557
|
+
*
|
|
15558
|
+
* Само по себе не сжимается и ничего не обрезает — иначе перестало бы задавать минимальную
|
|
15559
|
+
* ширину колонки, и раскладка считала бы её по одному лишь телу таблицы. Обрезку включает
|
|
15560
|
+
* заголовок, и только когда ширина колонки задана явно (см. `TableHeadCell`).
|
|
15561
|
+
*/
|
|
15562
|
+
const TableHeadContent = styled.span.withConfig({ displayName: "TableHeadContent", componentId: "sc-19t325s" }) `
|
|
15563
|
+
display: flex;
|
|
15564
|
+
align-items: center;
|
|
15565
|
+
gap: 0.25rem;
|
|
15566
|
+
`;
|
|
15567
|
+
const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", componentId: "sc-19bpg7s" }) `
|
|
15533
15568
|
/* Относительное позиционирование держит захват границы колонки. */
|
|
15534
15569
|
position: relative;
|
|
15570
|
+
box-sizing: border-box;
|
|
15535
15571
|
padding: 0.375rem 0.5rem;
|
|
15536
15572
|
text-align: left;
|
|
15537
15573
|
font-weight: 600;
|
|
15538
15574
|
white-space: nowrap;
|
|
15539
|
-
overflow: hidden;
|
|
15540
15575
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
15541
15576
|
/* Рамка принадлежит ячейке (рамки раздельные), поэтому едет вместе с липкой шапкой. */
|
|
15542
15577
|
border-bottom: 1px solid ${({ theme }) => theme.palette.elementDeep};
|
|
@@ -15546,18 +15581,22 @@ const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", compo
|
|
|
15546
15581
|
cursor: pointer;
|
|
15547
15582
|
user-select: none;
|
|
15548
15583
|
`}
|
|
15549
|
-
|
|
15550
|
-
|
|
15551
|
-
|
|
15552
|
-
|
|
15553
|
-
|
|
15554
|
-
|
|
15555
|
-
|
|
15556
|
-
|
|
15557
|
-
|
|
15558
|
-
|
|
15559
|
-
|
|
15560
|
-
|
|
15584
|
+
|
|
15585
|
+
/*
|
|
15586
|
+
* Обрезка только у колонки с заданной шириной: там длинный псевдоним иначе выдавил бы значок
|
|
15587
|
+
* сортировки за край. У колонки без ширины обрезать нечего — её ширину и задаёт заголовок,
|
|
15588
|
+
* а сжатое содержимое отдало бы этот расчёт телу таблицы, и заголовок схлопнулся бы в ноль.
|
|
15589
|
+
*/
|
|
15590
|
+
${({ $fixedWidth }) => $fixedWidth &&
|
|
15591
|
+
css `
|
|
15592
|
+
overflow: hidden;
|
|
15593
|
+
|
|
15594
|
+
${TableHeadContent} {
|
|
15595
|
+
min-width: 0;
|
|
15596
|
+
overflow: hidden;
|
|
15597
|
+
text-overflow: ellipsis;
|
|
15598
|
+
}
|
|
15599
|
+
`}
|
|
15561
15600
|
`;
|
|
15562
15601
|
/**
|
|
15563
15602
|
* Место под значок сортировки. Занято всегда, пока сортировка включена, а сам значок только
|
|
@@ -15587,6 +15626,10 @@ const TableRow = styled.tr.withConfig({ displayName: "TableRow", componentId: "s
|
|
|
15587
15626
|
}
|
|
15588
15627
|
`;
|
|
15589
15628
|
const TableCellWrapper = styled.td.withConfig({ displayName: "TableCellWrapper", componentId: "sc-ziu5rk" }) `
|
|
15629
|
+
/* Относительное позиционирование держит захват границы колонки. */
|
|
15630
|
+
position: relative;
|
|
15631
|
+
/* Как и у заголовка: ширина колонки считается по внешнему краю ячейки. */
|
|
15632
|
+
box-sizing: border-box;
|
|
15590
15633
|
padding: 0.125rem 0.25rem;
|
|
15591
15634
|
vertical-align: middle;
|
|
15592
15635
|
/* Предел снимает заданная ширина: с колонками по содержимому обрезать значение незачем. */
|
|
@@ -15926,30 +15969,30 @@ const TableCell = memo(({ attribute, row, canEdit, onChange }) => {
|
|
|
15926
15969
|
* Имя переменной ширины колонки.
|
|
15927
15970
|
*
|
|
15928
15971
|
* Через неё идёт и предпросмотр перетаскивания, и итоговая ширина: пока переменная не задана,
|
|
15929
|
-
* работает запасное
|
|
15930
|
-
*
|
|
15972
|
+
* работает запасное значение, а жест на время перетаскивания объявляет её на самой таблице —
|
|
15973
|
+
* одним свойством на один узел, как сетка меняет свой шаблон треков.
|
|
15931
15974
|
*/
|
|
15932
15975
|
const getColumnWidthVariable = (index) => `--table-col-${index}`;
|
|
15933
15976
|
/**
|
|
15934
|
-
* Инлайн-размер ячейки
|
|
15977
|
+
* Инлайн-размер ячейки колонки.
|
|
15935
15978
|
*
|
|
15936
|
-
*
|
|
15937
|
-
*
|
|
15938
|
-
*
|
|
15979
|
+
* Ставится всем колонкам, а не только тем, у кого ширина задана: жест фиксирует на время
|
|
15980
|
+
* перетаскивания ВСЕ колонки, иначе соседние перераспределялись бы на первом же шаге и таблицу
|
|
15981
|
+
* дёргало бы. Пока переменной нет, каждый предел падает на своё запасное значение и колонка
|
|
15982
|
+
* ведёт себя ровно так, как вела бы без инлайн-стиля вовсе.
|
|
15939
15983
|
*
|
|
15940
|
-
*
|
|
15984
|
+
* Раскладка таблицы автоматическая (ширину колонок выбирает содержимое), и одной `width` ей мало —
|
|
15985
|
+
* она для неё лишь пожелание. Жёстко колонку держат все три предела сразу.
|
|
15941
15986
|
*/
|
|
15942
|
-
const getColumnStyle = (index, width,
|
|
15943
|
-
if (width == null && !resizable) {
|
|
15944
|
-
return undefined;
|
|
15945
|
-
}
|
|
15987
|
+
const getColumnStyle = (index, width, isHead) => {
|
|
15946
15988
|
const variable = getColumnWidthVariable(index);
|
|
15947
15989
|
const fixed = width == null ? null : `${width}px`;
|
|
15948
15990
|
return {
|
|
15949
15991
|
width: `var(${variable}, ${fixed ?? "auto"})`,
|
|
15950
15992
|
minWidth: `var(${variable}, ${fixed ?? "0"})`,
|
|
15951
|
-
// Без заданной ширины предел остаётся
|
|
15952
|
-
|
|
15993
|
+
// Без заданной ширины предел остаётся тем, что задан стилем: у ячейки тела — общий предел
|
|
15994
|
+
// таблицы, у заголовка его нет вовсе.
|
|
15995
|
+
maxWidth: `var(${variable}, ${fixed ?? (isHead ? "none" : "var(--table-cell-max-width, 20rem)")})`,
|
|
15953
15996
|
};
|
|
15954
15997
|
};
|
|
15955
15998
|
|
|
@@ -15957,52 +16000,55 @@ const getColumnStyle = (index, width, resizable) => {
|
|
|
15957
16000
|
* Перетаскивание правой границы колонки.
|
|
15958
16001
|
*
|
|
15959
16002
|
* Жест — общий {@link useResizeDrag}, тот же, что двигает границы ячеек сетки дашборда. Здесь
|
|
15960
|
-
* остаётся только табличное: во время жеста
|
|
15961
|
-
* состояние
|
|
15962
|
-
* а не перерисовывает таблицу целиком.
|
|
16003
|
+
* остаётся только табличное: во время жеста ширины рисуются переменными на самой таблице, а в
|
|
16004
|
+
* состояние уходят один раз, на отпускание мыши.
|
|
15963
16005
|
*
|
|
15964
|
-
*
|
|
15965
|
-
*
|
|
16006
|
+
* Снимок берётся по ВСЕМ колонкам, и все они на время жеста фиксируются — так же, как сетка
|
|
16007
|
+
* фиксирует все треки. Иначе автоматическая раскладка перераспределяла бы соседние колонки на
|
|
16008
|
+
* первом же шаге, и таблицу дёргало бы в самом начале перетаскивания. По той же причине в
|
|
16009
|
+
* состояние уходят ширины всех колонок: без этого соседи прыгнули бы обратно на отпускании.
|
|
16010
|
+
*
|
|
16011
|
+
* Ширины снимаются с ячеек шапки: колонка одна на всю таблицу, а строк в ней сколько угодно.
|
|
15966
16012
|
*/
|
|
15967
|
-
const useColumnResize = ({ index,
|
|
15968
|
-
const variable = getColumnWidthVariable(index);
|
|
16013
|
+
const useColumnResize = ({ index, onResize }) => {
|
|
15969
16014
|
const onStart = useCallback((event) => {
|
|
15970
|
-
// Обработчик нажатия висит на самой ручке, поэтому
|
|
15971
|
-
//
|
|
15972
|
-
const
|
|
15973
|
-
|
|
16015
|
+
// Обработчик нажатия висит на самой ручке, поэтому таблица достаётся отсюда — отдельный
|
|
16016
|
+
// ref на неё не нужен.
|
|
16017
|
+
const table = event.currentTarget?.closest("table");
|
|
16018
|
+
const head = table?.querySelector("thead tr");
|
|
16019
|
+
if (!head) {
|
|
15974
16020
|
return null;
|
|
15975
16021
|
}
|
|
15976
|
-
|
|
15977
|
-
|
|
15978
|
-
|
|
15979
|
-
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
const
|
|
15983
|
-
const onMove = useCallback((state, event) => state.table?.style.setProperty(variable, `${getNextWidth(state, event)}px`), [getNextWidth, variable]);
|
|
16022
|
+
const widths = Array.from(head.children).map(cell => cell.getBoundingClientRect().width);
|
|
16023
|
+
return widths[index] === undefined ? null : { start: event.clientX, widths, table };
|
|
16024
|
+
}, [index]);
|
|
16025
|
+
const getNextWidths = useCallback((state, event) => state.widths.map((width, position) => position === index
|
|
16026
|
+
? Math.max(MIN_COLUMN_WIDTH, Math.round(width + event.clientX - state.start))
|
|
16027
|
+
: Math.round(width)), [index]);
|
|
16028
|
+
const onMove = useCallback((state, event) => getNextWidths(state, event).forEach((width, position) => state.table?.style.setProperty(getColumnWidthVariable(position), `${width}px`)), [getNextWidths]);
|
|
15984
16029
|
const onEnd = useCallback((state, event) => {
|
|
15985
|
-
state.table?.style.removeProperty(
|
|
15986
|
-
const
|
|
16030
|
+
state.widths.forEach((_width, position) => state.table?.style.removeProperty(getColumnWidthVariable(position)));
|
|
16031
|
+
const widths = getNextWidths(state, event);
|
|
15987
16032
|
// Клик по границе без перетаскивания ширину менять не должен.
|
|
15988
|
-
if (
|
|
16033
|
+
if (widths[index] === Math.round(state.widths[index])) {
|
|
15989
16034
|
return;
|
|
15990
16035
|
}
|
|
15991
|
-
|
|
15992
|
-
}, [
|
|
16036
|
+
onResize(widths);
|
|
16037
|
+
}, [getNextWidths, index, onResize]);
|
|
15993
16038
|
return useResizeDrag({ onStart, onMove, onEnd });
|
|
15994
16039
|
};
|
|
15995
16040
|
|
|
15996
16041
|
/**
|
|
15997
|
-
* Ручка ширины колонки на правой границе
|
|
16042
|
+
* Ручка ширины колонки на правой границе ячейки.
|
|
15998
16043
|
*
|
|
15999
16044
|
* Тот же компонент и тот же жест, что двигают границы ячеек сетки дашборда: пользователю это одно
|
|
16000
|
-
* и то же действие, и выглядеть оно обязано одинаково.
|
|
16045
|
+
* и то же действие, и выглядеть оно обязано одинаково. Поэтому и стоит она у КАЖДОЙ ячейки
|
|
16046
|
+
* колонки, как в сетке, — тянуть границу можно на любой строке, а не только в шапке.
|
|
16001
16047
|
*/
|
|
16002
|
-
const TableColumnResizer = memo(({ index,
|
|
16003
|
-
const { setHandle, dragging } = useColumnResize({ index,
|
|
16004
|
-
// Ручка лежит внутри
|
|
16005
|
-
// кликом по
|
|
16048
|
+
const TableColumnResizer = memo(({ index, onResize }) => {
|
|
16049
|
+
const { setHandle, dragging } = useColumnResize({ index, onResize });
|
|
16050
|
+
// Ручка лежит внутри ячейки, и без остановки всплытия перетаскивание границы заканчивалось бы
|
|
16051
|
+
// кликом по ней — то есть переключало бы сортировку в шапке и открывало бы правку в теле.
|
|
16006
16052
|
const stopPropagation = useCallback((event) => event.stopPropagation(), []);
|
|
16007
16053
|
return jsx(ResizeHandle, { ref: setHandle, "$axis": "column", "data-dragging": dragging, onClick: stopPropagation });
|
|
16008
16054
|
});
|
|
@@ -16015,7 +16061,7 @@ const TableColumnResizer = memo(({ index, onCommit }) => {
|
|
|
16015
16061
|
*/
|
|
16016
16062
|
const TableHeadRow = ({ columns, sort, sortEnabled, columnWidths, withActionsColumn, onSortToggle, onColumnResize, }) => (jsxs("tr", { children: [columns.map(({ attributeName, alias, description, resizable }, index) => {
|
|
16017
16063
|
const sorted = sort?.attributeName === attributeName;
|
|
16018
|
-
return (jsxs(TableHeadCell, { title: description || alias, style: getColumnStyle(index, columnWidths[attributeName],
|
|
16064
|
+
return (jsxs(TableHeadCell, { title: description || alias, style: getColumnStyle(index, columnWidths[attributeName], true), "$sortable": sortEnabled, "$fixedWidth": columnWidths[attributeName] != null, onClick: sortEnabled ? () => onSortToggle(attributeName) : undefined, children: [jsxs(TableHeadContent, { children: [alias, sortEnabled && (jsx(TableSortSlot, { "$active": sorted, children: jsx(Icon, { kind: sorted && sort?.direction === "desc" ? "sorting_des" : "sorting_asc" }) }))] }), resizable && jsx(TableColumnResizer, { index: index, onResize: onColumnResize })] }, attributeName));
|
|
16019
16065
|
}), withActionsColumn && jsx(TableHeadCell, {})] }));
|
|
16020
16066
|
|
|
16021
16067
|
const ContainerLoading = () => (jsx(Flex, { alignContent: "center", justifyContent: "center", width: "100%", children: jsx(CircularProgress, { diameter: 1.5, mono: true }) }));
|
|
@@ -16150,7 +16196,9 @@ const useTableView = (elementConfig) => {
|
|
|
16150
16196
|
// Растянутая мышью ширина живёт только в рантайме и перебивает конфигурационную: последнее
|
|
16151
16197
|
// слово за тем, кто тянул. Обратно в конфиг она не пишется.
|
|
16152
16198
|
const columnWidths = useMemo(() => columns.reduce((acc, attribute) => ({ ...acc, [attribute.attributeName]: widths[attribute.attributeName] ?? attribute.width }), {}), [columns, widths]);
|
|
16153
|
-
|
|
16199
|
+
// Жест отдаёт ширины всех колонок разом: соседние он тоже фиксировал, и вернуть их к
|
|
16200
|
+
// автоподбору значило бы дёрнуть таблицу сразу после отпускания.
|
|
16201
|
+
const onColumnResize = useCallback((next) => setWidths(columns.reduce((acc, { attributeName }, position) => next[position] === undefined ? acc : { ...acc, [attributeName]: next[position] }, {})), [columns]);
|
|
16154
16202
|
const onSortToggle = useCallback((attributeName) => setSort(current => getNextSort(current, attributeName)), []);
|
|
16155
16203
|
return {
|
|
16156
16204
|
context,
|
|
@@ -16191,13 +16239,13 @@ const ElementTable = memo(({ elementConfig }) => {
|
|
|
16191
16239
|
defaultValue: "Схема данных не задана",
|
|
16192
16240
|
}) }));
|
|
16193
16241
|
}
|
|
16194
|
-
return (jsx(TableBox, { "$sizeCss": sizeCss, children: jsxs(TableWrapper, { ref: setTable, "$contentWidth": contentWidth, children: [jsx(TableHead, { children: jsx(TableHeadRow, { columns: columns, sort: sort, sortEnabled: sortEnabled, columnWidths: columnWidths, withActionsColumn: context.canDelete, onSortToggle: onSortToggle, onColumnResize: onColumnResize }) }), jsx(TableBody, { children: rows.map(row => (jsxs(TableRow, { children: [columns.map((attribute, columnIndex) => (
|
|
16242
|
+
return (jsx(TableBox, { "$sizeCss": sizeCss, children: jsxs(TableWrapper, { ref: setTable, "$contentWidth": contentWidth, children: [jsx(TableHead, { children: jsx(TableHeadRow, { columns: columns, sort: sort, sortEnabled: sortEnabled, columnWidths: columnWidths, withActionsColumn: context.canDelete, onSortToggle: onSortToggle, onColumnResize: onColumnResize }) }), jsx(TableBody, { children: rows.map(row => (jsxs(TableRow, { children: [columns.map((attribute, columnIndex) => (jsxs(TableCellWrapper, {
|
|
16195
16243
|
// Стиль колонки из конфига идёт последним: шрифт задан для значений, и ширину
|
|
16196
16244
|
// он не трогает — своих размеров у него нет.
|
|
16197
16245
|
style: {
|
|
16198
|
-
...getColumnStyle(columnIndex, columnWidths[attribute.attributeName]
|
|
16246
|
+
...getColumnStyle(columnIndex, columnWidths[attribute.attributeName]),
|
|
16199
16247
|
...attribute.style,
|
|
16200
|
-
}, children: jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }) }, attribute.attributeName))), context.canDelete && (jsx(TableActionsCell, { children: jsx(IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }) }));
|
|
16248
|
+
}, children: [jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }), attribute.resizable && (jsx(TableColumnResizer, { index: columnIndex, onResize: onColumnResize }))] }, attribute.attributeName))), context.canDelete && (jsx(TableActionsCell, { children: jsx(IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }) }));
|
|
16201
16249
|
});
|
|
16202
16250
|
|
|
16203
16251
|
const TooltipIcon = styled(Icon).withConfig({ displayName: "TooltipIcon", componentId: "sc-1lkxudm" }) `
|