@evergis/react 4.0.144 → 4.0.146
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/components/ResizeHandle/constants.d.ts +15 -0
- package/dist/components/Dashboard/components/ResizeHandle/index.d.ts +3 -0
- package/dist/components/Dashboard/components/ResizeHandle/styled.d.ts +17 -0
- package/dist/components/Dashboard/components/ResizeHandle/types.d.ts +2 -0
- package/dist/components/Dashboard/components/index.d.ts +1 -0
- package/dist/components/Dashboard/elements/ElementTable/components/TableColumnResizer.d.ts +10 -0
- package/dist/components/Dashboard/elements/ElementTable/hooks/useColumnResize.d.ts +15 -16
- package/dist/components/Dashboard/elements/ElementTable/hooks/useTableView.d.ts +3 -5
- package/dist/components/Dashboard/elements/ElementTable/styled.d.ts +0 -7
- package/dist/components/Dashboard/elements/ElementTable/types.d.ts +7 -4
- package/dist/components/Dashboard/elements/ElementTable/utils/columnStyle.d.ts +11 -3
- package/dist/components/Dashboard/grid/constants.d.ts +0 -14
- package/dist/components/Dashboard/grid/hooks/useGridHeightResize.d.ts +2 -2
- package/dist/components/Dashboard/grid/hooks/useGridResize.d.ts +6 -10
- package/dist/components/Dashboard/hooks/index.d.ts +1 -0
- package/dist/components/Dashboard/hooks/useResizeDrag.d.ts +29 -0
- package/dist/index.js +291 -222
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +290 -222
- package/dist/react.esm.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -8170,6 +8170,70 @@ const useProjectDashboardInit = () => {
|
|
|
8170
8170
|
}, [projectInfo, updateProject]);
|
|
8171
8171
|
};
|
|
8172
8172
|
|
|
8173
|
+
/**
|
|
8174
|
+
* Съесть клик, которым закончилось перетаскивание.
|
|
8175
|
+
*
|
|
8176
|
+
* Мышь отпускают уже за пределами ручки, поэтому браузер шлёт `click` не ей, а общему предку —
|
|
8177
|
+
* ячейке или заголовку. Без этого перетаскивание границы заканчивалось бы сортировкой таблицы
|
|
8178
|
+
* по колонке или сменой выделения в сетке.
|
|
8179
|
+
*/
|
|
8180
|
+
const swallowNextClick = () => {
|
|
8181
|
+
const swallow = (event) => {
|
|
8182
|
+
event.stopPropagation();
|
|
8183
|
+
event.preventDefault();
|
|
8184
|
+
};
|
|
8185
|
+
window.addEventListener("click", swallow, { capture: true, once: true });
|
|
8186
|
+
// Клика может и не быть — например, мышь отпустили за пределами окна. Тогда снимаем слушатель
|
|
8187
|
+
// сами, иначе он съел бы следующий, уже осмысленный клик.
|
|
8188
|
+
window.setTimeout(() => window.removeEventListener("click", swallow, { capture: true }), 0);
|
|
8189
|
+
};
|
|
8190
|
+
/**
|
|
8191
|
+
* Перетаскивание границы: подписка на ручку, снимок на старте, предпросмотр на движении,
|
|
8192
|
+
* запись результата на отпускании.
|
|
8193
|
+
*
|
|
8194
|
+
* Общий для сетки дашборда и колонок таблицы. Различаются они только тем, что именно меряют и
|
|
8195
|
+
* куда пишут; сам жест обязан ощущаться одинаково — включая то, что мышь ведут по документу, а
|
|
8196
|
+
* не по самой ручке, и отпускание за пределами окна тоже завершает жест.
|
|
8197
|
+
*/
|
|
8198
|
+
const useResizeDrag = ({ onStart, onMove, onEnd }) => {
|
|
8199
|
+
const [handle, setHandle] = React.useState(null);
|
|
8200
|
+
const [dragging, setDragging] = React.useState(false);
|
|
8201
|
+
const stateRef = React.useRef(null);
|
|
8202
|
+
const movedRef = React.useRef(false);
|
|
8203
|
+
const mouseDown = React.useCallback((event) => {
|
|
8204
|
+
const state = onStart(event);
|
|
8205
|
+
if (state === null) {
|
|
8206
|
+
return;
|
|
8207
|
+
}
|
|
8208
|
+
// Гасим выделение текста: жест ведут мышью по документу, и без этого он выделял бы всё,
|
|
8209
|
+
// над чем проходит курсор.
|
|
8210
|
+
event.preventDefault();
|
|
8211
|
+
stateRef.current = state;
|
|
8212
|
+
movedRef.current = false;
|
|
8213
|
+
setDragging(true);
|
|
8214
|
+
}, [onStart]);
|
|
8215
|
+
const mouseMove = React.useCallback((event) => {
|
|
8216
|
+
if (stateRef.current !== null) {
|
|
8217
|
+
movedRef.current = true;
|
|
8218
|
+
onMove(stateRef.current, event);
|
|
8219
|
+
}
|
|
8220
|
+
}, [onMove]);
|
|
8221
|
+
const mouseUp = React.useCallback((event) => {
|
|
8222
|
+
const state = stateRef.current;
|
|
8223
|
+
if (state === null) {
|
|
8224
|
+
return;
|
|
8225
|
+
}
|
|
8226
|
+
stateRef.current = null;
|
|
8227
|
+
setDragging(false);
|
|
8228
|
+
if (movedRef.current) {
|
|
8229
|
+
swallowNextClick();
|
|
8230
|
+
}
|
|
8231
|
+
onEnd(state, event);
|
|
8232
|
+
}, [onEnd]);
|
|
8233
|
+
uilibGl.useDragAndDropEffect(handle, { mouseDown, mouseMove, mouseUp });
|
|
8234
|
+
return { setHandle, dragging };
|
|
8235
|
+
};
|
|
8236
|
+
|
|
8173
8237
|
const useRelatedDataSourceAttributes = ({ type = exports.WidgetType.Dashboard, elementConfig, dataSources, feature, }) => {
|
|
8174
8238
|
const { layerInfos } = useWidgetContext(type);
|
|
8175
8239
|
const { currentPage } = useWidgetPage(type);
|
|
@@ -9604,6 +9668,92 @@ const FiltersContainer = React.memo(({ elementConfig, config, type, renderElemen
|
|
|
9604
9668
|
return (jsxRuntime.jsxs(ContainerRoot, { ...root, children: [jsxRuntime.jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsxRuntime.jsx(uilibGl.Flex, { mb: !isVisible && selectedItems.length ? "2rem" : 0, children: jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }) }), isLoading && jsxRuntime.jsx(ContainerLoading, {}), !isLoading && isVisible && (jsxRuntime.jsx(FiltersContainerWrapper, { ...body, "$padding": padding, "$bgColor": bgColor, "$fontSize": fontSize, "$fontColor": fontColor, children: filterItems?.map(renderFilter) })), jsxRuntime.jsx(HiddenTitleItems, { elementConfig: elementConfig, config: config, type: type, filter: filterItems[0]?.options?.filterName })] }));
|
|
9605
9669
|
});
|
|
9606
9670
|
|
|
9671
|
+
/**
|
|
9672
|
+
* Заход зоны захвата на содержимое с каждой стороны границы, px.
|
|
9673
|
+
*
|
|
9674
|
+
* Без него попасть курсором ровно в границу невозможно: у таблицы её толщина — один пиксель,
|
|
9675
|
+
* а у сетки зазора может не быть вовсе. Ручка абсолютная и в раскладке не участвует, поэтому
|
|
9676
|
+
* расширение ничего не сдвигает.
|
|
9677
|
+
*/
|
|
9678
|
+
const HANDLE_BLEED_PX = 3;
|
|
9679
|
+
/**
|
|
9680
|
+
* Маркер ручки: нажатие на ней тянет границу, а не ячейку сетки.
|
|
9681
|
+
*
|
|
9682
|
+
* Ставит его сам компонент. Ручка колонки таблицы, оказавшейся внутри ячейки сетки, обязана
|
|
9683
|
+
* помечаться так же — иначе нажатие на ней начинало бы перетаскивание всей ячейки.
|
|
9684
|
+
*/
|
|
9685
|
+
const RESIZE_HANDLE_ATTR = "data-grid-handle";
|
|
9686
|
+
|
|
9687
|
+
/**
|
|
9688
|
+
* Зона захвата = зазор плюс небольшой заход на содержимое с обеих сторон.
|
|
9689
|
+
*
|
|
9690
|
+
* Смещение уводит дальний край ручки за зазор ровно на `HANDLE_BLEED_PX`, поэтому вместе с
|
|
9691
|
+
* шириной она оказывается симметрично «надета» на границу: от `-bleed` до `gap + bleed`.
|
|
9692
|
+
*/
|
|
9693
|
+
const handleSize = `calc(var(--grid-gap, 0px) + ${HANDLE_BLEED_PX * 2}px)`;
|
|
9694
|
+
const handleOffset = `calc(-1 * (var(--grid-gap, 0px) + ${HANDLE_BLEED_PX}px))`;
|
|
9695
|
+
/**
|
|
9696
|
+
* Ручка перетаскивания границы. Общая для сетки дашборда и колонок таблицы: жест один и тот же,
|
|
9697
|
+
* и выглядеть он обязан одинаково.
|
|
9698
|
+
*
|
|
9699
|
+
* Абсолютная и целиком лежит в зазоре, поэтому включение режима редактирования не сдвигает
|
|
9700
|
+
* раскладку ни на пиксель. Сам ползунок (`::after`) появляется только при наведении и во время
|
|
9701
|
+
* перетаскивания — в покое раскладка выглядит как обычно.
|
|
9702
|
+
*
|
|
9703
|
+
* Ширину зазора берёт из переменной: у сетки её объявляет тело сетки, у таблицы зазора нет вовсе,
|
|
9704
|
+
* и зона захвата сжимается до одного захода на содержимое с каждой стороны.
|
|
9705
|
+
*/
|
|
9706
|
+
const ResizeHandle = styled.div.attrs({ [RESIZE_HANDLE_ATTR]: true }).withConfig({ displayName: "ResizeHandle", componentId: "sc-1n6ja5b" }) `
|
|
9707
|
+
position: absolute;
|
|
9708
|
+
z-index: 3;
|
|
9709
|
+
touch-action: none;
|
|
9710
|
+
|
|
9711
|
+
::after {
|
|
9712
|
+
content: "";
|
|
9713
|
+
position: absolute;
|
|
9714
|
+
border-radius: 0.0625rem;
|
|
9715
|
+
background: transparent;
|
|
9716
|
+
transition: background-color 120ms ease;
|
|
9717
|
+
}
|
|
9718
|
+
|
|
9719
|
+
:hover::after,
|
|
9720
|
+
&[data-dragging="true"]::after {
|
|
9721
|
+
background: ${({ theme: { palette } }) => palette.primary};
|
|
9722
|
+
}
|
|
9723
|
+
|
|
9724
|
+
${({ $axis }) => $axis === "column"
|
|
9725
|
+
? styled.css `
|
|
9726
|
+
top: 0;
|
|
9727
|
+
bottom: 0;
|
|
9728
|
+
right: ${handleOffset};
|
|
9729
|
+
width: ${handleSize};
|
|
9730
|
+
cursor: col-resize;
|
|
9731
|
+
|
|
9732
|
+
::after {
|
|
9733
|
+
top: 20%;
|
|
9734
|
+
bottom: 20%;
|
|
9735
|
+
left: 50%;
|
|
9736
|
+
width: 0.125rem;
|
|
9737
|
+
transform: translateX(-50%);
|
|
9738
|
+
}
|
|
9739
|
+
`
|
|
9740
|
+
: styled.css `
|
|
9741
|
+
left: 0;
|
|
9742
|
+
right: 0;
|
|
9743
|
+
bottom: ${handleOffset};
|
|
9744
|
+
height: ${handleSize};
|
|
9745
|
+
cursor: row-resize;
|
|
9746
|
+
|
|
9747
|
+
::after {
|
|
9748
|
+
left: 20%;
|
|
9749
|
+
right: 20%;
|
|
9750
|
+
top: 50%;
|
|
9751
|
+
height: 0.125rem;
|
|
9752
|
+
transform: translateY(-50%);
|
|
9753
|
+
}
|
|
9754
|
+
`};
|
|
9755
|
+
`;
|
|
9756
|
+
|
|
9607
9757
|
/** Размер, при котором контейнер занимает всю ячейку родителя. */
|
|
9608
9758
|
const FILL_SIZE = "100%";
|
|
9609
9759
|
/** Собственные горизонтальные дефолты обёртки, мешающие контейнеру занять всю ширину ячейки. */
|
|
@@ -9683,6 +9833,7 @@ const getWrapperSizeStyle = ({ style, width: widthOption, height: heightOption,
|
|
|
9683
9833
|
};
|
|
9684
9834
|
};
|
|
9685
9835
|
|
|
9836
|
+
// Прямой импорт листового модуля, а не барреля components: тот тянет за собой контейнеры.
|
|
9686
9837
|
/**
|
|
9687
9838
|
* Минимальный размер трека, px. Ниже него ресайз не пускает — иначе ячейку не за что схватить.
|
|
9688
9839
|
*
|
|
@@ -9718,14 +9869,6 @@ const GRID_AUTO_FILL_DEFAULTS = { ...CONTAINERS_GROUP_DEFAULTS, minHeight: FILL_
|
|
|
9718
9869
|
* раскладки, поэтому задаётся явно через `options.gap`, а не навязывается всем сеткам.
|
|
9719
9870
|
*/
|
|
9720
9871
|
const DEFAULT_GRID_GAP = 0;
|
|
9721
|
-
/**
|
|
9722
|
-
* Насколько ручка ресайза заходит на содержимое с каждой стороны, px.
|
|
9723
|
-
*
|
|
9724
|
-
* По умолчанию зазора нет вовсе, так что попасть курсором ровно в границу невозможно — зона
|
|
9725
|
-
* захвата всегда шире зазора на эту величину с каждой стороны. Ручка абсолютная и в раскладке
|
|
9726
|
-
* не участвует, поэтому расширение ничего не сдвигает.
|
|
9727
|
-
*/
|
|
9728
|
-
const HANDLE_BLEED_PX = 3;
|
|
9729
9872
|
/**
|
|
9730
9873
|
* Сдвиг курсора, после которого нажатие на ячейке считается перетаскиванием, px.
|
|
9731
9874
|
*
|
|
@@ -9735,17 +9878,13 @@ const HANDLE_BLEED_PX = 3;
|
|
|
9735
9878
|
const DRAG_THRESHOLD_PX = 4;
|
|
9736
9879
|
/** Маркер ячейки в DOM: по нему ищется цель перетаскивания под курсором. */
|
|
9737
9880
|
const GRID_CELL_ATTR = "data-grid-cell";
|
|
9738
|
-
/** Маркер ручки ресайза: нажатие на ней тянет границу, а не ячейку. */
|
|
9739
|
-
const GRID_HANDLE_ATTR = "data-grid-handle";
|
|
9740
|
-
/** Тот же маркер пропсами: имя атрибута вычисляемое, а в JSX такое подставляется только спредом. */
|
|
9741
|
-
const GRID_HANDLE_PROPS = { [GRID_HANDLE_ATTR]: true };
|
|
9742
9881
|
/**
|
|
9743
9882
|
* Нажатия, которые перетаскиванием ячейки не считаются.
|
|
9744
9883
|
*
|
|
9745
9884
|
* Ручка тянет границу трека, а поля ввода живут своей жизнью: там нажатие ставит каретку и
|
|
9746
9885
|
* выделяет текст, и подменять это перестановкой ячеек нельзя.
|
|
9747
9886
|
*/
|
|
9748
|
-
const NO_CELL_DRAG_SELECTOR = `[${
|
|
9887
|
+
const NO_CELL_DRAG_SELECTOR = `[${RESIZE_HANDLE_ATTR}], input, textarea, select, [contenteditable="true"]`;
|
|
9749
9888
|
/**
|
|
9750
9889
|
* Разметка идущего жеста: ячейка-источник, цель под курсором и сам факт перетаскивания.
|
|
9751
9890
|
*
|
|
@@ -9766,72 +9905,6 @@ const FR_PRECISION = 1000;
|
|
|
9766
9905
|
const GRID_ROW_ID_PREFIX = "gridRow_";
|
|
9767
9906
|
const GRID_CELL_ID_PREFIX = "gridCell_";
|
|
9768
9907
|
|
|
9769
|
-
/**
|
|
9770
|
-
* Зона захвата = зазор плюс небольшой заход на содержимое с обеих сторон.
|
|
9771
|
-
*
|
|
9772
|
-
* Смещение уводит дальний край ручки за зазор ровно на `HANDLE_BLEED_PX`, поэтому вместе с
|
|
9773
|
-
* шириной она оказывается симметрично «надета» на границу: от `-bleed` до `gap + bleed`.
|
|
9774
|
-
*/
|
|
9775
|
-
const handleSize = `calc(var(--grid-gap, 0px) + ${HANDLE_BLEED_PX * 2}px)`;
|
|
9776
|
-
const handleOffset = `calc(-1 * (var(--grid-gap, 0px) + ${HANDLE_BLEED_PX}px))`;
|
|
9777
|
-
/**
|
|
9778
|
-
* Ручка перетаскивания границы треков.
|
|
9779
|
-
*
|
|
9780
|
-
* Абсолютная и целиком лежит в зазоре, поэтому включение режима редактирования не сдвигает
|
|
9781
|
-
* раскладку ни на пиксель. Сам ползунок (`::after`) появляется только при наведении и во время
|
|
9782
|
-
* перетаскивания — в покое сетка выглядит как обычно.
|
|
9783
|
-
*/
|
|
9784
|
-
const ResizeHandle = styled.div.withConfig({ displayName: "ResizeHandle", componentId: "sc-1dtcak4" }) `
|
|
9785
|
-
position: absolute;
|
|
9786
|
-
z-index: 3;
|
|
9787
|
-
touch-action: none;
|
|
9788
|
-
|
|
9789
|
-
::after {
|
|
9790
|
-
content: "";
|
|
9791
|
-
position: absolute;
|
|
9792
|
-
border-radius: 0.0625rem;
|
|
9793
|
-
background: transparent;
|
|
9794
|
-
transition: background-color 120ms ease;
|
|
9795
|
-
}
|
|
9796
|
-
|
|
9797
|
-
:hover::after,
|
|
9798
|
-
&[data-dragging="true"]::after {
|
|
9799
|
-
background: ${({ theme: { palette } }) => palette.primary};
|
|
9800
|
-
}
|
|
9801
|
-
|
|
9802
|
-
${({ $axis }) => $axis === "column"
|
|
9803
|
-
? styled.css `
|
|
9804
|
-
top: 0;
|
|
9805
|
-
bottom: 0;
|
|
9806
|
-
right: ${handleOffset};
|
|
9807
|
-
width: ${handleSize};
|
|
9808
|
-
cursor: col-resize;
|
|
9809
|
-
|
|
9810
|
-
::after {
|
|
9811
|
-
top: 20%;
|
|
9812
|
-
bottom: 20%;
|
|
9813
|
-
left: 50%;
|
|
9814
|
-
width: 0.125rem;
|
|
9815
|
-
transform: translateX(-50%);
|
|
9816
|
-
}
|
|
9817
|
-
`
|
|
9818
|
-
: styled.css `
|
|
9819
|
-
left: 0;
|
|
9820
|
-
right: 0;
|
|
9821
|
-
bottom: ${handleOffset};
|
|
9822
|
-
height: ${handleSize};
|
|
9823
|
-
cursor: row-resize;
|
|
9824
|
-
|
|
9825
|
-
::after {
|
|
9826
|
-
left: 20%;
|
|
9827
|
-
right: 20%;
|
|
9828
|
-
top: 50%;
|
|
9829
|
-
height: 0.125rem;
|
|
9830
|
-
transform: translateY(-50%);
|
|
9831
|
-
}
|
|
9832
|
-
`};
|
|
9833
|
-
`;
|
|
9834
|
-
|
|
9835
9908
|
const getTemplateProperty = (axis) => axis === "row" ? "gridTemplateRows" : "gridTemplateColumns";
|
|
9836
9909
|
/**
|
|
9837
9910
|
* Пиксельные размеры треков отрисованной сетки.
|
|
@@ -9919,29 +9992,24 @@ const toShares = (pixels, total) => {
|
|
|
9919
9992
|
* снова раздувалась содержимым.
|
|
9920
9993
|
*/
|
|
9921
9994
|
const useGridHeightResize = ({ sizes, autoHeight, getGrid, onCommit, }) => {
|
|
9922
|
-
const [handle, setHandle] = React.useState(null);
|
|
9923
|
-
const [dragging, setDragging] = React.useState(false);
|
|
9924
|
-
const dragRef = React.useRef(null);
|
|
9925
9995
|
const sizesRef = React.useRef(sizes);
|
|
9926
9996
|
sizesRef.current = sizes;
|
|
9927
9997
|
/** Свойство корня, которым жест двигает нижнюю границу: жёсткая высота либо её минимум. */
|
|
9928
9998
|
const heightProperty = autoHeight ? "minHeight" : "height";
|
|
9929
|
-
const
|
|
9999
|
+
const onStart = React.useCallback((event) => {
|
|
9930
10000
|
const grid = getGrid();
|
|
9931
10001
|
const root = grid?.parentElement;
|
|
9932
10002
|
if (!grid || !root)
|
|
9933
|
-
return;
|
|
10003
|
+
return null;
|
|
9934
10004
|
const pixels = readTrackPixels(grid, "row");
|
|
9935
10005
|
if (!pixels?.length || pixels.length !== sizesRef.current.length)
|
|
9936
|
-
return;
|
|
9937
|
-
|
|
9938
|
-
dragRef.current = {
|
|
10006
|
+
return null;
|
|
10007
|
+
return {
|
|
9939
10008
|
start: event.clientY,
|
|
9940
10009
|
pixels,
|
|
9941
10010
|
root,
|
|
9942
10011
|
rootHeight: root.getBoundingClientRect().height,
|
|
9943
10012
|
};
|
|
9944
|
-
setDragging(true);
|
|
9945
10013
|
}, [getGrid]);
|
|
9946
10014
|
/** Пиксели треков после сдвига: меняется только последний, минимум — текущий, если он уже мал. */
|
|
9947
10015
|
const getNextPixels = React.useCallback((state, event) => {
|
|
@@ -9949,22 +10017,16 @@ const useGridHeightResize = ({ sizes, autoHeight, getGrid, onCommit, }) => {
|
|
|
9949
10017
|
const min = Math.min(MIN_TRACK_PX, last);
|
|
9950
10018
|
return [...state.pixels.slice(0, -1), Math.max(last + event.clientY - state.start, min)];
|
|
9951
10019
|
}, []);
|
|
9952
|
-
const
|
|
9953
|
-
const state = dragRef.current;
|
|
10020
|
+
const onMove = React.useCallback((state, event) => {
|
|
9954
10021
|
const grid = getGrid();
|
|
9955
|
-
if (!
|
|
10022
|
+
if (!grid)
|
|
9956
10023
|
return;
|
|
9957
10024
|
const pixels = getNextPixels(state, event);
|
|
9958
10025
|
const delta = pixels[pixels.length - 1] - state.pixels[state.pixels.length - 1];
|
|
9959
10026
|
state.root.style[heightProperty] = `${state.rootHeight + delta}px`;
|
|
9960
10027
|
grid.style[getTemplateProperty("row")] = buildTrackTemplate(pixels.map(size => `${size}px`), autoHeight);
|
|
9961
10028
|
}, [autoHeight, getGrid, getNextPixels, heightProperty]);
|
|
9962
|
-
const
|
|
9963
|
-
const state = dragRef.current;
|
|
9964
|
-
if (!state)
|
|
9965
|
-
return;
|
|
9966
|
-
dragRef.current = null;
|
|
9967
|
-
setDragging(false);
|
|
10029
|
+
const onEnd = React.useCallback((state, event) => {
|
|
9968
10030
|
const grid = getGrid();
|
|
9969
10031
|
if (grid)
|
|
9970
10032
|
grid.style[getTemplateProperty("row")] = "";
|
|
@@ -9976,8 +10038,7 @@ const useGridHeightResize = ({ sizes, autoHeight, getGrid, onCommit, }) => {
|
|
|
9976
10038
|
const total = sizesRef.current.reduce((value, size) => value + size, 0);
|
|
9977
10039
|
onCommit(`${Math.round(state.rootHeight + delta)}px`, toShares(pixels, total));
|
|
9978
10040
|
}, [getGrid, getNextPixels, heightProperty, onCommit]);
|
|
9979
|
-
|
|
9980
|
-
return { setHandle, dragging };
|
|
10041
|
+
return useResizeDrag({ onStart, onMove, onEnd });
|
|
9981
10042
|
};
|
|
9982
10043
|
|
|
9983
10044
|
/**
|
|
@@ -9990,7 +10051,7 @@ const GridHeightResizer = React.memo(({ sizes, autoHeight, getGrid, onCommit })
|
|
|
9990
10051
|
// Ручка лежит внутри трека: без остановки всплытия перетаскивание границы заканчивалось бы
|
|
9991
10052
|
// кликом по ячейке, то есть меняло бы выделение.
|
|
9992
10053
|
const stopPropagation = React.useCallback((event) => event.stopPropagation(), []);
|
|
9993
|
-
return (jsxRuntime.jsx(ResizeHandle, {
|
|
10054
|
+
return (jsxRuntime.jsx(ResizeHandle, { ref: setHandle, "$axis": "row", "data-dragging": dragging, onClick: stopPropagation }));
|
|
9994
10055
|
});
|
|
9995
10056
|
|
|
9996
10057
|
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
@@ -10011,31 +10072,26 @@ const buildPreviewTemplate = (pixels, index, first, second) => buildTrackTemplat
|
|
|
10011
10072
|
/**
|
|
10012
10073
|
* Перетаскивание границы между двумя соседними треками.
|
|
10013
10074
|
*
|
|
10014
|
-
*
|
|
10015
|
-
*
|
|
10016
|
-
* на отпускание мыши.
|
|
10075
|
+
* Сам жест — общий {@link useResizeDrag}: он же двигает и границы колонок таблицы, поэтому
|
|
10076
|
+
* ощущаются они одинаково. Здесь остаётся только грид-специфичное: во время жеста раскладка
|
|
10077
|
+
* меняется ИНЛАЙН-стилем на самом гриде, а в конфиг доли уходят один раз, на отпускание мыши.
|
|
10017
10078
|
*
|
|
10018
|
-
* Пиксельный снимок треков берётся однократно на
|
|
10079
|
+
* Пиксельный снимок треков берётся однократно на нажатии — если пересчитывать его на каждом
|
|
10019
10080
|
* шаге уже после применения новых долей, округление `fr → px → fr` даёт дрейф границы.
|
|
10020
10081
|
*/
|
|
10021
10082
|
const useGridResize = ({ axis, index, sizes, getGrid, onCommit }) => {
|
|
10022
|
-
const [handle, setHandle] = React.useState(null);
|
|
10023
|
-
const [dragging, setDragging] = React.useState(false);
|
|
10024
|
-
const dragRef = React.useRef(null);
|
|
10025
10083
|
const sizesRef = React.useRef(sizes);
|
|
10026
10084
|
sizesRef.current = sizes;
|
|
10027
10085
|
const isRow = axis === "row";
|
|
10028
10086
|
const getPosition = React.useCallback((event) => (isRow ? event.clientY : event.clientX), [isRow]);
|
|
10029
|
-
const
|
|
10087
|
+
const onStart = React.useCallback((event) => {
|
|
10030
10088
|
const grid = getGrid();
|
|
10031
10089
|
if (!grid)
|
|
10032
|
-
return;
|
|
10090
|
+
return null;
|
|
10033
10091
|
const pixels = readTrackPixels(grid, axis);
|
|
10034
10092
|
if (!pixels || index + 1 >= pixels.length)
|
|
10035
|
-
return;
|
|
10036
|
-
event
|
|
10037
|
-
dragRef.current = { start: getPosition(event), pixels };
|
|
10038
|
-
setDragging(true);
|
|
10093
|
+
return null;
|
|
10094
|
+
return { start: getPosition(event), pixels };
|
|
10039
10095
|
}, [axis, getGrid, getPosition, index]);
|
|
10040
10096
|
/** Новый пиксельный размер первого трека пары с учётом минимального размера обоих. */
|
|
10041
10097
|
const getNextFirstSize = React.useCallback((state, event) => {
|
|
@@ -10046,10 +10102,9 @@ const useGridResize = ({ axis, index, sizes, getGrid, onCommit }) => {
|
|
|
10046
10102
|
const min = getMinTrackSize(total);
|
|
10047
10103
|
return clamp(first + getPosition(event) - state.start, min, total - min);
|
|
10048
10104
|
}, [getPosition, index]);
|
|
10049
|
-
const
|
|
10050
|
-
const state = dragRef.current;
|
|
10105
|
+
const onMove = React.useCallback((state, event) => {
|
|
10051
10106
|
const grid = getGrid();
|
|
10052
|
-
if (!
|
|
10107
|
+
if (!grid)
|
|
10053
10108
|
return;
|
|
10054
10109
|
const first = getNextFirstSize(state, event);
|
|
10055
10110
|
if (first === null)
|
|
@@ -10057,12 +10112,7 @@ const useGridResize = ({ axis, index, sizes, getGrid, onCommit }) => {
|
|
|
10057
10112
|
const total = state.pixels[index] + state.pixels[index + 1];
|
|
10058
10113
|
grid.style[getTemplateProperty(axis)] = buildPreviewTemplate(state.pixels, index, first, total - first);
|
|
10059
10114
|
}, [axis, getGrid, getNextFirstSize, index]);
|
|
10060
|
-
const
|
|
10061
|
-
const state = dragRef.current;
|
|
10062
|
-
if (!state)
|
|
10063
|
-
return;
|
|
10064
|
-
dragRef.current = null;
|
|
10065
|
-
setDragging(false);
|
|
10115
|
+
const onEnd = React.useCallback((state, event) => {
|
|
10066
10116
|
const grid = getGrid();
|
|
10067
10117
|
if (grid)
|
|
10068
10118
|
grid.style[getTemplateProperty(axis)] = "";
|
|
@@ -10077,8 +10127,7 @@ const useGridResize = ({ axis, index, sizes, getGrid, onCommit }) => {
|
|
|
10077
10127
|
return;
|
|
10078
10128
|
onCommit(index, [nextFirst, roundFr(share - nextFirst)]);
|
|
10079
10129
|
}, [axis, getGrid, getNextFirstSize, index, onCommit]);
|
|
10080
|
-
|
|
10081
|
-
return { setHandle, dragging };
|
|
10130
|
+
return useResizeDrag({ onStart, onMove, onEnd });
|
|
10082
10131
|
};
|
|
10083
10132
|
|
|
10084
10133
|
const GridResizer = React.memo(({ axis, index, sizes, getGrid, onCommit }) => {
|
|
@@ -10086,7 +10135,7 @@ const GridResizer = React.memo(({ axis, index, sizes, getGrid, onCommit }) => {
|
|
|
10086
10135
|
// Ручка лежит внутри трека, и без этого перетаскивание границы заканчивалось бы кликом
|
|
10087
10136
|
// по ячейке — то есть меняло бы выделение.
|
|
10088
10137
|
const stopPropagation = React.useCallback((event) => event.stopPropagation(), []);
|
|
10089
|
-
return (jsxRuntime.jsx(ResizeHandle, {
|
|
10138
|
+
return (jsxRuntime.jsx(ResizeHandle, { ref: setHandle, "$axis": axis, "data-dragging": dragging, onClick: stopPropagation }));
|
|
10090
10139
|
});
|
|
10091
10140
|
|
|
10092
10141
|
/**
|
|
@@ -15506,8 +15555,9 @@ const TableHead = styled.thead.withConfig({ displayName: "TableHead", componentI
|
|
|
15506
15555
|
z-index: 1;
|
|
15507
15556
|
`;
|
|
15508
15557
|
const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", componentId: "sc-1m6xil2" }) `
|
|
15509
|
-
/* Относительное позиционирование держит захват границы
|
|
15558
|
+
/* Относительное позиционирование держит захват границы колонки. */
|
|
15510
15559
|
position: relative;
|
|
15560
|
+
box-sizing: border-box;
|
|
15511
15561
|
padding: 0.375rem 0.5rem;
|
|
15512
15562
|
text-align: left;
|
|
15513
15563
|
font-weight: 600;
|
|
@@ -15535,33 +15585,13 @@ const TableHeadContent = styled.span.withConfig({ displayName: "TableHeadContent
|
|
|
15535
15585
|
overflow: hidden;
|
|
15536
15586
|
text-overflow: ellipsis;
|
|
15537
15587
|
`;
|
|
15538
|
-
/**
|
|
15539
|
-
* Захват правой границы колонки. Лежит поверх края ячейки и ловит указатель сам, поэтому
|
|
15540
|
-
* перетаскивание не доходит до заголовка и не переключает сортировку.
|
|
15541
|
-
*
|
|
15542
|
-
* Ширина в пикселах, а не в rem: это зона попадания курсора, и от размера шрифта она не зависит.
|
|
15543
|
-
*/
|
|
15544
|
-
const TableResizeHandle = styled.span.withConfig({ displayName: "TableResizeHandle", componentId: "sc-1g0q105" }) `
|
|
15545
|
-
position: absolute;
|
|
15546
|
-
top: 0;
|
|
15547
|
-
right: 0;
|
|
15548
|
-
bottom: 0;
|
|
15549
|
-
width: 8px;
|
|
15550
|
-
cursor: col-resize;
|
|
15551
|
-
touch-action: none;
|
|
15552
|
-
user-select: none;
|
|
15553
|
-
|
|
15554
|
-
:hover {
|
|
15555
|
-
background: ${({ theme }) => theme.palette.elementDeep};
|
|
15556
|
-
}
|
|
15557
|
-
`;
|
|
15558
15588
|
/**
|
|
15559
15589
|
* Место под значок сортировки. Занято всегда, пока сортировка включена, а сам значок только
|
|
15560
15590
|
* прячется: появляясь и исчезая, он менял бы ширину колонки — и таблицу дёргало бы на каждый
|
|
15561
15591
|
* клик по заголовку, вместе с телом. Оба направления рисуются значком в 1rem, поэтому
|
|
15562
15592
|
* переключение asc/des ширину тоже не трогает.
|
|
15563
15593
|
*/
|
|
15564
|
-
const TableSortSlot = styled.span.withConfig({ displayName: "TableSortSlot", componentId: "sc-
|
|
15594
|
+
const TableSortSlot = styled.span.withConfig({ displayName: "TableSortSlot", componentId: "sc-z378vf" }) `
|
|
15565
15595
|
display: inline-flex;
|
|
15566
15596
|
visibility: ${({ $active }) => ($active ? "visible" : "hidden")};
|
|
15567
15597
|
`;
|
|
@@ -15570,26 +15600,30 @@ const TableSortSlot = styled.span.withConfig({ displayName: "TableSortSlot", com
|
|
|
15570
15600
|
* её нижнюю кромку и сквозь прозрачную шапку не проступают. Величину пишет {@link useHeadOverlap},
|
|
15571
15601
|
* без неё отсечка нулевая и разметка не меняется.
|
|
15572
15602
|
*/
|
|
15573
|
-
const TableBody = styled.tbody.withConfig({ displayName: "TableBody", componentId: "sc-
|
|
15603
|
+
const TableBody = styled.tbody.withConfig({ displayName: "TableBody", componentId: "sc-1pxpl5v" }) `
|
|
15574
15604
|
clip-path: inset(var(${HEAD_OVERLAP_VARIABLE}, 0px) 0 0 0);
|
|
15575
15605
|
`;
|
|
15576
15606
|
/**
|
|
15577
15607
|
* Строка. Разделитель рисуют её ячейки: собственная рамка строки при раздельных рамках не
|
|
15578
15608
|
* рисуется вовсе, а при схлопнутых её рисовала бы таблица — и отсечка тела её бы не резала.
|
|
15579
15609
|
*/
|
|
15580
|
-
const TableRow = styled.tr.withConfig({ displayName: "TableRow", componentId: "sc-
|
|
15610
|
+
const TableRow = styled.tr.withConfig({ displayName: "TableRow", componentId: "sc-j62zvd" }) `
|
|
15581
15611
|
td {
|
|
15582
15612
|
border-bottom: 1px solid ${({ theme }) => theme.palette.elementDeep};
|
|
15583
15613
|
}
|
|
15584
15614
|
`;
|
|
15585
|
-
const TableCellWrapper = styled.td.withConfig({ displayName: "TableCellWrapper", componentId: "sc-
|
|
15615
|
+
const TableCellWrapper = styled.td.withConfig({ displayName: "TableCellWrapper", componentId: "sc-ziu5rk" }) `
|
|
15616
|
+
/* Относительное позиционирование держит захват границы колонки. */
|
|
15617
|
+
position: relative;
|
|
15618
|
+
/* Как и у заголовка: ширина колонки считается по внешнему краю ячейки. */
|
|
15619
|
+
box-sizing: border-box;
|
|
15586
15620
|
padding: 0.125rem 0.25rem;
|
|
15587
15621
|
vertical-align: middle;
|
|
15588
15622
|
/* Предел снимает заданная ширина: с колонками по содержимому обрезать значение незачем. */
|
|
15589
15623
|
max-width: var(--table-cell-max-width, 20rem);
|
|
15590
15624
|
`;
|
|
15591
15625
|
/** Колонка действий: узкая, не растягивается содержимым. */
|
|
15592
|
-
const TableActionsCell = styled(TableCellWrapper).withConfig({ displayName: "TableActionsCell", componentId: "sc-
|
|
15626
|
+
const TableActionsCell = styled(TableCellWrapper).withConfig({ displayName: "TableActionsCell", componentId: "sc-18w13t3" }) `
|
|
15593
15627
|
width: 2rem;
|
|
15594
15628
|
text-align: right;
|
|
15595
15629
|
`;
|
|
@@ -15612,7 +15646,7 @@ const cellWrapMixin = styled.css `
|
|
|
15612
15646
|
white-space: nowrap;
|
|
15613
15647
|
`}
|
|
15614
15648
|
`;
|
|
15615
|
-
const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "sc-
|
|
15649
|
+
const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "sc-ok630s" }) `
|
|
15616
15650
|
padding: 0.375rem 0.25rem;
|
|
15617
15651
|
/* Та же высота строки, что у редактора — иначе строка подпрыгивала бы по вертикали. */
|
|
15618
15652
|
line-height: 1.25rem;
|
|
@@ -15626,7 +15660,7 @@ const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "
|
|
|
15626
15660
|
* Кнопка, а не просто текст, именно ради фокуса: она — таб-стоп ячейки, и Tab по таблице
|
|
15627
15661
|
* открывает редактор с курсором внутри.
|
|
15628
15662
|
*/
|
|
15629
|
-
const CellButton = styled.button.withConfig({ displayName: "CellButton", componentId: "sc-
|
|
15663
|
+
const CellButton = styled.button.withConfig({ displayName: "CellButton", componentId: "sc-98k9cz" }) `
|
|
15630
15664
|
width: 100%;
|
|
15631
15665
|
padding: 0.375rem 0.25rem;
|
|
15632
15666
|
line-height: 1.25rem;
|
|
@@ -15644,7 +15678,7 @@ const CellButton = styled.button.withConfig({ displayName: "CellButton", compone
|
|
|
15644
15678
|
border-color: ${({ theme }) => theme.palette.elementDeep};
|
|
15645
15679
|
}
|
|
15646
15680
|
`;
|
|
15647
|
-
const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder", componentId: "sc-
|
|
15681
|
+
const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder", componentId: "sc-7tff41" }) `
|
|
15648
15682
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
15649
15683
|
`;
|
|
15650
15684
|
/**
|
|
@@ -15653,11 +15687,11 @@ const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder",
|
|
|
15653
15687
|
* Копия остаётся в потоке и держит ширину колонки ровно такой, какой она была до клика, —
|
|
15654
15688
|
* иначе таблица дёргалась бы на каждый вход в правку и выход из неё.
|
|
15655
15689
|
*/
|
|
15656
|
-
const CellEditor = styled.div.withConfig({ displayName: "CellEditor", componentId: "sc-
|
|
15690
|
+
const CellEditor = styled.div.withConfig({ displayName: "CellEditor", componentId: "sc-qa22du" }) `
|
|
15657
15691
|
position: relative;
|
|
15658
15692
|
min-height: 2rem;
|
|
15659
15693
|
`;
|
|
15660
|
-
const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId: "sc-
|
|
15694
|
+
const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId: "sc-1i1yvb2" }) `
|
|
15661
15695
|
display: block;
|
|
15662
15696
|
padding: 0.375rem 0.25rem;
|
|
15663
15697
|
/* Рамка повторяет CellButton — с ней высота ячейки в правке совпадает с высотой на чтении. */
|
|
@@ -15667,7 +15701,7 @@ const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId
|
|
|
15667
15701
|
|
|
15668
15702
|
${cellWrapMixin};
|
|
15669
15703
|
`;
|
|
15670
|
-
const CellField = styled.div.withConfig({ displayName: "CellField", componentId: "sc-
|
|
15704
|
+
const CellField = styled.div.withConfig({ displayName: "CellField", componentId: "sc-1ww3875" }) `
|
|
15671
15705
|
position: absolute;
|
|
15672
15706
|
inset: 0;
|
|
15673
15707
|
display: flex;
|
|
@@ -15689,14 +15723,14 @@ const CellField = styled.div.withConfig({ displayName: "CellField", componentId:
|
|
|
15689
15723
|
* Отступы те же, что у текстовой ячейки (`CellText`): в одном ряду с обычными колонками значения
|
|
15690
15724
|
* обязаны стоять на одной линии.
|
|
15691
15725
|
*/
|
|
15692
|
-
const AttachmentsCellBox = styled.div.withConfig({ displayName: "AttachmentsCellBox", componentId: "sc-
|
|
15726
|
+
const AttachmentsCellBox = styled.div.withConfig({ displayName: "AttachmentsCellBox", componentId: "sc-1ayq7sq" }) `
|
|
15693
15727
|
display: flex;
|
|
15694
15728
|
flex-direction: column;
|
|
15695
15729
|
align-items: flex-start;
|
|
15696
15730
|
gap: 0.25rem;
|
|
15697
15731
|
padding: 0.375rem 0.25rem;
|
|
15698
15732
|
`;
|
|
15699
|
-
const TableEmpty = styled.div.withConfig({ displayName: "TableEmpty", componentId: "sc-
|
|
15733
|
+
const TableEmpty = styled.div.withConfig({ displayName: "TableEmpty", componentId: "sc-dmdhrv" }) `
|
|
15700
15734
|
padding: 0.75rem 0.25rem;
|
|
15701
15735
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
15702
15736
|
`;
|
|
@@ -15919,15 +15953,91 @@ const TableCell = React.memo(({ attribute, row, canEdit, onChange }) => {
|
|
|
15919
15953
|
});
|
|
15920
15954
|
|
|
15921
15955
|
/**
|
|
15922
|
-
*
|
|
15956
|
+
* Имя переменной ширины колонки.
|
|
15957
|
+
*
|
|
15958
|
+
* Через неё идёт и предпросмотр перетаскивания, и итоговая ширина: пока переменная не задана,
|
|
15959
|
+
* работает запасное значение из стиля ячейки, а жест на время перетаскивания объявляет её на
|
|
15960
|
+
* самой таблице — одним свойством на один узел, как сетка меняет свой шаблон треков.
|
|
15961
|
+
*/
|
|
15962
|
+
const getColumnWidthVariable = (index) => `--table-col-${index}`;
|
|
15963
|
+
/**
|
|
15964
|
+
* Инлайн-размер ячейки колонки с заданной или изменяемой шириной.
|
|
15923
15965
|
*
|
|
15924
15966
|
* Раскладка таблицы автоматическая (ширину колонок выбирает содержимое), и одной `width` ей мало —
|
|
15925
15967
|
* она для неё лишь пожелание. Жёстко колонку держат все три предела сразу, поэтому и ставим их
|
|
15926
15968
|
* втроём, на каждую ячейку колонки.
|
|
15927
15969
|
*
|
|
15928
|
-
*
|
|
15970
|
+
* Ни ширины, ни разрешения тянуть — стиля нет: колонка остаётся на попечении раскладки, как и была.
|
|
15929
15971
|
*/
|
|
15930
|
-
const getColumnStyle = (
|
|
15972
|
+
const getColumnStyle = (index, width, resizable) => {
|
|
15973
|
+
if (width == null && !resizable) {
|
|
15974
|
+
return undefined;
|
|
15975
|
+
}
|
|
15976
|
+
const variable = getColumnWidthVariable(index);
|
|
15977
|
+
const fixed = width == null ? null : `${width}px`;
|
|
15978
|
+
return {
|
|
15979
|
+
width: `var(${variable}, ${fixed ?? "auto"})`,
|
|
15980
|
+
minWidth: `var(${variable}, ${fixed ?? "0"})`,
|
|
15981
|
+
// Без заданной ширины предел остаётся общим для всех ячеек — тем, что задан стилем таблицы.
|
|
15982
|
+
maxWidth: `var(${variable}, ${fixed ?? "var(--table-cell-max-width, 20rem)"})`,
|
|
15983
|
+
};
|
|
15984
|
+
};
|
|
15985
|
+
|
|
15986
|
+
/**
|
|
15987
|
+
* Перетаскивание правой границы колонки.
|
|
15988
|
+
*
|
|
15989
|
+
* Жест — общий {@link useResizeDrag}, тот же, что двигает границы ячеек сетки дашборда. Здесь
|
|
15990
|
+
* остаётся только табличное: во время жеста ширина рисуется переменной на самой таблице, а в
|
|
15991
|
+
* состояние уходит один раз, на отпускание мыши. Так шаг жеста меняет одно свойство одного узла,
|
|
15992
|
+
* а не перерисовывает таблицу целиком.
|
|
15993
|
+
*
|
|
15994
|
+
* Стартовая ширина берётся с той ячейки, за границу которой потянули: у колонки без `width` её
|
|
15995
|
+
* выбрала раскладка таблицы, и тянуть надо от того, что видно.
|
|
15996
|
+
*/
|
|
15997
|
+
const useColumnResize = ({ index, onCommit }) => {
|
|
15998
|
+
const variable = getColumnWidthVariable(index);
|
|
15999
|
+
const onStart = React.useCallback((event) => {
|
|
16000
|
+
// Обработчик нажатия висит на самой ручке, поэтому её ячейка и таблица достаются отсюда —
|
|
16001
|
+
// отдельный ref на них не нужен. Ячейка любая: ручки стоят и в шапке, и в каждой строке.
|
|
16002
|
+
const cell = event.currentTarget?.closest("th, td");
|
|
16003
|
+
if (!cell) {
|
|
16004
|
+
return null;
|
|
16005
|
+
}
|
|
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]);
|
|
16014
|
+
const onEnd = React.useCallback((state, event) => {
|
|
16015
|
+
state.table?.style.removeProperty(variable);
|
|
16016
|
+
const next = getNextWidth(state, event);
|
|
16017
|
+
// Клик по границе без перетаскивания ширину менять не должен.
|
|
16018
|
+
if (next === Math.round(state.width)) {
|
|
16019
|
+
return;
|
|
16020
|
+
}
|
|
16021
|
+
onCommit(next);
|
|
16022
|
+
}, [getNextWidth, onCommit, variable]);
|
|
16023
|
+
return useResizeDrag({ onStart, onMove, onEnd });
|
|
16024
|
+
};
|
|
16025
|
+
|
|
16026
|
+
/**
|
|
16027
|
+
* Ручка ширины колонки на правой границе ячейки.
|
|
16028
|
+
*
|
|
16029
|
+
* Тот же компонент и тот же жест, что двигают границы ячеек сетки дашборда: пользователю это одно
|
|
16030
|
+
* и то же действие, и выглядеть оно обязано одинаково. Поэтому и стоит она у КАЖДОЙ ячейки
|
|
16031
|
+
* колонки, как в сетке, — тянуть границу можно на любой строке, а не только в шапке.
|
|
16032
|
+
*/
|
|
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 });
|
|
16036
|
+
// Ручка лежит внутри ячейки, и без остановки всплытия перетаскивание границы заканчивалось бы
|
|
16037
|
+
// кликом по ней — то есть переключало бы сортировку в шапке и открывало бы правку в теле.
|
|
16038
|
+
const stopPropagation = React.useCallback((event) => event.stopPropagation(), []);
|
|
16039
|
+
return jsxRuntime.jsx(ResizeHandle, { ref: setHandle, "$axis": "column", "data-dragging": dragging, onClick: stopPropagation });
|
|
16040
|
+
});
|
|
15931
16041
|
|
|
15932
16042
|
/**
|
|
15933
16043
|
* Шапка таблицы: заголовки колонок, сортировка кликом и захват границы для ручной ширины.
|
|
@@ -15935,9 +16045,9 @@ const getColumnStyle = (width) => width == null ? undefined : { width, minWidth:
|
|
|
15935
16045
|
* Захват рисуется по разрешению атрибута (`resizable`) и не смотрит на режим правки контейнера:
|
|
15936
16046
|
* ширина колонки — это вид, а не данные.
|
|
15937
16047
|
*/
|
|
15938
|
-
const TableHeadRow = ({ columns, sort, sortEnabled, columnWidths, withActionsColumn, onSortToggle,
|
|
16048
|
+
const TableHeadRow = ({ columns, sort, sortEnabled, columnWidths, withActionsColumn, onSortToggle, onColumnResize, }) => (jsxRuntime.jsxs("tr", { children: [columns.map(({ attributeName, alias, description, resizable }, index) => {
|
|
15939
16049
|
const sorted = sort?.attributeName === attributeName;
|
|
15940
|
-
return (jsxRuntime.jsxs(TableHeadCell, { title: description || alias, style: getColumnStyle(columnWidths[attributeName]), "$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 &&
|
|
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));
|
|
15941
16051
|
}), withActionsColumn && jsxRuntime.jsx(TableHeadCell, {})] }));
|
|
15942
16052
|
|
|
15943
16053
|
const ContainerLoading = () => (jsxRuntime.jsx(uilibGl.Flex, { alignContent: "center", justifyContent: "center", width: "100%", children: jsxRuntime.jsx(uilibGl.CircularProgress, { diameter: 1.5, mono: true }) }));
|
|
@@ -16043,53 +16153,6 @@ const getTableBoxStyle = (width, height) => {
|
|
|
16043
16153
|
};
|
|
16044
16154
|
};
|
|
16045
16155
|
|
|
16046
|
-
/**
|
|
16047
|
-
* Ручное изменение ширины колонок.
|
|
16048
|
-
*
|
|
16049
|
-
* Растянутые ширины живут только здесь: тянут их в рантайме, а `width` атрибута в конфиге задаёт
|
|
16050
|
-
* лишь стартовое значение — записывать растянутое обратно в конфиг незачем.
|
|
16051
|
-
*
|
|
16052
|
-
* Разрешение (`resizable`) от `options.editMode` не зависит: ширина колонки — это вид таблицы,
|
|
16053
|
-
* а не правка данных, и тянуть её должно быть можно и на таблице только для чтения.
|
|
16054
|
-
*
|
|
16055
|
-
* Стартовую ширину берём с самой ячейки, а не из конфига: у колонки без `width` её выбрала
|
|
16056
|
-
* раскладка таблицы, и тянуть надо ровно от того, что видно.
|
|
16057
|
-
*/
|
|
16058
|
-
const useColumnResize = (columns) => {
|
|
16059
|
-
const [widths, setWidths] = React.useState({});
|
|
16060
|
-
const dragRef = React.useRef(null);
|
|
16061
|
-
const onResizeStart = React.useCallback((attributeName, event) => {
|
|
16062
|
-
const handle = event.currentTarget;
|
|
16063
|
-
// Захват границы — не клик по заголовку: иначе каждое перетаскивание переключало бы сортировку.
|
|
16064
|
-
event.preventDefault();
|
|
16065
|
-
event.stopPropagation();
|
|
16066
|
-
dragRef.current = {
|
|
16067
|
-
attributeName,
|
|
16068
|
-
startX: event.clientX,
|
|
16069
|
-
startWidth: handle.closest("th")?.getBoundingClientRect().width ?? MIN_COLUMN_WIDTH,
|
|
16070
|
-
};
|
|
16071
|
-
handle.setPointerCapture(event.pointerId);
|
|
16072
|
-
}, []);
|
|
16073
|
-
const onResizeMove = React.useCallback((event) => {
|
|
16074
|
-
const drag = dragRef.current;
|
|
16075
|
-
if (!drag) {
|
|
16076
|
-
return;
|
|
16077
|
-
}
|
|
16078
|
-
const next = Math.max(MIN_COLUMN_WIDTH, Math.round(drag.startWidth + event.clientX - drag.startX));
|
|
16079
|
-
setWidths(current => current[drag.attributeName] === next ? current : { ...current, [drag.attributeName]: next });
|
|
16080
|
-
}, []);
|
|
16081
|
-
const onResizeEnd = React.useCallback((event) => {
|
|
16082
|
-
const handle = event.currentTarget;
|
|
16083
|
-
dragRef.current = null;
|
|
16084
|
-
if (handle.hasPointerCapture(event.pointerId)) {
|
|
16085
|
-
handle.releasePointerCapture(event.pointerId);
|
|
16086
|
-
}
|
|
16087
|
-
}, []);
|
|
16088
|
-
// Растянутая ширина перебивает конфигурационную: последнее слово за тем, кто тянул.
|
|
16089
|
-
const columnWidths = React.useMemo(() => columns.reduce((acc, { attributeName, width }) => ({ ...acc, [attributeName]: widths[attributeName] ?? width }), {}), [columns, widths]);
|
|
16090
|
-
return { columnWidths, onResizeStart, onResizeMove, onResizeEnd };
|
|
16091
|
-
};
|
|
16092
|
-
|
|
16093
16156
|
/**
|
|
16094
16157
|
* Вид таблицы: колонки плюс локальная сортировка.
|
|
16095
16158
|
*
|
|
@@ -16103,19 +16166,23 @@ const useColumnResize = (columns) => {
|
|
|
16103
16166
|
* `width`/`height` — размер собственного бокса таблицы: он ограничивает её саму и прокручивает
|
|
16104
16167
|
* то, что не влезло. Место, отведённое контейнеру, задаётся его же опциями и живёт отдельно.
|
|
16105
16168
|
*
|
|
16106
|
-
* Ширины колонок — тоже вид: конфиг задаёт стартовую, растянутая мышью живёт в
|
|
16107
|
-
*
|
|
16169
|
+
* Ширины колонок — тоже вид: конфиг задаёт стартовую, растянутая мышью живёт здесь и в конфиг
|
|
16170
|
+
* не возвращается.
|
|
16108
16171
|
*/
|
|
16109
16172
|
const useTableView = (elementConfig) => {
|
|
16110
16173
|
const context = React.useContext(StructuredDataContext);
|
|
16111
16174
|
const { sort: sortEnabled, width, height } = elementConfig?.options || {};
|
|
16112
16175
|
const [sort, setSort] = React.useState(null);
|
|
16176
|
+
const [widths, setWidths] = React.useState({});
|
|
16113
16177
|
const schema = context?.schema;
|
|
16114
16178
|
const rows = context?.rows;
|
|
16115
16179
|
const columns = React.useMemo(() => schema ?? [], [schema]);
|
|
16116
16180
|
const sortedRows = React.useMemo(() => sortRows(rows ?? [], sort, schema ?? []), [rows, schema, sort]);
|
|
16117
16181
|
const sizeCss = React.useMemo(() => getTableBoxStyle(width, height), [height, width]);
|
|
16118
|
-
|
|
16182
|
+
// Растянутая мышью ширина живёт только в рантайме и перебивает конфигурационную: последнее
|
|
16183
|
+
// слово за тем, кто тянул. Обратно в конфиг она не пишется.
|
|
16184
|
+
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 })), []);
|
|
16119
16186
|
const onSortToggle = React.useCallback((attributeName) => setSort(current => getNextSort(current, attributeName)), []);
|
|
16120
16187
|
return {
|
|
16121
16188
|
context,
|
|
@@ -16128,9 +16195,7 @@ const useTableView = (elementConfig) => {
|
|
|
16128
16195
|
contentWidth: width != null,
|
|
16129
16196
|
columnWidths,
|
|
16130
16197
|
onSortToggle,
|
|
16131
|
-
|
|
16132
|
-
onResizeMove,
|
|
16133
|
-
onResizeEnd,
|
|
16198
|
+
onColumnResize,
|
|
16134
16199
|
};
|
|
16135
16200
|
};
|
|
16136
16201
|
|
|
@@ -16142,7 +16207,7 @@ const useTableView = (elementConfig) => {
|
|
|
16142
16207
|
*/
|
|
16143
16208
|
const ElementTable = React.memo(({ elementConfig }) => {
|
|
16144
16209
|
const { t } = useGlobalContext();
|
|
16145
|
-
const { context, columns, rows, sort, sortEnabled, sizeCss, contentWidth, columnWidths, onSortToggle,
|
|
16210
|
+
const { context, columns, rows, sort, sortEnabled, sizeCss, contentWidth, columnWidths, onSortToggle, onColumnResize, } = useTableView(elementConfig);
|
|
16146
16211
|
// Узел таблицы держим состоянием, а не ref: отсечка должна встать сразу, как он появится.
|
|
16147
16212
|
const [table, setTable] = React.useState(null);
|
|
16148
16213
|
useHeadOverlap(table);
|
|
@@ -16158,10 +16223,13 @@ const ElementTable = React.memo(({ elementConfig }) => {
|
|
|
16158
16223
|
defaultValue: "Схема данных не задана",
|
|
16159
16224
|
}) }));
|
|
16160
16225
|
}
|
|
16161
|
-
return (jsxRuntime.jsx(TableBox, { "$sizeCss": sizeCss, children: jsxRuntime.jsxs(TableWrapper, { ref: setTable, "$contentWidth": contentWidth, children: [jsxRuntime.jsx(TableHead, { children: jsxRuntime.jsx(TableHeadRow, { columns: columns, sort: sort, sortEnabled: sortEnabled, columnWidths: columnWidths, withActionsColumn: context.canDelete, onSortToggle: onSortToggle,
|
|
16226
|
+
return (jsxRuntime.jsx(TableBox, { "$sizeCss": sizeCss, children: jsxRuntime.jsxs(TableWrapper, { ref: setTable, "$contentWidth": contentWidth, children: [jsxRuntime.jsx(TableHead, { children: jsxRuntime.jsx(TableHeadRow, { columns: columns, sort: sort, sortEnabled: sortEnabled, columnWidths: columnWidths, withActionsColumn: context.canDelete, onSortToggle: onSortToggle, onColumnResize: onColumnResize }) }), jsxRuntime.jsx(TableBody, { children: rows.map(row => (jsxRuntime.jsxs(TableRow, { children: [columns.map((attribute, columnIndex) => (jsxRuntime.jsxs(TableCellWrapper, {
|
|
16162
16227
|
// Стиль колонки из конфига идёт последним: шрифт задан для значений, и ширину
|
|
16163
16228
|
// он не трогает — своих размеров у него нет.
|
|
16164
|
-
style: {
|
|
16229
|
+
style: {
|
|
16230
|
+
...getColumnStyle(columnIndex, columnWidths[attribute.attributeName], attribute.resizable),
|
|
16231
|
+
...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))) })] }) }));
|
|
16165
16233
|
});
|
|
16166
16234
|
|
|
16167
16235
|
const TooltipIcon = styled(uilibGl.Icon).withConfig({ displayName: "TooltipIcon", componentId: "sc-1lkxudm" }) `
|
|
@@ -19630,8 +19698,6 @@ exports.GRID_DRAGGING_ATTR = GRID_DRAGGING_ATTR;
|
|
|
19630
19698
|
exports.GRID_DRAG_SOURCE_ATTR = GRID_DRAG_SOURCE_ATTR;
|
|
19631
19699
|
exports.GRID_DROP_TARGET_ATTR = GRID_DROP_TARGET_ATTR;
|
|
19632
19700
|
exports.GRID_FILL_DEFAULTS = GRID_FILL_DEFAULTS;
|
|
19633
|
-
exports.GRID_HANDLE_ATTR = GRID_HANDLE_ATTR;
|
|
19634
|
-
exports.GRID_HANDLE_PROPS = GRID_HANDLE_PROPS;
|
|
19635
19701
|
exports.GRID_ROW_ID_PREFIX = GRID_ROW_ID_PREFIX;
|
|
19636
19702
|
exports.GlobalContext = GlobalContext;
|
|
19637
19703
|
exports.GlobalProvider = GlobalProvider;
|
|
@@ -19695,6 +19761,8 @@ exports.PresentationPanelWrapper = PresentationPanelWrapper;
|
|
|
19695
19761
|
exports.PresentationWrapper = PresentationWrapper;
|
|
19696
19762
|
exports.ProgressContainer = ProgressContainer;
|
|
19697
19763
|
exports.QUERY_DESCRIPTION_CACHE_TTL = QUERY_DESCRIPTION_CACHE_TTL;
|
|
19764
|
+
exports.RESIZE_HANDLE_ATTR = RESIZE_HANDLE_ATTR;
|
|
19765
|
+
exports.ResizeHandle = ResizeHandle;
|
|
19698
19766
|
exports.RoundedBackgroundContainer = RoundedBackgroundContainer;
|
|
19699
19767
|
exports.SAVE_HOOK_RESULT_DURATION = SAVE_HOOK_RESULT_DURATION;
|
|
19700
19768
|
exports.SERVER_NOTIFICATION_EVENT = SERVER_NOTIFICATION_EVENT;
|
|
@@ -19925,6 +19993,7 @@ exports.useRelatedDataSourceAttributes = useRelatedDataSourceAttributes;
|
|
|
19925
19993
|
exports.useRemoteTask = useRemoteTask;
|
|
19926
19994
|
exports.useRenderElement = useRenderElement;
|
|
19927
19995
|
exports.useResizeBox = useResizeBox;
|
|
19996
|
+
exports.useResizeDrag = useResizeDrag;
|
|
19928
19997
|
exports.useSavePrototypeBuilder = useSavePrototypeBuilder;
|
|
19929
19998
|
exports.useServerNotificationsContext = useServerNotificationsContext;
|
|
19930
19999
|
exports.useShownOtherItems = useShownOtherItems;
|