@evergis/react 4.0.129 → 4.0.130
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/componentTypes.d.ts +1 -1
- package/dist/components/Dashboard/components/AddButton/styled.d.ts +15 -0
- package/dist/components/Dashboard/components/index.d.ts +1 -0
- package/dist/components/Dashboard/containers/AttachmentContainer/styled.d.ts +0 -1
- package/dist/components/Dashboard/containers/StructuredDataContainer/constants.d.ts +2 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/hooks/useStructuredData.d.ts +4 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/styled.d.ts +3 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/utils/filterValue.d.ts +3 -2
- package/dist/components/Dashboard/containers/StructuredDataContainer/utils/viewScroll.d.ts +17 -0
- package/dist/components/Dashboard/elements/ElementTable/components/TableCell.d.ts +1 -1
- package/dist/components/Dashboard/elements/ElementTable/constants.d.ts +5 -0
- package/dist/components/Dashboard/elements/ElementTable/hooks/useCellEditing.d.ts +25 -9
- package/dist/components/Dashboard/elements/ElementTable/hooks/useHeadOverlap.d.ts +15 -0
- package/dist/components/Dashboard/elements/ElementTable/hooks/useSurfaceColor.d.ts +16 -0
- package/dist/components/Dashboard/elements/ElementTable/hooks/useTableView.d.ts +10 -1
- package/dist/components/Dashboard/elements/ElementTable/styled.d.ts +51 -4
- package/dist/components/Dashboard/elements/ElementTable/types.d.ts +5 -0
- package/dist/components/Dashboard/elements/ElementTable/utils/surfaceColor.d.ts +13 -0
- package/dist/components/Dashboard/elements/ElementTable/utils/tableBox.d.ts +20 -0
- package/dist/components/Dashboard/types.d.ts +0 -6
- package/dist/index.js +349 -113
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +350 -115
- package/dist/react.esm.js.map +1 -1
- package/package.json +3 -3
package/dist/react.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
2
|
-
import { IconButton, Flex, transition, Chip, shadows, Description, Divider, Icon, Popup, Menu, IconToggleButton, LinearProgress, Tooltip as Tooltip$1, IconToggle, Preview, LegendToggler, DropdownField, MultiSelectContainer, IconButtonButton, useDragAndDropEffect, FlatButton, DraggableTreeContainer, DraggableTree, FlexSpan, Dialog, DialogTitle, ActionsGroup, DialogContent, DialogActions, RaisedButton, UploaderItemArea, UploaderTitleWrapper, ThemeProvider, darkTheme, CircularProgress, Switch, AutoComplete, Input, Slider, Dropdown, Checkbox, DatePicker, getLocale, H2, Blank, Popover, NumberInput, Uploader, NumberRangeSlider, useAsyncAutocomplete, RangeNumberInput, TreeDropdown, defaultTheme, dateFormat } from '@evergis/uilib-gl';
|
|
3
|
-
import { isValidElement, Fragment, createContext, memo, useRef, useState, useCallback, useEffect, useContext, useMemo, createElement, forwardRef } from 'react';
|
|
4
1
|
import styled, { createGlobalStyle, css, useTheme } from 'styled-components';
|
|
2
|
+
import { Icon, IconButtonInnerChild, IconButton, Flex, transition, Chip, shadows, Description, Divider, Popup, Menu, IconToggleButton, LinearProgress, Tooltip as Tooltip$1, IconToggle, Preview, LegendToggler, DropdownField, MultiSelectContainer, IconButtonButton, useDragAndDropEffect, FlatButton, DraggableTreeContainer, DraggableTree, FlexSpan, Dialog, DialogTitle, ActionsGroup, DialogContent, DialogActions, RaisedButton, UploaderItemArea, UploaderTitleWrapper, ThemeProvider, darkTheme, CircularProgress, Switch, AutoComplete, Input, Slider, Dropdown, Checkbox, DatePicker, getLocale, H2, Blank, Popover, NumberInput, Uploader, NumberRangeSlider, useAsyncAutocomplete, RangeNumberInput, TreeDropdown, defaultTheme, dateFormat } from '@evergis/uilib-gl';
|
|
3
|
+
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
4
|
+
import { isValidElement, Fragment, createContext, memo, useRef, useState, useCallback, useEffect, useContext, useMemo, createElement, useLayoutEffect, forwardRef } from 'react';
|
|
5
5
|
import { lineChartClassNames, BarChart as BarChart$1, barChartClassNames, LineChart, PieChart } from '@evergis/charts';
|
|
6
6
|
import { AttributeType, AttributeIconType, generateId, STORAGE_TOKEN_KEY, parseJwt, STORAGE_REFRESH_TOKEN_KEY, RemoteTaskStatus, AttributeConfigurationType, LayerServiceType, OgcGeometryType, StringSubType } from '@evergis/api';
|
|
7
7
|
import { isNil, isEmpty, uniqueId, isEqual, unescape } from 'lodash';
|
|
@@ -28,6 +28,45 @@ import { Terminal } from '@xterm/xterm';
|
|
|
28
28
|
import { FitAddon } from '@xterm/addon-fit';
|
|
29
29
|
import '@xterm/xterm/css/xterm.css';
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Кнопка «добавить»: серая скруглённая, со значком и подписью. Общая на весь дашборд — вложения
|
|
33
|
+
* и таблица структурированных данных добавляют одинаковой кнопкой, разница только в значке.
|
|
34
|
+
*
|
|
35
|
+
* Размеры сняты с макета (все — в половину его пикселей, макет снят на удвоенной плотности):
|
|
36
|
+
* высота 24, поля 10, просвет между значком и подписью 6, значок 14, подпись 14.
|
|
37
|
+
*
|
|
38
|
+
* Скругление и ширина по содержимому — от самого `IconButton`: он скруглён по умолчанию, а с
|
|
39
|
+
* подписью в детях перестаёт держать фиксированную ширину. Значок ужат до 0.875rem: свой 1rem
|
|
40
|
+
* он заполняет краями, и на макете кружок мельче подписи, а не вровень с ней.
|
|
41
|
+
*
|
|
42
|
+
* Подпись темнее значка: `IconButton` красит и то и другое цветом иконки, но в макете подпись —
|
|
43
|
+
* обычный текст (`textPrimary`), а приглушён только значок.
|
|
44
|
+
*/
|
|
45
|
+
const AddButtonRow = styled(IconButton).withConfig({ displayName: "AddButtonRow", componentId: "sc-3ytj1o" }) `
|
|
46
|
+
padding: 0 0.625rem;
|
|
47
|
+
height: 1.5rem;
|
|
48
|
+
background-color: ${({ theme }) => theme.palette.elementDark};
|
|
49
|
+
font-size: 0.875rem;
|
|
50
|
+
|
|
51
|
+
&:hover {
|
|
52
|
+
background-color: ${({ theme }) => theme.palette.elementDeep};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
${Icon} {
|
|
56
|
+
width: 0.875rem;
|
|
57
|
+
height: 0.875rem;
|
|
58
|
+
|
|
59
|
+
&:after {
|
|
60
|
+
font-size: 0.875rem;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
${IconButtonInnerChild} {
|
|
65
|
+
margin-left: 0.375rem;
|
|
66
|
+
color: ${({ theme }) => theme.palette.textPrimary};
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
|
|
31
70
|
const AddFeatureButton = ({ title, icon = "feature_add" /* , layerName, geometryType*/ }) => {
|
|
32
71
|
// const [, handleAddFeature] = useFeatureCreator(layerName, geometryType);
|
|
33
72
|
const handleAddFeature = () => { };
|
|
@@ -8733,19 +8772,10 @@ const ShowMoreButton$1 = styled.div.withConfig({ displayName: "ShowMoreButton",
|
|
|
8733
8772
|
const AddButtonContainer = styled.div.withConfig({ displayName: "AddButtonContainer", componentId: "sc-1yphz1r" }) `
|
|
8734
8773
|
margin-top: 0.75rem;
|
|
8735
8774
|
`;
|
|
8736
|
-
const
|
|
8737
|
-
padding: 0 0.75rem;
|
|
8738
|
-
height: 1.5rem;
|
|
8739
|
-
background-color: ${({ theme }) => theme.palette.elementDark};
|
|
8740
|
-
|
|
8741
|
-
&:hover {
|
|
8742
|
-
background-color: ${({ theme }) => theme.palette.elementDeep};
|
|
8743
|
-
}
|
|
8744
|
-
`;
|
|
8745
|
-
const HiddenFileInput = styled.input.withConfig({ displayName: "HiddenFileInput", componentId: "sc-kgi0m7" }) `
|
|
8775
|
+
const HiddenFileInput = styled.input.withConfig({ displayName: "HiddenFileInput", componentId: "sc-3apzla" }) `
|
|
8746
8776
|
display: none;
|
|
8747
8777
|
`;
|
|
8748
|
-
const LinkDialogContent = styled.div.withConfig({ displayName: "LinkDialogContent", componentId: "sc-
|
|
8778
|
+
const LinkDialogContent = styled.div.withConfig({ displayName: "LinkDialogContent", componentId: "sc-1kihzpg" }) `
|
|
8749
8779
|
display: flex;
|
|
8750
8780
|
flex-direction: column;
|
|
8751
8781
|
width: 100%;
|
|
@@ -10936,6 +10966,9 @@ const StructuredDataActions = styled(Flex).withConfig({ displayName: "Structured
|
|
|
10936
10966
|
/**
|
|
10937
10967
|
* Область представления. Прокручивается внутри себя, чтобы длинная таблица не растягивала
|
|
10938
10968
|
* контейнер за пределы отведённой ему ячейки; `min-height: 0` разрешает flex-ребёнку сжиматься.
|
|
10969
|
+
*
|
|
10970
|
+
* Собственный бокс таблицы (`options.width`/`height` представления) живёт внутри и на эту
|
|
10971
|
+
* прокрутку не влияет: он ограничивает саму таблицу, а не отведённое контейнером место.
|
|
10939
10972
|
*/
|
|
10940
10973
|
const StructuredDataView = styled(Flex).withConfig({ displayName: "StructuredDataView", componentId: "sc-1ws3t0d" }) `
|
|
10941
10974
|
flex-direction: column;
|
|
@@ -10952,6 +10985,33 @@ const StructuredDataView = styled(Flex).withConfig({ displayName: "StructuredDat
|
|
|
10952
10985
|
*/
|
|
10953
10986
|
const StructuredDataContext = createContext(null);
|
|
10954
10987
|
|
|
10988
|
+
/** Слот представления: единственный ребёнок контейнера, рисующий данные (элемент `table`). */
|
|
10989
|
+
const STRUCTURED_DATA_VIEW_SLOT = "data";
|
|
10990
|
+
/**
|
|
10991
|
+
* Типы атрибутов с редактором ячейки. Атрибут любого другого типа показывается только на чтение,
|
|
10992
|
+
* даже если помечен `isEditable: true` — редактора для него нет.
|
|
10993
|
+
*/
|
|
10994
|
+
const EDITABLE_ATTRIBUTE_TYPES = [
|
|
10995
|
+
AttributeType.String,
|
|
10996
|
+
AttributeType.Int32,
|
|
10997
|
+
AttributeType.Int64,
|
|
10998
|
+
AttributeType.Double,
|
|
10999
|
+
AttributeType.Boolean,
|
|
11000
|
+
AttributeType.DateTime,
|
|
11001
|
+
];
|
|
11002
|
+
/** Типы, для которых ячейка редактируется числовым инпутом. */
|
|
11003
|
+
const NUMBER_EDITOR_TYPES = [
|
|
11004
|
+
AttributeType.Int32,
|
|
11005
|
+
AttributeType.Int64,
|
|
11006
|
+
AttributeType.Double,
|
|
11007
|
+
];
|
|
11008
|
+
/** Типы, значение которых хранится целым числом — дробную часть в них не пускаем. */
|
|
11009
|
+
const INTEGER_ATTRIBUTE_TYPES = [AttributeType.Int32, AttributeType.Int64];
|
|
11010
|
+
/** Тип атрибута, когда его не задали ни конфиг, ни источник. */
|
|
11011
|
+
const DEFAULT_ATTRIBUTE_TYPE = AttributeType.String;
|
|
11012
|
+
/** Сколько миллисекунд висит нотификация об ошибке записи. */
|
|
11013
|
+
const SAVE_ERROR_DURATION = 5000;
|
|
11014
|
+
|
|
10955
11015
|
/**
|
|
10956
11016
|
* Оставляет от произвольного набора свойств только атрибуты схемы. Отсутствующие добавляет
|
|
10957
11017
|
* как `null`: строка всегда имеет одинаковый набор ключей, иначе представление и
|
|
@@ -10989,8 +11049,9 @@ const getEditableProperties = (row, schema) => schema
|
|
|
10989
11049
|
/**
|
|
10990
11050
|
* Строки черновика → значение фильтра `valueType: "features"`.
|
|
10991
11051
|
*
|
|
10992
|
-
* В `properties`
|
|
10993
|
-
*
|
|
11052
|
+
* В `properties` попадает ровно схема: значения по её атрибутам, включая незаполненные. Лишние
|
|
11053
|
+
* ключи черновика (пришли из источника, остались от прежней схемы) наружу не уходят, а объявленный
|
|
11054
|
+
* атрибут уходит всегда. Геометрия не поддерживается — `geometry: null`.
|
|
10994
11055
|
*/
|
|
10995
11056
|
const toFeaturesFilterValue = (rows, schema) => ({
|
|
10996
11057
|
type: "FeatureCollection",
|
|
@@ -11039,14 +11100,17 @@ const useStructuredDataDraft = ({ schema, dataSource, hasDataSource, filterValue
|
|
|
11039
11100
|
}, [applyBaseline, features, hasDataSource, schema]);
|
|
11040
11101
|
// Ручная структура гидратируется из фильтра один раз: дальше значение фильтра пишем мы сами,
|
|
11041
11102
|
// и повторная гидратация только пересоздавала бы ключи строк.
|
|
11103
|
+
//
|
|
11104
|
+
// Флаг взводится по факту гидратации, а не авансом: значение может приехать позже схемы
|
|
11105
|
+
// (восстановленный выбор пользователя — асинхронно, в отличие от `defaultValue` из конфига),
|
|
11106
|
+
// и окно не должно сгорать на пустом первом рендере. Грязный черновик значение не затирает.
|
|
11042
11107
|
useEffect(() => {
|
|
11043
|
-
|
|
11108
|
+
const canHydrate = !hasDataSource && !hydrated.current && !dirtyRef.current && !!schema.length;
|
|
11109
|
+
if (!canHydrate || !isFeaturesFilterValue(filterValue)) {
|
|
11044
11110
|
return;
|
|
11045
11111
|
}
|
|
11046
11112
|
hydrated.current = true;
|
|
11047
|
-
|
|
11048
|
-
applyBaseline(fromFeaturesFilterValue(filterValue, schema));
|
|
11049
|
-
}
|
|
11113
|
+
applyBaseline(fromFeaturesFilterValue(filterValue, schema));
|
|
11050
11114
|
}, [applyBaseline, filterValue, hasDataSource, schema]);
|
|
11051
11115
|
const changeCell = useCallback((key, attributeName, value) => {
|
|
11052
11116
|
setRows(current => current.map(row => row.key === key
|
|
@@ -11069,36 +11133,16 @@ const useStructuredDataDraft = ({ schema, dataSource, hasDataSource, filterValue
|
|
|
11069
11133
|
}, []));
|
|
11070
11134
|
}, []);
|
|
11071
11135
|
const reset = useCallback(() => setRows(baseline.current), []);
|
|
11072
|
-
const commitSaved = useCallback((next) =>
|
|
11136
|
+
const commitSaved = useCallback((next) => {
|
|
11137
|
+
// Сохранённое состояние — наше: значение фильтра теперь пишем мы, и вернувшееся из него
|
|
11138
|
+
// обновление не должно пересоздавать ключи уже показанных строк.
|
|
11139
|
+
hydrated.current = true;
|
|
11140
|
+
applyBaseline(next);
|
|
11141
|
+
}, [applyBaseline]);
|
|
11073
11142
|
const visibleRows = useMemo(() => rows.filter(({ state }) => state !== "deleted"), [rows]);
|
|
11074
11143
|
return { rows, visibleRows, dirty, changeCell, addRow, deleteRow, reset, commitSaved };
|
|
11075
11144
|
};
|
|
11076
11145
|
|
|
11077
|
-
/**
|
|
11078
|
-
* Типы атрибутов с редактором ячейки. Атрибут любого другого типа показывается только на чтение,
|
|
11079
|
-
* даже если помечен `isEditable: true` — редактора для него нет.
|
|
11080
|
-
*/
|
|
11081
|
-
const EDITABLE_ATTRIBUTE_TYPES = [
|
|
11082
|
-
AttributeType.String,
|
|
11083
|
-
AttributeType.Int32,
|
|
11084
|
-
AttributeType.Int64,
|
|
11085
|
-
AttributeType.Double,
|
|
11086
|
-
AttributeType.Boolean,
|
|
11087
|
-
AttributeType.DateTime,
|
|
11088
|
-
];
|
|
11089
|
-
/** Типы, для которых ячейка редактируется числовым инпутом. */
|
|
11090
|
-
const NUMBER_EDITOR_TYPES = [
|
|
11091
|
-
AttributeType.Int32,
|
|
11092
|
-
AttributeType.Int64,
|
|
11093
|
-
AttributeType.Double,
|
|
11094
|
-
];
|
|
11095
|
-
/** Типы, значение которых хранится целым числом — дробную часть в них не пускаем. */
|
|
11096
|
-
const INTEGER_ATTRIBUTE_TYPES = [AttributeType.Int32, AttributeType.Int64];
|
|
11097
|
-
/** Тип атрибута, когда его не задали ни конфиг, ни источник. */
|
|
11098
|
-
const DEFAULT_ATTRIBUTE_TYPE = AttributeType.String;
|
|
11099
|
-
/** Сколько миллисекунд висит нотификация об ошибке записи. */
|
|
11100
|
-
const SAVE_ERROR_DURATION = 5000;
|
|
11101
|
-
|
|
11102
11146
|
/**
|
|
11103
11147
|
* Применяет черновик к слою источника: удаление → обновление → создание.
|
|
11104
11148
|
*
|
|
@@ -11265,13 +11309,19 @@ const useStructuredDataSchema = (type, elementConfig) => {
|
|
|
11265
11309
|
* Вид источника на права правки не влияет — от него зависит только адресат «Сохранить». Слой
|
|
11266
11310
|
* принимает запись через features-API, источник без `layerName` (EQL, python-скрипт, внешний
|
|
11267
11311
|
* url) не принимает ничего, и правка такой таблицы уходит только в фильтр.
|
|
11312
|
+
*
|
|
11313
|
+
* Значение фильтра читается так же, как его читают остальные потребители дашборда: выбор
|
|
11314
|
+
* пользователя, а пока его нет — `defaultValue` из конфига фильтра. Общего стейта, залитого
|
|
11315
|
+
* дефолтами, в дашборде нет, поэтому фолбэк делает каждый потребитель сам.
|
|
11268
11316
|
*/
|
|
11269
11317
|
const useStructuredData = (type, elementConfig) => {
|
|
11270
11318
|
const { filters } = useWidgetContext(type);
|
|
11319
|
+
const { currentPage } = useWidgetPage(type);
|
|
11271
11320
|
const { relatedDataSource, filterName, editMode } = elementConfig?.options || {};
|
|
11272
11321
|
const { schema, dataSource, layerName } = useStructuredDataSchema(type, elementConfig);
|
|
11273
11322
|
const hasDataSource = !!relatedDataSource;
|
|
11274
|
-
const
|
|
11323
|
+
const configFilter = useMemo(() => getConfigFilter(filterName, currentPage?.filters), [currentPage?.filters, filterName]);
|
|
11324
|
+
const filterValue = useMemo(() => (filterName ? filters?.[filterName]?.value ?? configFilter?.defaultValue : undefined), [configFilter?.defaultValue, filterName, filters]);
|
|
11275
11325
|
const { rows, visibleRows, dirty, changeCell, addRow, deleteRow, reset, commitSaved } = useStructuredDataDraft({
|
|
11276
11326
|
schema,
|
|
11277
11327
|
dataSource,
|
|
@@ -11344,7 +11394,7 @@ const StructuredDataContainer = memo(({ type, elementConfig, isVisible, renderEl
|
|
|
11344
11394
|
if (hasError) {
|
|
11345
11395
|
return jsx(DataSourceError, { name: elementConfig?.templateName });
|
|
11346
11396
|
}
|
|
11347
|
-
return (jsxs(ContainerRoot, { ...root, children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxs(Container, { ...body, isColumn: true, children: [jsx(StructuredDataView, { children: jsx(StructuredDataContext.Provider, { value: contextValue, children: renderElement({ id:
|
|
11397
|
+
return (jsxs(ContainerRoot, { ...root, children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxs(Container, { ...body, isColumn: true, children: [jsx(StructuredDataView, { children: jsx(StructuredDataContext.Provider, { value: contextValue, children: renderElement({ id: STRUCTURED_DATA_VIEW_SLOT }) }) }), canEdit && (jsxs(StructuredDataToolbar, { children: [jsx(StructuredDataActions, { children: jsx(AddButtonRow, { kind: "feature_add", tabIndex: 0, disabled: saving, onClick: onAddRow, children: t("actions.add", { ns: "common", defaultValue: "Добавить" }) }) }), dirty && (jsxs(StructuredDataActions, { children: [jsx(IconButton, { error: true, kind: "close", tabIndex: 0, disabled: saving, title: t("actions.cancel", { ns: "common", defaultValue: "Отменить" }), onClick: onCancel }), jsx(IconButton, { primary: true, kind: "success", tabIndex: 0, disabled: saving, title: t("actions.save", { ns: "common", defaultValue: "Сохранить" }), onClick: onSave })] }))] }))] })), jsx(DeleteRowDialog, { isOpen: isDeleteConfirmOpen, isSourceRow: isDeletingSourceRow, onConfirm: onDeleteConfirm, onCancel: onDeleteCancel })] }));
|
|
11348
11398
|
});
|
|
11349
11399
|
|
|
11350
11400
|
const TabAnchor = styled.div.withConfig({ displayName: "TabAnchor", componentId: "sc-emqf31" }) `
|
|
@@ -14295,28 +14345,86 @@ const ElementSvg = memo(({ type, elementConfig, ...rest }) => {
|
|
|
14295
14345
|
return (jsx(SvgImage, { url: getSvgUrl({ elementConfig, layerInfo, attributes }), width: width, height: height, fontColor: fontColor }));
|
|
14296
14346
|
});
|
|
14297
14347
|
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14348
|
+
/**
|
|
14349
|
+
* Насколько тело таблицы заехало под липкую шапку. Пишется на таблицу при прокрутке, читается
|
|
14350
|
+
* стилем тела: ровно на эту величину тело и отсекается.
|
|
14351
|
+
*/
|
|
14352
|
+
const HEAD_OVERLAP_VARIABLE = "--table-head-overlap";
|
|
14353
|
+
/**
|
|
14354
|
+
* Признак времени в шаблоне `stringFormat.format`.
|
|
14355
|
+
*
|
|
14356
|
+
* Варианты времени в конфигурации атрибута — `hh:mm`, `hh:mm tt`, `hh:mm:ss`, `hh:mm:ss tt`
|
|
14357
|
+
* (см. `timeOptions` в `utils/format`), поэтому достаточно найти часы с минутами.
|
|
14358
|
+
*/
|
|
14359
|
+
const TIME_FORMAT = /hh:mm/;
|
|
14360
|
+
/**
|
|
14361
|
+
* Контейнер порталов `@evergis/uilib-gl` — в него попадают выпадающие слои контролов,
|
|
14362
|
+
* в том числе календарь `DatePicker`. Клик по ним DOM-деревом лежит вне ячейки, поэтому
|
|
14363
|
+
* закрытие редактора по клику снаружи обязано этот контейнер пропускать.
|
|
14364
|
+
*/
|
|
14365
|
+
const PORTAL_ROOT_SELECTOR = "#portal-root";
|
|
14366
|
+
|
|
14367
|
+
/**
|
|
14368
|
+
* Собственный бокс таблицы. Без размеров в `options` представления узел ничего не меняет:
|
|
14369
|
+
* таблица растёт под содержимое, а прокручивает лишнее область представления контейнера.
|
|
14370
|
+
*
|
|
14371
|
+
* С размерами бокс становится её скролл-контейнером — и липкая шапка липнет уже к нему.
|
|
14372
|
+
*/
|
|
14373
|
+
const TableBox = styled.div.withConfig({ displayName: "TableBox", componentId: "sc-19vtvuq" }) `
|
|
14374
|
+
min-width: 0;
|
|
14375
|
+
|
|
14376
|
+
${sizeCssMixin};
|
|
14377
|
+
`;
|
|
14378
|
+
/**
|
|
14379
|
+
* Таблица. По умолчанию втискивается в ширину, которую ей дали: колонкам достаётся то, что есть,
|
|
14380
|
+
* а длинные значения режутся многоточием внутри ячейки.
|
|
14381
|
+
*
|
|
14382
|
+
* `$contentWidth` (ширина бокса задана в `options`) переводит её на ширину по содержимому:
|
|
14383
|
+
* колонки встают по своим значениям, предел ячейки снимается, и всё, что не влезло, уходит
|
|
14384
|
+
* в горизонтальную прокрутку бокса. Иначе вышла бы бессмыслица — бокс с прокруткой, а значения
|
|
14385
|
+
* всё равно с многоточием. `min-width` оставляет таблицу растянутой на весь бокс, когда
|
|
14386
|
+
* содержимого на его ширину не набирается.
|
|
14387
|
+
*
|
|
14388
|
+
* Снятый предел ширины ячейки едет вниз css-переменной, а не правилом по `TableCellWrapper`:
|
|
14389
|
+
* ячейка объявлена ниже по файлу, и селектор по ней отсюда попал бы в TDZ.
|
|
14390
|
+
*/
|
|
14391
|
+
const TableWrapper = styled.table.withConfig({ displayName: "TableWrapper", componentId: "sc-ih9qqq" }) `
|
|
14392
|
+
width: ${({ $contentWidth }) => ($contentWidth ? "max-content" : "100%")};
|
|
14393
|
+
min-width: 100%;
|
|
14394
|
+
/*
|
|
14395
|
+
* Рамки раздельные (со схлопнутым интервалом, поэтому выглядят как схлопнутые). Схлопнутые
|
|
14396
|
+
* рисует сама таблица, а не ячейки, и отсечка тела их не режет: линия строки, уехавшей под
|
|
14397
|
+
* шапку, продолжала бы рисоваться поверх заголовков.
|
|
14398
|
+
*/
|
|
14399
|
+
border-collapse: separate;
|
|
14400
|
+
border-spacing: 0;
|
|
14301
14401
|
font-size: 0.875rem;
|
|
14402
|
+
|
|
14403
|
+
${({ $contentWidth }) => !!$contentWidth &&
|
|
14404
|
+
css `
|
|
14405
|
+
--table-cell-max-width: none;
|
|
14406
|
+
`};
|
|
14302
14407
|
`;
|
|
14303
14408
|
/**
|
|
14304
14409
|
* Шапка липнет к верху области прокрутки — при длинной таблице заголовки остаются видны.
|
|
14305
14410
|
*
|
|
14306
|
-
*
|
|
14307
|
-
*
|
|
14411
|
+
* Своего фона у неё нет и не должно быть: контейнер дашборда красится цветом из конфига, и любой
|
|
14412
|
+
* назначенный шапке цвет остался бы прямоугольником чужого цвета, как только фон контейнера
|
|
14413
|
+
* поменяли. Под шапкой виден фон контейнера, а строки под неё не заезжают — тело отсечено
|
|
14414
|
+
* (см. TableBody и useHeadOverlap).
|
|
14308
14415
|
*/
|
|
14309
|
-
const TableHead = styled.thead.withConfig({ displayName: "TableHead", componentId: "sc-
|
|
14416
|
+
const TableHead = styled.thead.withConfig({ displayName: "TableHead", componentId: "sc-m8fpi" }) `
|
|
14310
14417
|
position: sticky;
|
|
14311
14418
|
top: 0;
|
|
14312
14419
|
z-index: 1;
|
|
14313
14420
|
`;
|
|
14314
|
-
const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", componentId: "sc-
|
|
14421
|
+
const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", componentId: "sc-1m6xil2" }) `
|
|
14315
14422
|
padding: 0.375rem 0.5rem;
|
|
14316
14423
|
text-align: left;
|
|
14317
14424
|
font-weight: 600;
|
|
14318
14425
|
white-space: nowrap;
|
|
14319
14426
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
14427
|
+
/* Рамка принадлежит ячейке (рамки раздельные), поэтому едет вместе с липкой шапкой. */
|
|
14320
14428
|
border-bottom: 1px solid ${({ theme }) => theme.palette.elementDeep};
|
|
14321
14429
|
|
|
14322
14430
|
${({ $sortable }) => $sortable &&
|
|
@@ -14325,25 +14433,50 @@ const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", compo
|
|
|
14325
14433
|
user-select: none;
|
|
14326
14434
|
`}
|
|
14327
14435
|
`;
|
|
14328
|
-
const TableHeadContent = styled.span.withConfig({ displayName: "TableHeadContent", componentId: "sc-
|
|
14436
|
+
const TableHeadContent = styled.span.withConfig({ displayName: "TableHeadContent", componentId: "sc-8hzcop" }) `
|
|
14329
14437
|
display: inline-flex;
|
|
14330
14438
|
align-items: center;
|
|
14331
14439
|
gap: 0.25rem;
|
|
14332
14440
|
`;
|
|
14333
|
-
|
|
14334
|
-
|
|
14441
|
+
/**
|
|
14442
|
+
* Место под значок сортировки. Занято всегда, пока сортировка включена, а сам значок только
|
|
14443
|
+
* прячется: появляясь и исчезая, он менял бы ширину колонки — и таблицу дёргало бы на каждый
|
|
14444
|
+
* клик по заголовку, вместе с телом. Оба направления рисуются значком в 1rem, поэтому
|
|
14445
|
+
* переключение asc/des ширину тоже не трогает.
|
|
14446
|
+
*/
|
|
14447
|
+
const TableSortSlot = styled.span.withConfig({ displayName: "TableSortSlot", componentId: "sc-z378vf" }) `
|
|
14448
|
+
display: inline-flex;
|
|
14449
|
+
visibility: ${({ $active }) => ($active ? "visible" : "hidden")};
|
|
14335
14450
|
`;
|
|
14336
|
-
|
|
14451
|
+
/**
|
|
14452
|
+
* Тело таблицы. Отсекается ровно на то, на сколько его накрыла липкая шапка: строки уходят под
|
|
14453
|
+
* её нижнюю кромку и сквозь прозрачную шапку не проступают. Величину пишет {@link useHeadOverlap},
|
|
14454
|
+
* без неё отсечка нулевая и разметка не меняется.
|
|
14455
|
+
*/
|
|
14456
|
+
const TableBody = styled.tbody.withConfig({ displayName: "TableBody", componentId: "sc-1pxpl5v" }) `
|
|
14457
|
+
clip-path: inset(var(${HEAD_OVERLAP_VARIABLE}, 0px) 0 0 0);
|
|
14458
|
+
`;
|
|
14459
|
+
/**
|
|
14460
|
+
* Строка. Разделитель рисуют её ячейки: собственная рамка строки при раздельных рамках не
|
|
14461
|
+
* рисуется вовсе, а при схлопнутых её рисовала бы таблица — и отсечка тела её бы не резала.
|
|
14462
|
+
*/
|
|
14463
|
+
const TableRow = styled.tr.withConfig({ displayName: "TableRow", componentId: "sc-j62zvd" }) `
|
|
14464
|
+
td {
|
|
14465
|
+
border-bottom: 1px solid ${({ theme }) => theme.palette.elementDeep};
|
|
14466
|
+
}
|
|
14467
|
+
`;
|
|
14468
|
+
const TableCellWrapper = styled.td.withConfig({ displayName: "TableCellWrapper", componentId: "sc-ziu5rk" }) `
|
|
14337
14469
|
padding: 0.125rem 0.25rem;
|
|
14338
14470
|
vertical-align: middle;
|
|
14339
|
-
|
|
14471
|
+
/* Предел снимает заданная ширина: с колонками по содержимому обрезать значение незачем. */
|
|
14472
|
+
max-width: var(--table-cell-max-width, 20rem);
|
|
14340
14473
|
`;
|
|
14341
14474
|
/** Колонка действий: узкая, не растягивается содержимым. */
|
|
14342
|
-
const TableActionsCell = styled(TableCellWrapper).withConfig({ displayName: "TableActionsCell", componentId: "sc-
|
|
14475
|
+
const TableActionsCell = styled(TableCellWrapper).withConfig({ displayName: "TableActionsCell", componentId: "sc-18w13t3" }) `
|
|
14343
14476
|
width: 2rem;
|
|
14344
14477
|
text-align: right;
|
|
14345
14478
|
`;
|
|
14346
|
-
const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "sc-
|
|
14479
|
+
const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "sc-ok630s" }) `
|
|
14347
14480
|
padding: 0.375rem 0.25rem;
|
|
14348
14481
|
/* Та же высота строки, что у редактора — иначе строка подпрыгивала бы по вертикали. */
|
|
14349
14482
|
line-height: 1.25rem;
|
|
@@ -14353,9 +14486,12 @@ const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "
|
|
|
14353
14486
|
`;
|
|
14354
14487
|
/**
|
|
14355
14488
|
* Редактируемая ячейка вне фокуса. Показывает значение по `stringFormat`, а редактор
|
|
14356
|
-
* подставляется
|
|
14489
|
+
* подставляется на фокус — иначе форматирование пришлось бы дублировать внутри инпута.
|
|
14490
|
+
*
|
|
14491
|
+
* Кнопка, а не просто текст, именно ради фокуса: она — таб-стоп ячейки, и Tab по таблице
|
|
14492
|
+
* открывает редактор с курсором внутри.
|
|
14357
14493
|
*/
|
|
14358
|
-
const CellButton = styled.button.withConfig({ displayName: "CellButton", componentId: "sc-
|
|
14494
|
+
const CellButton = styled.button.withConfig({ displayName: "CellButton", componentId: "sc-98k9cz" }) `
|
|
14359
14495
|
width: 100%;
|
|
14360
14496
|
padding: 0.375rem 0.25rem;
|
|
14361
14497
|
line-height: 1.25rem;
|
|
@@ -14374,7 +14510,7 @@ const CellButton = styled.button.withConfig({ displayName: "CellButton", compone
|
|
|
14374
14510
|
border-color: ${({ theme }) => theme.palette.elementDeep};
|
|
14375
14511
|
}
|
|
14376
14512
|
`;
|
|
14377
|
-
const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder", componentId: "sc-
|
|
14513
|
+
const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder", componentId: "sc-7tff41" }) `
|
|
14378
14514
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
14379
14515
|
`;
|
|
14380
14516
|
/**
|
|
@@ -14383,11 +14519,11 @@ const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder",
|
|
|
14383
14519
|
* Копия остаётся в потоке и держит ширину колонки ровно такой, какой она была до клика, —
|
|
14384
14520
|
* иначе таблица дёргалась бы на каждый вход в правку и выход из неё.
|
|
14385
14521
|
*/
|
|
14386
|
-
const CellEditor = styled.div.withConfig({ displayName: "CellEditor", componentId: "sc-
|
|
14522
|
+
const CellEditor = styled.div.withConfig({ displayName: "CellEditor", componentId: "sc-qa22du" }) `
|
|
14387
14523
|
position: relative;
|
|
14388
14524
|
min-height: 2rem;
|
|
14389
14525
|
`;
|
|
14390
|
-
const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId: "sc-
|
|
14526
|
+
const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId: "sc-1i1yvb2" }) `
|
|
14391
14527
|
display: block;
|
|
14392
14528
|
padding: 0.375rem 0.25rem;
|
|
14393
14529
|
/* Рамка повторяет CellButton — с ней высота ячейки в правке совпадает с высотой на чтении. */
|
|
@@ -14396,7 +14532,7 @@ const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId
|
|
|
14396
14532
|
white-space: nowrap;
|
|
14397
14533
|
visibility: hidden;
|
|
14398
14534
|
`;
|
|
14399
|
-
const CellField = styled.div.withConfig({ displayName: "CellField", componentId: "sc-
|
|
14535
|
+
const CellField = styled.div.withConfig({ displayName: "CellField", componentId: "sc-1ww3875" }) `
|
|
14400
14536
|
position: absolute;
|
|
14401
14537
|
inset: 0;
|
|
14402
14538
|
display: flex;
|
|
@@ -14411,7 +14547,7 @@ const CellField = styled.div.withConfig({ displayName: "CellField", componentId:
|
|
|
14411
14547
|
min-width: 0;
|
|
14412
14548
|
}
|
|
14413
14549
|
`;
|
|
14414
|
-
const TableEmpty = styled.div.withConfig({ displayName: "TableEmpty", componentId: "sc-
|
|
14550
|
+
const TableEmpty = styled.div.withConfig({ displayName: "TableEmpty", componentId: "sc-1vamijg" }) `
|
|
14415
14551
|
padding: 0.75rem 0.25rem;
|
|
14416
14552
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
14417
14553
|
`;
|
|
@@ -14431,38 +14567,60 @@ const isSameCellValue = (next, current, type) => {
|
|
|
14431
14567
|
};
|
|
14432
14568
|
|
|
14433
14569
|
/**
|
|
14434
|
-
*
|
|
14570
|
+
* Правка одной ячейки.
|
|
14435
14571
|
*
|
|
14436
|
-
*
|
|
14437
|
-
*
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
*
|
|
14442
|
-
* в том числе календарь `DatePicker`. Клик по ним DOM-деревом лежит вне ячейки, поэтому
|
|
14443
|
-
* закрытие редактора по клику снаружи обязано этот контейнер пропускать.
|
|
14444
|
-
*/
|
|
14445
|
-
const PORTAL_ROOT_SELECTOR = "#portal-root";
|
|
14446
|
-
|
|
14447
|
-
/**
|
|
14448
|
-
* Режим правки одной ячейки: открывается кликом по значению, закрывается кликом снаружи.
|
|
14572
|
+
* Открывает её фокус, а не клик: по таблице ходят Tab-ом, и на каждой ячейке сразу нужно поле
|
|
14573
|
+
* с курсором — кнопка, требующая ещё и Enter, ломала бы весь проход.
|
|
14574
|
+
*
|
|
14575
|
+
* Поэтому состояний три. `focused` — ячейка под фокусом с закрытым редактором, состояние после
|
|
14576
|
+
* Enter/Escape: фокус возвращается на кнопку, но правку заново не открывает (иначе выйти из неё
|
|
14577
|
+
* было бы нечем), а Tab с неё идёт дальше по таблице.
|
|
14449
14578
|
*
|
|
14450
|
-
* Закрывать по
|
|
14451
|
-
* календаря — редактор исчезал бы раньше, чем календарь успевал открыться.
|
|
14452
|
-
* `
|
|
14453
|
-
*
|
|
14579
|
+
* Закрывать правку по любому уходу фокуса нельзя: DatePicker уводит его из поля уже на клике по
|
|
14580
|
+
* иконке календаря — редактор исчезал бы раньше, чем календарь успевал открыться. Клавиатурный
|
|
14581
|
+
* уход видно по `relatedTarget` (фокус ушёл на соседнюю ячейку), мышиный ловит `mousedown`
|
|
14582
|
+
* снаружи. Клики внутри портала (`#portal-root`) считаем «своими»: выпадающие слои контролов
|
|
14583
|
+
* uilib живут именно там, вне DOM-поддерева ячейки.
|
|
14454
14584
|
*/
|
|
14455
14585
|
const useCellEditing = () => {
|
|
14456
|
-
const [
|
|
14586
|
+
const [mode, setMode] = useState("idle");
|
|
14587
|
+
const buttonRef = useRef(null);
|
|
14457
14588
|
const editorRef = useRef(null);
|
|
14458
|
-
const
|
|
14459
|
-
//
|
|
14460
|
-
// из
|
|
14461
|
-
const
|
|
14462
|
-
|
|
14463
|
-
|
|
14589
|
+
const editing = mode === "editing";
|
|
14590
|
+
// Фокус на закрытой ячейке — это уже правка. Из `focused` не открываем: фокус туда только что
|
|
14591
|
+
// вернули из редактора, и Escape перестал бы работать.
|
|
14592
|
+
const onFocus = useCallback(() => setMode(current => (current === "idle" ? "editing" : current)), []);
|
|
14593
|
+
// Переход в правку убирает саму кнопку — её прощальный blur эту правку закрывать не должен.
|
|
14594
|
+
const onBlur = useCallback(() => setMode(current => (current === "editing" ? current : "idle")), []);
|
|
14595
|
+
// Клик открывает правку и тогда, когда фокус на ячейке уже стоит — то есть после Enter/Escape.
|
|
14596
|
+
const onClick = useCallback(() => setMode("editing"), []);
|
|
14597
|
+
// Enter и Escape закрывают редактор, оставляя фокус на ячейке: значение записано в черновик
|
|
14598
|
+
// на каждый ввод, отдельного «применить» нет.
|
|
14599
|
+
const onEditorKeyDown = useCallback((event) => {
|
|
14600
|
+
if (event.key !== "Enter" && event.key !== "Escape") {
|
|
14601
|
+
return;
|
|
14602
|
+
}
|
|
14603
|
+
// Гасим действие по умолчанию: у Enter это «нажать то, что в фокусе», а фокус браузер смотрит
|
|
14604
|
+
// уже после обработчиков — к тому моменту он вернулся на кнопку ячейки, и правка открылась бы
|
|
14605
|
+
// заново тем же нажатием.
|
|
14606
|
+
event.preventDefault();
|
|
14607
|
+
setMode("focused");
|
|
14608
|
+
}, []);
|
|
14609
|
+
const onEditorBlur = useCallback(({ relatedTarget }) => {
|
|
14610
|
+
const inside = editorRef.current?.contains(relatedTarget) || !!relatedTarget?.closest(PORTAL_ROOT_SELECTOR);
|
|
14611
|
+
// Фокус «в никуда» уходом не считаем: так ведут себя внутренности DatePicker.
|
|
14612
|
+
if (!relatedTarget || inside) {
|
|
14613
|
+
return;
|
|
14464
14614
|
}
|
|
14615
|
+
setMode("idle");
|
|
14465
14616
|
}, []);
|
|
14617
|
+
// Выход из редактора возвращает фокус ячейке: иначе он падал бы в body, и следующий Tab пошёл
|
|
14618
|
+
// бы с начала страницы.
|
|
14619
|
+
useEffect(() => {
|
|
14620
|
+
if (mode === "focused") {
|
|
14621
|
+
buttonRef.current?.focus();
|
|
14622
|
+
}
|
|
14623
|
+
}, [mode]);
|
|
14466
14624
|
useEffect(() => {
|
|
14467
14625
|
if (!editing) {
|
|
14468
14626
|
return undefined;
|
|
@@ -14472,24 +14630,26 @@ const useCellEditing = () => {
|
|
|
14472
14630
|
if (editorRef.current?.contains(node) || node?.closest?.(PORTAL_ROOT_SELECTOR)) {
|
|
14473
14631
|
return;
|
|
14474
14632
|
}
|
|
14475
|
-
|
|
14633
|
+
setMode("idle");
|
|
14476
14634
|
};
|
|
14477
14635
|
document.addEventListener("mousedown", onDocumentMouseDown);
|
|
14478
14636
|
return () => document.removeEventListener("mousedown", onDocumentMouseDown);
|
|
14479
14637
|
}, [editing]);
|
|
14480
|
-
|
|
14638
|
+
const buttonProps = useMemo(() => ({ ref: buttonRef, onFocus, onBlur, onClick }), [onBlur, onClick, onFocus]);
|
|
14639
|
+
const editorProps = useMemo(() => ({ ref: editorRef, onBlur: onEditorBlur, onKeyDown: onEditorKeyDown }), [onEditorBlur, onEditorKeyDown]);
|
|
14640
|
+
return { editing, buttonProps, editorProps };
|
|
14481
14641
|
};
|
|
14482
14642
|
|
|
14483
14643
|
/**
|
|
14484
14644
|
* Ячейка таблицы.
|
|
14485
14645
|
*
|
|
14486
|
-
* Вне фокуса значение всегда показано через `stringFormat
|
|
14646
|
+
* Вне фокуса значение всегда показано через `stringFormat`, редактор подставляется на фокус.
|
|
14487
14647
|
* Иначе форматирование (округление, разряды, единицы) пришлось бы дублировать внутри инпута,
|
|
14488
14648
|
* а вводить в отформатированное поле нельзя.
|
|
14489
14649
|
*/
|
|
14490
14650
|
const TableCell = memo(({ attribute, row, canEdit, onChange }) => {
|
|
14491
14651
|
const { t, language } = useGlobalContext();
|
|
14492
|
-
const { editing,
|
|
14652
|
+
const { editing, buttonProps, editorProps } = useCellEditing();
|
|
14493
14653
|
const { attributeName, type, isEditable, stringFormat } = attribute;
|
|
14494
14654
|
const value = row.properties[attributeName];
|
|
14495
14655
|
const handleChange = useCallback((next) => {
|
|
@@ -14518,22 +14678,53 @@ const TableCell = memo(({ attribute, row, canEdit, onChange }) => {
|
|
|
14518
14678
|
return jsx(CellText, { title: formatted, children: formatted || jsx(CellPlaceholder, { children: "\u2014" }) });
|
|
14519
14679
|
}
|
|
14520
14680
|
if (!editing) {
|
|
14521
|
-
return (jsx(CellButton, { type: "button",
|
|
14681
|
+
return (jsx(CellButton, { type: "button", ...buttonProps, children: formatted || jsx(CellPlaceholder, { children: "\u2014" }) }));
|
|
14522
14682
|
}
|
|
14523
14683
|
const renderEditor = () => {
|
|
14524
14684
|
if (type === AttributeType.DateTime) {
|
|
14525
|
-
return (jsx(DatePicker, { value: dateValue, locale: getLocale(language), withTime: withTime, withHeader: true, width: "100%", onChange: date => handleChange(date.toISOString()) }));
|
|
14685
|
+
return (jsx(DatePicker, { focus: true, value: dateValue, locale: getLocale(language), withTime: withTime, withHeader: true, width: "100%", onChange: date => handleChange(date.toISOString()) }));
|
|
14526
14686
|
}
|
|
14527
14687
|
if (NUMBER_EDITOR_TYPES.includes(type)) {
|
|
14528
14688
|
return (jsx(NumberInput, { autoFocus: true, value: value === null || value === undefined ? null : Number(value), width: "100%", numeralDecimalScale: INTEGER_ATTRIBUTE_TYPES.includes(type) ? 0 : undefined, onChange: next => handleChange(next) }));
|
|
14529
14689
|
}
|
|
14530
14690
|
return (jsx(Input, { autoFocus: true, value: value === null || value === undefined ? "" : String(value), width: "100%", onChange: ({ target }) => handleChange(target.value) }));
|
|
14531
14691
|
};
|
|
14532
|
-
return (jsxs(CellEditor, {
|
|
14692
|
+
return (jsxs(CellEditor, { ...editorProps, children: [jsx(CellGhost, { children: formatted || "—" }), jsx(CellField, { children: renderEditor() })] }));
|
|
14533
14693
|
});
|
|
14534
14694
|
|
|
14535
14695
|
const ContainerLoading = () => (jsx(Flex, { alignContent: "center", justifyContent: "center", width: "100%", children: jsx(CircularProgress, { diameter: 1.5, mono: true }) }));
|
|
14536
14696
|
|
|
14697
|
+
/**
|
|
14698
|
+
* Отсечка тела таблицы по нижней кромке липкой шапки.
|
|
14699
|
+
*
|
|
14700
|
+
* Шапка прозрачная — фон контейнера виден сквозь неё, и красить её нечем: цвет контейнера задаётся
|
|
14701
|
+
* конфигом и меняется. Значит, строки не должны под неё заезжать в принципе. Тело для этого
|
|
14702
|
+
* отсекается (`clip-path`) ровно на то, на сколько шапка его накрыла: низ шапки минус верх тела.
|
|
14703
|
+
*
|
|
14704
|
+
* Разница считается по факту, а не по величине прокрутки: она одинаково верна и когда прокручивает
|
|
14705
|
+
* собственный бокс таблицы, и когда её прокручивает область представления контейнера. Пока
|
|
14706
|
+
* не прокручено, низ шапки совпадает с верхом тела — отсекать нечего.
|
|
14707
|
+
*
|
|
14708
|
+
* Прокрутка не всплывает, но проходит фазу перехвата, поэтому слушаем документ: какой именно
|
|
14709
|
+
* предок прокручивается, знать не нужно.
|
|
14710
|
+
*/
|
|
14711
|
+
const useHeadOverlap = (table) => {
|
|
14712
|
+
useLayoutEffect(() => {
|
|
14713
|
+
if (!table) {
|
|
14714
|
+
return undefined;
|
|
14715
|
+
}
|
|
14716
|
+
const update = () => {
|
|
14717
|
+
const head = table.tHead?.getBoundingClientRect();
|
|
14718
|
+
const body = table.tBodies[0]?.getBoundingClientRect();
|
|
14719
|
+
const overlap = head && body ? Math.max(0, head.bottom - body.top) : 0;
|
|
14720
|
+
table.style.setProperty(HEAD_OVERLAP_VARIABLE, `${overlap}px`);
|
|
14721
|
+
};
|
|
14722
|
+
update();
|
|
14723
|
+
document.addEventListener("scroll", update, { capture: true, passive: true });
|
|
14724
|
+
return () => document.removeEventListener("scroll", update, { capture: true });
|
|
14725
|
+
}, [table]);
|
|
14726
|
+
};
|
|
14727
|
+
|
|
14537
14728
|
const compareValues = (left, right, type) => {
|
|
14538
14729
|
if (NUMERIC_ATTRIBUTE_TYPES.includes(type)) {
|
|
14539
14730
|
return Number(left) - Number(right);
|
|
@@ -14578,28 +14769,66 @@ const getNextSort = (current, attributeName) => {
|
|
|
14578
14769
|
};
|
|
14579
14770
|
|
|
14580
14771
|
/**
|
|
14581
|
-
*
|
|
14772
|
+
* Css собственного бокса таблицы: размер из `options` представления плюс прокрутка того,
|
|
14773
|
+
* что в этот размер не влез.
|
|
14774
|
+
*
|
|
14775
|
+
* Размеров нет — нет и бокса: таблица занимает столько, сколько просит содержимое, а лишнее,
|
|
14776
|
+
* как и раньше, уходит в прокрутку области представления контейнера.
|
|
14777
|
+
*
|
|
14778
|
+
* Проценты работают только по ширине. Между областью представления и таблицей стоит блочная
|
|
14779
|
+
* обёртка элемента (`ElementValueWrapper`) с высотой `auto`, и `height: "100%"` в ней не
|
|
14780
|
+
* разрешается — вертикальный предел задают конкретные единицы (`240`, `"20rem"`, `"50vh"`),
|
|
14781
|
+
* а «занять всю выданную высоту» остаётся за `options.height` контейнера.
|
|
14782
|
+
*
|
|
14783
|
+
* `contain: inline-size` идёт в пару к fill-ширине: сама по себе она предком не ограничена
|
|
14784
|
+
* (процент от раскладки, которая меряет себя содержимым, вырождается в `auto`), и таблица
|
|
14785
|
+
* распирала бы ряд плиток или трек `auto` изнутри. С containment вклад бокса в ширину предка
|
|
14786
|
+
* обнуляется: ширину он берёт снаружи, а внутрь по ней не смотрят.
|
|
14787
|
+
*/
|
|
14788
|
+
const getTableBoxStyle = (width, height) => {
|
|
14789
|
+
if (width == null && height == null) {
|
|
14790
|
+
return undefined;
|
|
14791
|
+
}
|
|
14792
|
+
return {
|
|
14793
|
+
...getWrapperSizeStyle({ width, height, overflow: "auto" }),
|
|
14794
|
+
...(isFillSize(width) && { contain: "inline-size" }),
|
|
14795
|
+
};
|
|
14796
|
+
};
|
|
14797
|
+
|
|
14798
|
+
/**
|
|
14799
|
+
* Вид таблицы: колонки плюс локальная сортировка.
|
|
14800
|
+
*
|
|
14801
|
+
* Набор и порядок колонок — это схема контейнера (`attributesDescription`) как есть: показываем
|
|
14802
|
+
* ровно то, что описано, и в том же порядке. Своего отбора у представления нет — иначе описанный
|
|
14803
|
+
* атрибут и видимая колонка расходились бы, а в фильтр всё равно уходят все атрибуты схемы.
|
|
14582
14804
|
*
|
|
14583
14805
|
* Сортировка живёт здесь, а не в контейнере: она ничего не меняет в данных и не должна
|
|
14584
14806
|
* влиять на порядок строк, уходящих в фильтр.
|
|
14807
|
+
*
|
|
14808
|
+
* `width`/`height` — размер собственного бокса таблицы: он ограничивает её саму и прокручивает
|
|
14809
|
+
* то, что не влезло. Место, отведённое контейнеру, задаётся его же опциями и живёт отдельно.
|
|
14585
14810
|
*/
|
|
14586
14811
|
const useTableView = (elementConfig) => {
|
|
14587
14812
|
const context = useContext(StructuredDataContext);
|
|
14588
|
-
const {
|
|
14813
|
+
const { sort: sortEnabled, width, height } = elementConfig?.options || {};
|
|
14589
14814
|
const [sort, setSort] = useState(null);
|
|
14590
14815
|
const schema = context?.schema;
|
|
14591
14816
|
const rows = context?.rows;
|
|
14592
|
-
const columns = useMemo(() =>
|
|
14593
|
-
if (!columnNames?.length) {
|
|
14594
|
-
return schema ?? [];
|
|
14595
|
-
}
|
|
14596
|
-
return columnNames
|
|
14597
|
-
.map(columnName => schema?.find(({ attributeName }) => attributeName === columnName))
|
|
14598
|
-
.filter(Boolean);
|
|
14599
|
-
}, [columnNames, schema]);
|
|
14817
|
+
const columns = useMemo(() => schema ?? [], [schema]);
|
|
14600
14818
|
const sortedRows = useMemo(() => sortRows(rows ?? [], sort, schema ?? []), [rows, schema, sort]);
|
|
14819
|
+
const sizeCss = useMemo(() => getTableBoxStyle(width, height), [height, width]);
|
|
14601
14820
|
const onSortToggle = useCallback((attributeName) => setSort(current => getNextSort(current, attributeName)), []);
|
|
14602
|
-
return {
|
|
14821
|
+
return {
|
|
14822
|
+
context,
|
|
14823
|
+
columns,
|
|
14824
|
+
rows: sortedRows,
|
|
14825
|
+
sort,
|
|
14826
|
+
sortEnabled: !!sortEnabled,
|
|
14827
|
+
sizeCss,
|
|
14828
|
+
// Ширина задана — колонки по содержимому: лишнее уходит в прокрутку бокса, а не в многоточие.
|
|
14829
|
+
contentWidth: width != null,
|
|
14830
|
+
onSortToggle,
|
|
14831
|
+
};
|
|
14603
14832
|
};
|
|
14604
14833
|
|
|
14605
14834
|
/**
|
|
@@ -14610,7 +14839,10 @@ const useTableView = (elementConfig) => {
|
|
|
14610
14839
|
*/
|
|
14611
14840
|
const ElementTable = memo(({ elementConfig }) => {
|
|
14612
14841
|
const { t } = useGlobalContext();
|
|
14613
|
-
const { context, columns, rows, sort, sortEnabled, onSortToggle } = useTableView(elementConfig);
|
|
14842
|
+
const { context, columns, rows, sort, sortEnabled, sizeCss, contentWidth, onSortToggle } = useTableView(elementConfig);
|
|
14843
|
+
// Узел таблицы держим состоянием, а не ref: отсечка должна встать сразу, как он появится.
|
|
14844
|
+
const [table, setTable] = useState(null);
|
|
14845
|
+
useHeadOverlap(table);
|
|
14614
14846
|
if (!context) {
|
|
14615
14847
|
return null;
|
|
14616
14848
|
}
|
|
@@ -14623,7 +14855,10 @@ const ElementTable = memo(({ elementConfig }) => {
|
|
|
14623
14855
|
defaultValue: "Схема данных не задана",
|
|
14624
14856
|
}) }));
|
|
14625
14857
|
}
|
|
14626
|
-
return (
|
|
14858
|
+
return (jsx(TableBox, { "$sizeCss": sizeCss, children: jsxs(TableWrapper, { ref: setTable, "$contentWidth": contentWidth, children: [jsx(TableHead, { children: jsxs("tr", { children: [columns.map(({ attributeName, alias, description }) => {
|
|
14859
|
+
const sorted = sort?.attributeName === attributeName;
|
|
14860
|
+
return (jsx(TableHeadCell, { title: description || alias, "$sortable": sortEnabled, 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" }) }))] }) }, attributeName));
|
|
14861
|
+
}), context.canEdit && jsx(TableHeadCell, {})] }) }), jsx(TableBody, { children: rows.map(row => (jsxs(TableRow, { children: [columns.map(attribute => (jsx(TableCellWrapper, { children: jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }) }, attribute.attributeName))), context.canEdit && (jsx(TableActionsCell, { children: jsx(IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }) }));
|
|
14627
14862
|
});
|
|
14628
14863
|
|
|
14629
14864
|
const TooltipIcon = styled(Icon).withConfig({ displayName: "TooltipIcon", componentId: "sc-1lkxudm" }) `
|
|
@@ -17814,5 +18049,5 @@ const DEFAULT_HEATMAP_STYLE = {
|
|
|
17814
18049
|
],
|
|
17815
18050
|
};
|
|
17816
18051
|
|
|
17817
|
-
export { ALIGNMENTS, ALIGN_ITEMS, ATTRIBUTE_ICON_ELEMENT_TYPES, AddFeatureButton, AddFeatureContainer, AlertIconContainer, AttachmentContainer, AttributeGalleryContainer, AttributeLabel, BASE_CONTAINER_STYLE, BaseMapTheme, CHART_TYPES, COMPACT_FRACTION_DIGITS, CONFIG_PAGES_ID, CONFIG_PAGE_ID, CONTAINERS_GROUP_DEFAULTS, CONTAINER_BODY_ATTRIBUTE, CONTAINER_BODY_FILL_STYLE, CameraContainer, Chart, ChartContainer, ChartLegend, ChartLoading, Container, ContainerChildren, ContainerLoading, ContainerRoot, ContainerTemplate, ContainerWrapper, ContainersGroupContainer, DEFAULT_ATTRIBUTE_NAME, DEFAULT_BARCHART_RADIUS, DEFAULT_BASE_MAP, DEFAULT_BLUR, DEFAULT_CHART_ANGLE, DEFAULT_CHART_HEIGHT, DEFAULT_CHART_WIDTH, DEFAULT_CIRCLE_RADIUS, DEFAULT_CIRCLE_STROKE_WIDTH, DEFAULT_CIRCLE_STYLE, DEFAULT_COLOR, DEFAULT_DASHBOARD_CONFIG, DEFAULT_DATA_SOURCE_LIMIT, DEFAULT_DROPDOWN_WIDTH, DEFAULT_FILL_EXTRUSION_BASE, DEFAULT_FILL_EXTRUSION_HEIGHT, DEFAULT_FILL_EXTRUSION_STYLE, DEFAULT_FILL_EXTRUSION_VERTICAL_GRADIENT, DEFAULT_FILL_STYLE, DEFAULT_FILTER_PADDING, DEFAULT_GRID_GAP, DEFAULT_HEATMAP_COLOR, DEFAULT_HEATMAP_INTENSITY, DEFAULT_HEATMAP_RADIUS, DEFAULT_HEATMAP_STYLE, DEFAULT_HEATMAP_WEIGHT, DEFAULT_ICON_ANCHOR, DEFAULT_ICON_OVERLAP, DEFAULT_ICON_PADDING, DEFAULT_ICON_ROTATE, DEFAULT_ICON_SIZE, DEFAULT_ID_ATTRIBUTE_NAME, DEFAULT_LAT, DEFAULT_LINE_CAP, DEFAULT_LINE_JOIN, DEFAULT_LINE_STYLE, DEFAULT_LINE_WIDTH, DEFAULT_LNG, DEFAULT_OPACITY, DEFAULT_PAGES_CONFIG, DEFAULT_PIECHART_RADIUS, DEFAULT_SYMBOL_COLOR, DEFAULT_SYMBOL_HALO_COLOR, DEFAULT_SYMBOL_PLACEMENT, DEFAULT_SYMBOL_SPACING, DEFAULT_SYMBOL_STYLE, DEFAULT_TEXT_ANCHOR, DEFAULT_TEXT_JUSTIFY, DEFAULT_TEXT_SIZE, DEFAULT_TEXT_TRANSFORM, DEFAULT_TRACK_FR, DEFAULT_TRANSLATE, DEFAULT_ZOOM, DRAG_THRESHOLD_PX, Dashboard, DashboardCheckbox, DashboardChip, DashboardContent, DashboardContext, DashboardDefaultHeader, DashboardHeader, DashboardLoading, DashboardPlaceholder, DashboardPlaceholderWrap, DashboardProvider, DashboardWrapper, DataSourceContainer, DataSourceError, DataSourceErrorContainer, DataSourceInnerContainer, DataSourceProgressContainer, DateFormat, DefaultAttributesContainer, DefaultHeaderContainer, DefaultHeaderWrapper, DividerContainer, EMPTY_DATA_SOURCE_LAYER_INFO, EditGeometryType, ElementButton, ElementCamera, ElementChart, ElementChips, ElementControl, ElementIcon, ElementImage, ElementLegend, ElementLink, ElementMarkdown, ElementSlideshow, ElementSvg, ElementTable, ElementTooltip, ElementValueWrapper, ExpandableTitle, FEATURE_CARD_DEFAULT_COLORS, FEATURE_CARD_OTHER_COLOR, FILL_SIZE, FILTERED_VALUE_OPACITY, FILTER_PREFIX, FR_PRECISION, FeatureCardBackgroundHeader, FeatureCardButtons, FeatureCardContext, FeatureCardDefaultHeader, FeatureCardHeader, FeatureCardProvider, FeatureCardSlideshowHeader, FeatureCardTitle, FeatureControls, FeatureTitleContainer, FiltersContainer, GEOMETRY_ATTRIBUTE, GRID_AUTO_FILL_DEFAULTS, GRID_CELL_ATTR, GRID_CELL_ID_PREFIX, GRID_DRAGGING_ATTR, GRID_DRAG_SOURCE_ATTR, GRID_DROP_TARGET_ATTR, GRID_FILL_DEFAULTS, GRID_HANDLE_ATTR, GRID_HANDLE_PROPS, GRID_ROW_ID_PREFIX, GlobalContext, GlobalProvider, GridRowContainer, HANDLE_BLEED_PX, Header, HeaderContainer, HeaderFontColorMixin, HeaderFrontView, HeaderTemplate, HeaderTitleContainer, HiddenTitleItems, IconContainer, ImageContainer, LEFT_PANEL_HEADER_HEIGHT, Layer, LayerDescription, LayerGroupList, LayerIcon, LayerIconContainer, LayerListContainer, LayerTree, LayersContainer, LayersListWrapper, LinearProgressContainer, LogTerminal, LogoContainer, MAX_CHART_WIDTH, MAX_TRACKS, MIN_TRACK_PX, MIN_TRACK_RATIO, Map$1 as Map, MapContext, MapProvider, NO_CELL_DRAG_SELECTOR, NO_CONTENT_VALUE, NUMERIC_ATTRIBUTE_TYPES, NoLiveSnapshotContainer, OBJECT_FITS, OVERFLOWS, OneColumnContainer, POLL_SUBTASK_INTERVAL_MS, POLL_SUBTASK_TIMEOUT_MS, PROVIDER_PREFIX, PageNavigator, PageTitle, PageTitleContainer, PagesContainer, Pagination, PresentationHeader, PresentationHeaderButtons, PresentationHeaderTools, PresentationPanelContainer, PresentationPanelWrapper, PresentationWrapper, ProgressContainer, ProviderPrefix, QUERY_DESCRIPTION_CACHE_TTL, RoundedBackgroundContainer, SAVE_HOOK_RESULT_DURATION, SERVER_NOTIFICATION_EVENT, STACK_BAR_TOTAL_HEIGHT, ScalingFactor, ServerNotificationsContext, ServerNotificationsProvider, SlideshowContainer, SmallPreviewContainer$1 as SmallPreviewContainer, SmallPreviewControl, SmallPreviewCounter, SmallPreviewImages, SmallPreviewLeft, SmallPreviewRight, StackBar, StructuredDataContainer, SvgImage, TILE_ALIGNMENTS, TIME_ZONE_FORMAT, TITLE_SLOT_IDS, TabsContainer, TextTrim, ThemeName, TitleContainer, TopContainer, TopContainerButtons, TwoColumnContainer, UploadContainer, VIEW_MODES, WidgetType, addDataSource, addDataSources, adjustColor, applyFiltersToCondition, applyQueryFilters, applyTreeFilterToCondition, applyVarsToCondition, asAttributeName, asChartId, asContainerId, asDataSourceName, asFilterName, asLayerName, asModalId, asResourceId, asTabId, buildGridTemplate, buildTrackTemplate, checkEqualOrIncludes, checkIsLoading, collectConfigIds, containsNodeId, createConfigLayer, createConfigPage, createGridCell, createGridIdFactory, createGridRow, createNewPageId, createSaveNotificationId, dateOptions, debounce, decimalOpacityToHex, enrichStyleItemsWithIds, enrichStyleModelsWithIds, eqlParametersToPayload, fetchQueryDescription, findAttributeInExpression, findCellContext, formatArea, formatAttributeValue, formatChartRelatedValue, formatConditionValue, formatDataSourceCondition, formatDate$1 as formatDate, formatElementValue, formatLength, formatNumber, formatPolygonMeasure, geometryToEwkt, getActualExtrusionHeight, getAttributeByName, getAttributeConfigurationByName, getAttributeIconElement, getAttributeIconUrl, getAttributeValue, getAttributesConfiguration, getAverageTrackSize, getChartAxes, getChartFilterName, getChartMarkers, getConfigFilter, getContainerComponent, getDashboardHeader, getDataFromAttributes, getDataFromRelatedFeatures, getDataSource, getDataSourceFilterValue, getDataSourceLayerInfo, getDate, getDefaultConfig, getDisplayTemplateNameFromAttribute, getElementValue, getFeatureAttributes, getFeatureCardHeader, getFilterComponent, getFilterSelectedItems, getFilterValue, getFormattedAttributes, getGradientColors, getImageUrl, getLayerClientStyle, getLayerInfo, getLayerInfoAttribute, getLayerInfoFromDataSources, getLayoutChildren, getPagesFromConfig, getPagesFromProjectInfo, getProxyService, getRelatedAttribute, getRenderElement, getResourceUrl, getRootElementId, getSelectedFilterValue, getSlideshowImages, getStyleAttributes, getSvgUrl, getTemplateNameFromAttribute, getThemeByName, getTotalFromAttributes, getTotalFromRelatedFeatures, getTrackSize, getTrackSizeKey, getTrackSizes, getWrapperSizeStyle, hexToRgba, isEmptyElementValue, isEmptyValue, isFeaturesFilterValue, isFillSize, isFrSize, isGridNode, isHiddenEmptyValue, isHookActive, isLayerService, isNotValidSelectedTab, isNumeric, isObject, isProxyService, isRootOwningContainer, isTreeFilterValue, isVisibleContainer, mapNodeById, mergeAttributeConfigurations, metersPerPixel, noMarginMixin, numberOptions, parseFrValue, parseIconNames, parseIconNamesFromClientStyle, pieChartTooltipFromAttributes, pieChartTooltipFromRelatedFeatures, pointOptions, removeDataSource, removeTracks, replaceNodesByIds, rgbToHex, roundFr, roundTotalSum, setLayoutChildren, sizeCssMixin, sliceShownOtherItems, stretchPalette, timeOptions, toCssSize, toFrSize, toPxNumber, toRenderableValue, tooltipNameFromAttributes, tooltipValueFromAttributes, tooltipValueFromRelatedFeatures, transparentizeColor, updateDataSource, useAfterSave, useAppHeight, useAttachmentItems, useAttachmentPreviewImages, useAutoCompleteControl, useBeforeSave, useChartChange, useChartData, useContainerAttributes, useContainerRoot, useCurrentPageLayers, useCustomFeatureSelect, useDashboardHeader, useDataSources, useDebouncedCallback, useDiffPage, useEditGroupAttributes, useEqualTileWidth, useExpandableContainers, useExportPdf, useFeatureSaveHooks, useFetchImageWithAuth, useFetchWithAuth, useGetConfigLayer, useGlobalContext, useHeaderRender, useHideIfEmptyDataSource, useIconsFromLayers, useLayerHiddenAttributes, useLayerParams, useMapContext, useMapDraw, useMapImages, useMaxZoomTo, useProjectDashboardInit, usePythonSandbox, usePythonTask, useRedrawLayer, useRelatedDataSourceAttributes, useRemoteTask, useRenderElement, useResizeBox, useSavePrototypeBuilder, useServerNotificationsContext, useShownOtherItems, useToggle, useUpdateDataSource, useVisibleProjectItems, useWidgetConfig, useWidgetContext, useWidgetFilters, useWidgetPage, useWindowResize, useWrapperSize, useZoomToFeatures, useZoomToPoint, withTrackSize };
|
|
18052
|
+
export { ALIGNMENTS, ALIGN_ITEMS, ATTRIBUTE_ICON_ELEMENT_TYPES, AddButtonRow, AddFeatureButton, AddFeatureContainer, AlertIconContainer, AttachmentContainer, AttributeGalleryContainer, AttributeLabel, BASE_CONTAINER_STYLE, BaseMapTheme, CHART_TYPES, COMPACT_FRACTION_DIGITS, CONFIG_PAGES_ID, CONFIG_PAGE_ID, CONTAINERS_GROUP_DEFAULTS, CONTAINER_BODY_ATTRIBUTE, CONTAINER_BODY_FILL_STYLE, CameraContainer, Chart, ChartContainer, ChartLegend, ChartLoading, Container, ContainerChildren, ContainerLoading, ContainerRoot, ContainerTemplate, ContainerWrapper, ContainersGroupContainer, DEFAULT_ATTRIBUTE_NAME, DEFAULT_BARCHART_RADIUS, DEFAULT_BASE_MAP, DEFAULT_BLUR, DEFAULT_CHART_ANGLE, DEFAULT_CHART_HEIGHT, DEFAULT_CHART_WIDTH, DEFAULT_CIRCLE_RADIUS, DEFAULT_CIRCLE_STROKE_WIDTH, DEFAULT_CIRCLE_STYLE, DEFAULT_COLOR, DEFAULT_DASHBOARD_CONFIG, DEFAULT_DATA_SOURCE_LIMIT, DEFAULT_DROPDOWN_WIDTH, DEFAULT_FILL_EXTRUSION_BASE, DEFAULT_FILL_EXTRUSION_HEIGHT, DEFAULT_FILL_EXTRUSION_STYLE, DEFAULT_FILL_EXTRUSION_VERTICAL_GRADIENT, DEFAULT_FILL_STYLE, DEFAULT_FILTER_PADDING, DEFAULT_GRID_GAP, DEFAULT_HEATMAP_COLOR, DEFAULT_HEATMAP_INTENSITY, DEFAULT_HEATMAP_RADIUS, DEFAULT_HEATMAP_STYLE, DEFAULT_HEATMAP_WEIGHT, DEFAULT_ICON_ANCHOR, DEFAULT_ICON_OVERLAP, DEFAULT_ICON_PADDING, DEFAULT_ICON_ROTATE, DEFAULT_ICON_SIZE, DEFAULT_ID_ATTRIBUTE_NAME, DEFAULT_LAT, DEFAULT_LINE_CAP, DEFAULT_LINE_JOIN, DEFAULT_LINE_STYLE, DEFAULT_LINE_WIDTH, DEFAULT_LNG, DEFAULT_OPACITY, DEFAULT_PAGES_CONFIG, DEFAULT_PIECHART_RADIUS, DEFAULT_SYMBOL_COLOR, DEFAULT_SYMBOL_HALO_COLOR, DEFAULT_SYMBOL_PLACEMENT, DEFAULT_SYMBOL_SPACING, DEFAULT_SYMBOL_STYLE, DEFAULT_TEXT_ANCHOR, DEFAULT_TEXT_JUSTIFY, DEFAULT_TEXT_SIZE, DEFAULT_TEXT_TRANSFORM, DEFAULT_TRACK_FR, DEFAULT_TRANSLATE, DEFAULT_ZOOM, DRAG_THRESHOLD_PX, Dashboard, DashboardCheckbox, DashboardChip, DashboardContent, DashboardContext, DashboardDefaultHeader, DashboardHeader, DashboardLoading, DashboardPlaceholder, DashboardPlaceholderWrap, DashboardProvider, DashboardWrapper, DataSourceContainer, DataSourceError, DataSourceErrorContainer, DataSourceInnerContainer, DataSourceProgressContainer, DateFormat, DefaultAttributesContainer, DefaultHeaderContainer, DefaultHeaderWrapper, DividerContainer, EMPTY_DATA_SOURCE_LAYER_INFO, EditGeometryType, ElementButton, ElementCamera, ElementChart, ElementChips, ElementControl, ElementIcon, ElementImage, ElementLegend, ElementLink, ElementMarkdown, ElementSlideshow, ElementSvg, ElementTable, ElementTooltip, ElementValueWrapper, ExpandableTitle, FEATURE_CARD_DEFAULT_COLORS, FEATURE_CARD_OTHER_COLOR, FILL_SIZE, FILTERED_VALUE_OPACITY, FILTER_PREFIX, FR_PRECISION, FeatureCardBackgroundHeader, FeatureCardButtons, FeatureCardContext, FeatureCardDefaultHeader, FeatureCardHeader, FeatureCardProvider, FeatureCardSlideshowHeader, FeatureCardTitle, FeatureControls, FeatureTitleContainer, FiltersContainer, GEOMETRY_ATTRIBUTE, GRID_AUTO_FILL_DEFAULTS, GRID_CELL_ATTR, GRID_CELL_ID_PREFIX, GRID_DRAGGING_ATTR, GRID_DRAG_SOURCE_ATTR, GRID_DROP_TARGET_ATTR, GRID_FILL_DEFAULTS, GRID_HANDLE_ATTR, GRID_HANDLE_PROPS, GRID_ROW_ID_PREFIX, GlobalContext, GlobalProvider, GridRowContainer, HANDLE_BLEED_PX, Header, HeaderContainer, HeaderFontColorMixin, HeaderFrontView, HeaderTemplate, HeaderTitleContainer, HiddenTitleItems, IconContainer, ImageContainer, LEFT_PANEL_HEADER_HEIGHT, Layer, LayerDescription, LayerGroupList, LayerIcon, LayerIconContainer, LayerListContainer, LayerTree, LayersContainer, LayersListWrapper, LinearProgressContainer, LogTerminal, LogoContainer, MAX_CHART_WIDTH, MAX_TRACKS, MIN_TRACK_PX, MIN_TRACK_RATIO, Map$1 as Map, MapContext, MapProvider, NO_CELL_DRAG_SELECTOR, NO_CONTENT_VALUE, NUMERIC_ATTRIBUTE_TYPES, NoLiveSnapshotContainer, OBJECT_FITS, OVERFLOWS, OneColumnContainer, POLL_SUBTASK_INTERVAL_MS, POLL_SUBTASK_TIMEOUT_MS, PROVIDER_PREFIX, PageNavigator, PageTitle, PageTitleContainer, PagesContainer, Pagination, PresentationHeader, PresentationHeaderButtons, PresentationHeaderTools, PresentationPanelContainer, PresentationPanelWrapper, PresentationWrapper, ProgressContainer, ProviderPrefix, QUERY_DESCRIPTION_CACHE_TTL, RoundedBackgroundContainer, SAVE_HOOK_RESULT_DURATION, SERVER_NOTIFICATION_EVENT, STACK_BAR_TOTAL_HEIGHT, ScalingFactor, ServerNotificationsContext, ServerNotificationsProvider, SlideshowContainer, SmallPreviewContainer$1 as SmallPreviewContainer, SmallPreviewControl, SmallPreviewCounter, SmallPreviewImages, SmallPreviewLeft, SmallPreviewRight, StackBar, StructuredDataContainer, SvgImage, TILE_ALIGNMENTS, TIME_ZONE_FORMAT, TITLE_SLOT_IDS, TabsContainer, TextTrim, ThemeName, TitleContainer, TopContainer, TopContainerButtons, TwoColumnContainer, UploadContainer, VIEW_MODES, WidgetType, addDataSource, addDataSources, adjustColor, applyFiltersToCondition, applyQueryFilters, applyTreeFilterToCondition, applyVarsToCondition, asAttributeName, asChartId, asContainerId, asDataSourceName, asFilterName, asLayerName, asModalId, asResourceId, asTabId, buildGridTemplate, buildTrackTemplate, checkEqualOrIncludes, checkIsLoading, collectConfigIds, containsNodeId, createConfigLayer, createConfigPage, createGridCell, createGridIdFactory, createGridRow, createNewPageId, createSaveNotificationId, dateOptions, debounce, decimalOpacityToHex, enrichStyleItemsWithIds, enrichStyleModelsWithIds, eqlParametersToPayload, fetchQueryDescription, findAttributeInExpression, findCellContext, formatArea, formatAttributeValue, formatChartRelatedValue, formatConditionValue, formatDataSourceCondition, formatDate$1 as formatDate, formatElementValue, formatLength, formatNumber, formatPolygonMeasure, geometryToEwkt, getActualExtrusionHeight, getAttributeByName, getAttributeConfigurationByName, getAttributeIconElement, getAttributeIconUrl, getAttributeValue, getAttributesConfiguration, getAverageTrackSize, getChartAxes, getChartFilterName, getChartMarkers, getConfigFilter, getContainerComponent, getDashboardHeader, getDataFromAttributes, getDataFromRelatedFeatures, getDataSource, getDataSourceFilterValue, getDataSourceLayerInfo, getDate, getDefaultConfig, getDisplayTemplateNameFromAttribute, getElementValue, getFeatureAttributes, getFeatureCardHeader, getFilterComponent, getFilterSelectedItems, getFilterValue, getFormattedAttributes, getGradientColors, getImageUrl, getLayerClientStyle, getLayerInfo, getLayerInfoAttribute, getLayerInfoFromDataSources, getLayoutChildren, getPagesFromConfig, getPagesFromProjectInfo, getProxyService, getRelatedAttribute, getRenderElement, getResourceUrl, getRootElementId, getSelectedFilterValue, getSlideshowImages, getStyleAttributes, getSvgUrl, getTemplateNameFromAttribute, getThemeByName, getTotalFromAttributes, getTotalFromRelatedFeatures, getTrackSize, getTrackSizeKey, getTrackSizes, getWrapperSizeStyle, hexToRgba, isEmptyElementValue, isEmptyValue, isFeaturesFilterValue, isFillSize, isFrSize, isGridNode, isHiddenEmptyValue, isHookActive, isLayerService, isNotValidSelectedTab, isNumeric, isObject, isProxyService, isRootOwningContainer, isTreeFilterValue, isVisibleContainer, mapNodeById, mergeAttributeConfigurations, metersPerPixel, noMarginMixin, numberOptions, parseFrValue, parseIconNames, parseIconNamesFromClientStyle, pieChartTooltipFromAttributes, pieChartTooltipFromRelatedFeatures, pointOptions, removeDataSource, removeTracks, replaceNodesByIds, rgbToHex, roundFr, roundTotalSum, setLayoutChildren, sizeCssMixin, sliceShownOtherItems, stretchPalette, timeOptions, toCssSize, toFrSize, toPxNumber, toRenderableValue, tooltipNameFromAttributes, tooltipValueFromAttributes, tooltipValueFromRelatedFeatures, transparentizeColor, updateDataSource, useAfterSave, useAppHeight, useAttachmentItems, useAttachmentPreviewImages, useAutoCompleteControl, useBeforeSave, useChartChange, useChartData, useContainerAttributes, useContainerRoot, useCurrentPageLayers, useCustomFeatureSelect, useDashboardHeader, useDataSources, useDebouncedCallback, useDiffPage, useEditGroupAttributes, useEqualTileWidth, useExpandableContainers, useExportPdf, useFeatureSaveHooks, useFetchImageWithAuth, useFetchWithAuth, useGetConfigLayer, useGlobalContext, useHeaderRender, useHideIfEmptyDataSource, useIconsFromLayers, useLayerHiddenAttributes, useLayerParams, useMapContext, useMapDraw, useMapImages, useMaxZoomTo, useProjectDashboardInit, usePythonSandbox, usePythonTask, useRedrawLayer, useRelatedDataSourceAttributes, useRemoteTask, useRenderElement, useResizeBox, useSavePrototypeBuilder, useServerNotificationsContext, useShownOtherItems, useToggle, useUpdateDataSource, useVisibleProjectItems, useWidgetConfig, useWidgetContext, useWidgetFilters, useWidgetPage, useWindowResize, useWrapperSize, useZoomToFeatures, useZoomToPoint, withTrackSize };
|
|
17818
18053
|
//# sourceMappingURL=react.esm.js.map
|