ydb-embedded-ui 3.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/components/EntitiesCount/EntitiesCount.tsx +34 -0
  3. package/dist/components/EntitiesCount/i18n/en.json +3 -0
  4. package/dist/components/{AsideNavigation/Settings → EntitiesCount}/i18n/index.ts +2 -2
  5. package/dist/components/EntitiesCount/i18n/ru.json +3 -0
  6. package/dist/components/EntitiesCount/index.ts +1 -0
  7. package/dist/components/Fullscreen/Fullscreen.scss +7 -5
  8. package/dist/components/TabletsOverall/TabletsOverall.tsx +4 -4
  9. package/dist/components/TabletsStatistic/TabletsStatistic.tsx +56 -0
  10. package/dist/components/TabletsStatistic/index.ts +1 -0
  11. package/dist/containers/App/App.scss +4 -12
  12. package/dist/containers/AsideNavigation/AsideNavigation.scss +0 -18
  13. package/dist/containers/AsideNavigation/AsideNavigation.tsx +95 -33
  14. package/dist/containers/Heatmap/Heatmap.scss +0 -7
  15. package/dist/containers/Heatmap/Heatmap.tsx +203 -0
  16. package/dist/containers/Heatmap/HeatmapCanvas/HeatmapCanvas.js +2 -1
  17. package/dist/containers/Heatmap/index.ts +1 -0
  18. package/dist/containers/Node/Node.tsx +1 -1
  19. package/dist/containers/Storage/Storage.js +12 -19
  20. package/dist/containers/Tablets/Tablets.scss +0 -5
  21. package/dist/containers/Tablets/Tablets.tsx +172 -0
  22. package/dist/containers/Tablets/i18n/en.json +6 -0
  23. package/dist/{components/AsideNavigation → containers/Tablets}/i18n/index.ts +1 -1
  24. package/dist/containers/Tablets/i18n/ru.json +6 -0
  25. package/dist/containers/Tablets/index.ts +1 -0
  26. package/dist/containers/TabletsFilters/TabletsFilters.js +4 -8
  27. package/dist/containers/TabletsFilters/TabletsFilters.scss +6 -2
  28. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -8
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -7
  30. package/dist/containers/Tenants/Tenants.js +1 -1
  31. package/dist/containers/UserSettings/UserSettings.tsx +4 -3
  32. package/dist/routes.ts +1 -1
  33. package/dist/store/reducers/{heatmap.js → heatmap.ts} +33 -18
  34. package/dist/store/reducers/settings.js +12 -2
  35. package/dist/types/api/compute.ts +1 -1
  36. package/dist/types/api/schema.ts +16 -3
  37. package/dist/types/store/heatmap.ts +51 -0
  38. package/dist/utils/constants.ts +1 -37
  39. package/dist/utils/getNodesColumns.js +7 -2
  40. package/dist/utils/tablet.ts +53 -0
  41. package/package.json +2 -1
  42. package/dist/components/AsideNavigation/AsideHeader.scss +0 -147
  43. package/dist/components/AsideNavigation/AsideHeader.tsx +0 -389
  44. package/dist/components/AsideNavigation/AsideHeaderFooterItem/AsideHeaderFooterItem.scss +0 -82
  45. package/dist/components/AsideNavigation/AsideHeaderFooterItem/AsideHeaderFooterItem.tsx +0 -138
  46. package/dist/components/AsideNavigation/AsideHeaderFooterSlot/AsideHeaderFooterSlot.tsx +0 -33
  47. package/dist/components/AsideNavigation/AsideHeaderFooterSlot/SlotsContext.tsx +0 -49
  48. package/dist/components/AsideNavigation/AsideHeaderTooltip/AsideHeaderTooltip.scss +0 -16
  49. package/dist/components/AsideNavigation/AsideHeaderTooltip/AsideHeaderTooltip.tsx +0 -37
  50. package/dist/components/AsideNavigation/CompositeBar/CompositeBar.scss +0 -108
  51. package/dist/components/AsideNavigation/CompositeBar/CompositeBar.tsx +0 -282
  52. package/dist/components/AsideNavigation/Content/Content.tsx +0 -35
  53. package/dist/components/AsideNavigation/Drawer/Drawer.scss +0 -76
  54. package/dist/components/AsideNavigation/Drawer/Drawer.tsx +0 -134
  55. package/dist/components/AsideNavigation/Drawer/index.ts +0 -1
  56. package/dist/components/AsideNavigation/Logo/Logo.scss +0 -43
  57. package/dist/components/AsideNavigation/Logo/Logo.tsx +0 -82
  58. package/dist/components/AsideNavigation/Settings/README.md +0 -92
  59. package/dist/components/AsideNavigation/Settings/Settings.scss +0 -128
  60. package/dist/components/AsideNavigation/Settings/Settings.tsx +0 -270
  61. package/dist/components/AsideNavigation/Settings/SettingsMenu/SettingsMenu.scss +0 -78
  62. package/dist/components/AsideNavigation/Settings/SettingsMenu/SettingsMenu.tsx +0 -141
  63. package/dist/components/AsideNavigation/Settings/SettingsSearch/SettingsSearch.tsx +0 -57
  64. package/dist/components/AsideNavigation/Settings/collect-settings.ts +0 -156
  65. package/dist/components/AsideNavigation/Settings/filter-settings.ts +0 -38
  66. package/dist/components/AsideNavigation/Settings/helpers.ts +0 -39
  67. package/dist/components/AsideNavigation/Settings/i18n/en.json +0 -5
  68. package/dist/components/AsideNavigation/Settings/i18n/ru.json +0 -5
  69. package/dist/components/AsideNavigation/Settings/index.ts +0 -1
  70. package/dist/components/AsideNavigation/constants.ts +0 -28
  71. package/dist/components/AsideNavigation/helpers.ts +0 -34
  72. package/dist/components/AsideNavigation/i18n/en.json +0 -4
  73. package/dist/components/AsideNavigation/i18n/ru.json +0 -4
  74. package/dist/components/AsideNavigation/icons.ts +0 -32
  75. package/dist/components/AsideNavigation/types.ts +0 -23
  76. package/dist/components/TabletsStatistic/TabletsStatistic.js +0 -58
  77. package/dist/containers/Heatmap/Heatmap.js +0 -244
  78. package/dist/containers/Tablets/Tablets.js +0 -228
@@ -1,389 +0,0 @@
1
- import React from 'react';
2
- import block from 'bem-cn-lite';
3
- import noop from 'lodash/noop';
4
- import throttle from 'lodash/throttle';
5
-
6
- import {Button, Icon} from '@gravity-ui/uikit';
7
-
8
- import {Drawer, DrawerItem} from './Drawer';
9
- import {Logo, LogoProps} from './Logo/Logo';
10
- import {CompositeBar} from './CompositeBar/CompositeBar';
11
- import {AsideHeaderFooterItem} from './AsideHeaderFooterItem/AsideHeaderFooterItem';
12
- import {Content, RenderContentType} from './Content/Content';
13
- import {AsideHeaderMenuItem} from './types';
14
- import {
15
- ASIDE_HEADER_COLLAPSE_BUTTON_SIZE,
16
- ASIDE_HEADER_COMPACT_WIDTH,
17
- ASIDE_HEADER_EXPANDED_WIDTH,
18
- AsideHeaderEvent,
19
- AsideHeaderVisibleItem,
20
- FooterItemIconView,
21
- } from './constants';
22
- import i18n from './i18n';
23
-
24
- import {getLocalData, setLocalData} from './helpers';
25
- import {SetSlotsContext, SlotsProvider} from './AsideHeaderFooterSlot/SlotsContext';
26
- import {SlotName} from './AsideHeaderFooterSlot/AsideHeaderFooterSlot';
27
-
28
- import controlMenuButton from '../../assets/icons/control-menu-button.svg';
29
-
30
- import './AsideHeader.scss';
31
- import {Lang} from '../../utils/i18n';
32
-
33
- const b = block('nv-aside-header');
34
-
35
- export type {AsideHeaderMenuItem};
36
-
37
- interface AsideHeaderGeneralProps
38
- extends Pick<
39
- LogoProps,
40
- | 'onLogoIconClick'
41
- | 'logoText'
42
- | 'logoIcon'
43
- | 'logoIconClassName'
44
- | 'logoIconSize'
45
- | 'logoTextSize'
46
- | 'logoHref'
47
- | 'logoWrapper'
48
- > {
49
- className?: string;
50
- panelClassName?: string;
51
- renderContent?: RenderContentType;
52
- renderPanel?: () => React.ReactNode;
53
- lang?: Lang;
54
- renderFooter?: (data: {
55
- size: number;
56
- isCompact: boolean;
57
- asideRef: React.RefObject<HTMLDivElement>;
58
- }) => React.ReactNode;
59
- onEvent?: (event: AsideHeaderEvent) => void;
60
- settings?: React.ReactNode;
61
- settingsIconWithBadge?: boolean;
62
- onChangeCompact?: (compact: boolean) => void;
63
- isCompact?: boolean;
64
- initIsCompact?: boolean;
65
- }
66
-
67
- interface AsideHeaderDefaultProps {
68
- menuItems: AsideHeaderMenuItem[];
69
- panelVisible: boolean;
70
- onClosePanel: () => void;
71
- }
72
-
73
- export interface AsideHeaderProps
74
- extends AsideHeaderGeneralProps,
75
- Partial<AsideHeaderDefaultProps> {}
76
-
77
- type AsideHeaderInnerProps = AsideHeaderGeneralProps & AsideHeaderDefaultProps;
78
-
79
- interface AsideHeaderState {
80
- visibleItem: AsideHeaderVisibleItem | null;
81
- isCompact: boolean;
82
- isButtonVisible: boolean;
83
- }
84
-
85
- export {AsideHeaderFooterItem};
86
-
87
- export {SlotName};
88
-
89
- export class AsideHeader extends React.Component<AsideHeaderInnerProps, AsideHeaderState> {
90
- static getDerivedStateFromProps(props: AsideHeaderInnerProps, state: AsideHeaderState) {
91
- if (typeof props.isCompact !== 'undefined') {
92
- const newState: Partial<AsideHeaderState> = {
93
- isCompact: props.isCompact,
94
- };
95
- if ((!props.isCompact || !state.isCompact) && !state.isButtonVisible) {
96
- newState.isButtonVisible = true;
97
- }
98
- return newState;
99
- }
100
- return null;
101
- }
102
-
103
- constructor(props: AsideHeaderInnerProps) {
104
- super(props);
105
-
106
- this.throttledPageMouseMove = throttle(this.onPageMouseMove, 300);
107
-
108
- const isCompact =
109
- typeof getLocalData()?.isCompact === 'boolean'
110
- ? Boolean(getLocalData()?.isCompact)
111
- : Boolean(props.initIsCompact);
112
-
113
- this.state = {
114
- visibleItem: null,
115
- isCompact,
116
- isButtonVisible: !isCompact,
117
- };
118
- }
119
-
120
- componentDidUpdate(prevProps: AsideHeaderInnerProps, prevState: AsideHeaderState) {
121
- if (!prevProps.panelVisible && this.props.panelVisible && this.state.visibleItem) {
122
- this.setState({visibleItem: null});
123
- }
124
-
125
- if (
126
- (prevState.visibleItem === AsideHeaderVisibleItem.Settings) !==
127
- this.isVisibleItem(AsideHeaderVisibleItem.Settings)
128
- ) {
129
- this.props.onEvent?.(
130
- this.isVisibleItem(AsideHeaderVisibleItem.Settings)
131
- ? AsideHeaderEvent.SETTINGS_OPEN
132
- : AsideHeaderEvent.SETTINGS_CLOSE,
133
- );
134
- }
135
- }
136
-
137
- render() {
138
- const size = this.state.isCompact
139
- ? ASIDE_HEADER_COMPACT_WIDTH
140
- : ASIDE_HEADER_EXPANDED_WIDTH;
141
-
142
- return (
143
- <div className={b(null, this.props.className)}>
144
- <div
145
- className={b('pane-container')}
146
- onMouseMove={(event) => {
147
- if (!this.state.isCompact) {
148
- return;
149
- }
150
- event.persist();
151
- this.throttledPageMouseMove(event);
152
- }}
153
- >
154
- {this.renderFirstPane(size)}
155
- {this.renderSecondPane(size)}
156
- </div>
157
- </div>
158
- );
159
- }
160
-
161
- static defaultProps: AsideHeaderDefaultProps = {
162
- menuItems: [],
163
- panelVisible: false,
164
- onClosePanel: noop,
165
- };
166
-
167
- asideRef = React.createRef<HTMLDivElement>();
168
-
169
- throttledPageMouseMove: (_event: React.MouseEvent<HTMLDivElement>) => void;
170
-
171
- triggerEvent = (event: AsideHeaderEvent) => {
172
- switch (event) {
173
- case AsideHeaderEvent.SETTINGS_OPEN:
174
- this.onSettingsToggle(true);
175
- break;
176
- }
177
- };
178
-
179
- private renderFirstPane = (size: number) => {
180
- const {menuItems, panelVisible, renderPanel, panelClassName, settings} = this.props;
181
- const {isCompact} = this.state;
182
-
183
- return (
184
- <SlotsProvider>
185
- <div className={b('aside')} style={{width: size}}>
186
- {this.renderCollapseButton()}
187
- <div className={b('aside-popup-anchor')} ref={this.asideRef} />
188
- <div className={b('aside-content')}>
189
- <Logo
190
- onLogoIconClick={this.props.onLogoIconClick}
191
- logoWrapper={this.props.logoWrapper}
192
- logoText={this.props.logoText}
193
- logoIcon={this.props.logoIcon}
194
- logoIconSize={this.props.logoIconSize}
195
- logoTextSize={this.props.logoTextSize}
196
- logoHref={this.props.logoHref}
197
- logoIconClassName={this.props.logoIconClassName}
198
- isCompact={isCompact}
199
- />
200
- <CompositeBar
201
- items={menuItems}
202
- isCompact={isCompact}
203
- onClickItem={this.onCompositeBarClick}
204
- />
205
- {this.renderFooter(size)}
206
- </div>
207
- </div>
208
- <Drawer
209
- className={b('drawer')}
210
- onVeilClick={this.onCloseDrawer}
211
- onEscape={this.onCloseDrawer}
212
- style={{left: size}}
213
- >
214
- <DrawerItem visible={panelVisible} className={b('panel', panelClassName)}>
215
- {renderPanel?.()}
216
- </DrawerItem>
217
- <DrawerItem visible={this.isVisibleItem(AsideHeaderVisibleItem.Settings)}>
218
- {settings}
219
- </DrawerItem>
220
- </Drawer>
221
- </SlotsProvider>
222
- );
223
- };
224
-
225
- private renderSecondPane = (size: number) => {
226
- return (
227
- <Content
228
- size={size}
229
- renderContent={this.props.renderContent}
230
- className={b('content')}
231
- />
232
- );
233
- };
234
-
235
- private renderFooter = (size: number) => {
236
- const {settings, settingsIconWithBadge} = this.props;
237
- const {isCompact} = this.state;
238
-
239
- return (
240
- <SetSlotsContext.Consumer>
241
- {(registerSlot) => {
242
- if (!registerSlot) {
243
- return null;
244
- }
245
- return (
246
- <div className={b('footer')}>
247
- {this.props.renderFooter?.({
248
- size,
249
- isCompact,
250
- asideRef: this.asideRef,
251
- })}
252
- <div
253
- ref={(node) => {
254
- registerSlot(SlotName.Support, node);
255
- }}
256
- />
257
- <div
258
- ref={(node) => {
259
- registerSlot(SlotName.BugReport, node);
260
- }}
261
- />
262
- <div
263
- ref={(node) => {
264
- registerSlot(SlotName.Settings, node);
265
- }}
266
- >
267
- {settings ? (
268
- <AsideHeaderFooterItem
269
- slot={SlotName.Settings}
270
- view={
271
- settingsIconWithBadge
272
- ? FooterItemIconView.WithDot
273
- : FooterItemIconView.Normal
274
- }
275
- text={i18n('switch_settings')}
276
- isCompact={isCompact}
277
- isCurrent={this.isVisibleItem(
278
- AsideHeaderVisibleItem.Settings,
279
- )}
280
- onClick={() => this.onSettingsToggle()}
281
- />
282
- ) : null}
283
- </div>
284
- <div
285
- ref={(node) => {
286
- registerSlot(SlotName.User, node);
287
- }}
288
- />
289
- </div>
290
- );
291
- }}
292
- </SetSlotsContext.Consumer>
293
- );
294
- };
295
-
296
- private renderCollapseButton = () => {
297
- const {isCompact, isButtonVisible} = this.state;
298
-
299
- const buttonVisibility = isButtonVisible ? 'visible' : 'hidden';
300
-
301
- return (
302
- <Button
303
- className={b('collapse-button', {compact: isCompact})}
304
- view="flat"
305
- style={{visibility: buttonVisibility}}
306
- onClick={this.onCollapseButtonClick}
307
- >
308
- <Icon
309
- data={controlMenuButton}
310
- className={b('collapse-icon')}
311
- width="14"
312
- height="14"
313
- />
314
- </Button>
315
- );
316
- };
317
-
318
- private onCollapseButtonClick = () => {
319
- const newIsCompact = !this.state.isCompact;
320
-
321
- if (typeof this.props.isCompact === 'undefined') {
322
- setLocalData({isCompact: newIsCompact});
323
- this.setState({
324
- isCompact: newIsCompact,
325
- isButtonVisible: !newIsCompact,
326
- });
327
- } else {
328
- this.setState({isButtonVisible: !newIsCompact});
329
- }
330
- if (this.props.onChangeCompact) {
331
- this.props.onChangeCompact(newIsCompact);
332
- }
333
- };
334
-
335
- private onCloseDrawer = () => {
336
- this.setState({visibleItem: null});
337
- this.props.onClosePanel?.();
338
- };
339
-
340
- private onSettingsToggle = (open?: boolean) => {
341
- let visibleItem;
342
-
343
- if (typeof open === 'undefined') {
344
- visibleItem = this.getToggledVisibleItem(AsideHeaderVisibleItem.Settings);
345
- } else {
346
- visibleItem = open ? AsideHeaderVisibleItem.Settings : null;
347
- }
348
-
349
- this.setState({visibleItem});
350
- if (this.props.panelVisible) {
351
- this.props.onClosePanel?.();
352
- }
353
- };
354
-
355
- private isVisibleItem = (item: AsideHeaderVisibleItem) => {
356
- return item === this.state.visibleItem;
357
- };
358
-
359
- private getToggledVisibleItem = (item: AsideHeaderVisibleItem) => {
360
- return !this.isVisibleItem(item) ? item : null;
361
- };
362
-
363
- private onPageMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {
364
- const xPointerCoordinate = event.clientX;
365
-
366
- const hoverArea = ASIDE_HEADER_COMPACT_WIDTH + ASIDE_HEADER_COLLAPSE_BUTTON_SIZE;
367
-
368
- if (
369
- !this.state.isButtonVisible &&
370
- xPointerCoordinate <= hoverArea &&
371
- xPointerCoordinate >= 0
372
- ) {
373
- this.setState({isButtonVisible: true});
374
- return;
375
- }
376
-
377
- if (
378
- this.state.isButtonVisible &&
379
- (xPointerCoordinate > hoverArea || xPointerCoordinate < 0)
380
- ) {
381
- this.setState({isButtonVisible: false});
382
- return;
383
- }
384
- };
385
-
386
- private onCompositeBarClick = () => {
387
- this.setState({visibleItem: null});
388
- };
389
- }
@@ -1,82 +0,0 @@
1
- @mixin aside-header-popup-animation() {
2
- &.popup2_theme_normal.popup2_direction_right-bottom.popup2_visible_yes {
3
- /* stylelint-disable-next-line */
4
- animation-name: popup2_theme_normal_bottom_visible;
5
- }
6
-
7
- &.popup2_theme_normal.popup2_direction_right-bottom {
8
- /* stylelint-disable-next-line */
9
- animation-name: popup2_theme_normal_bottom;
10
- }
11
- }
12
-
13
- .nv-aside-header-footer-item {
14
- $class: &;
15
- display: flex;
16
- overflow: hidden;
17
- align-items: center;
18
-
19
- width: 100%;
20
- min-height: 40px;
21
-
22
- @at-root .yc-list__item_active &:not(&_current) {
23
- background-color: var(--yc-color-base-simple-hover);
24
- }
25
-
26
- &_current {
27
- background-color: var(--yc-color-base-selection);
28
- }
29
-
30
- &:hover {
31
- cursor: pointer;
32
- }
33
-
34
- &:not(&_current):hover {
35
- background-color: var(--yc-color-base-simple-hover);
36
- }
37
-
38
- &__icon-place {
39
- display: flex;
40
- flex-shrink: 0;
41
- justify-content: center;
42
- align-items: center;
43
-
44
- width: var(--nv-aside-header-min-width);
45
- height: 100%;
46
- }
47
-
48
- &__text {
49
- overflow: hidden;
50
-
51
- width: 100%;
52
-
53
- white-space: nowrap;
54
- text-overflow: ellipsis;
55
- }
56
-
57
- &__icon-wrap {
58
- display: flex;
59
- justify-content: center;
60
- align-items: center;
61
-
62
- width: 38px;
63
- height: 38px;
64
- }
65
-
66
- #{$class} &__icon {
67
- color: var(--yc-color-text-misc);
68
- }
69
-
70
- &__btn-icon {
71
- display: flex;
72
- justify-content: center;
73
- align-items: center;
74
-
75
- width: 100%;
76
- height: 100%;
77
- }
78
-
79
- &__popup {
80
- @include aside-header-popup-animation();
81
- }
82
- }
@@ -1,138 +0,0 @@
1
- import React from 'react';
2
- import block from 'bem-cn-lite';
3
- import {Icon, Popup, PopupPlacement, PopupProps} from '@gravity-ui/uikit';
4
-
5
- import {AsideHeaderTooltip} from '../AsideHeaderTooltip/AsideHeaderTooltip';
6
- import {AsideHeaderFooterSlot, SlotName} from '../AsideHeaderFooterSlot/AsideHeaderFooterSlot';
7
- import {ASIDE_HEADER_ICON_SIZE, FooterItemIconView} from '../constants';
8
- import {footerItemIconMap, getFooterItemIcon} from '../icons';
9
-
10
- import settingsIcon from '../../../assets/icons/settings.svg';
11
-
12
- import './AsideHeaderFooterItem.scss';
13
-
14
- const b = block('nv-aside-header-footer-item');
15
-
16
- export const defaultAsideHeaderFooterPopupPlacement: PopupPlacement = ['right-end'];
17
- export const defaultAsideHeaderFooterPopupOffset: NonNullable<PopupProps['offset']> = [-20, 8];
18
-
19
- export interface AsideHeaderFooterItemProps {
20
- onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
21
- isCompact: boolean;
22
- isCurrent?: boolean;
23
- text: React.ReactNode;
24
- tooltipText?: React.ReactNode;
25
- enableTooltip?: boolean;
26
- iconSize?: string | number;
27
- slot?: SlotName;
28
- view?: FooterItemIconView;
29
- className?: string;
30
- popupVisible?: boolean;
31
- popupAnchor?: React.RefObject<HTMLElement>;
32
- popupPlacement?: PopupPlacement;
33
- popupOffset?: PopupProps['offset'];
34
- renderPopupContent?: () => React.ReactNode;
35
- onClosePopup?: () => void;
36
- renderCustomIcon?: () => React.ReactNode;
37
- }
38
-
39
- export const AsideHeaderFooterItem: React.FC<AsideHeaderFooterItemProps> = ({
40
- onClick,
41
- isCompact,
42
- isCurrent = false,
43
- enableTooltip = true,
44
- tooltipText,
45
- text,
46
- iconSize = ASIDE_HEADER_ICON_SIZE,
47
- slot,
48
- view,
49
- className,
50
- popupAnchor,
51
- popupVisible = false,
52
- popupPlacement = defaultAsideHeaderFooterPopupPlacement,
53
- popupOffset = defaultAsideHeaderFooterPopupOffset,
54
- onClosePopup,
55
- renderPopupContent,
56
- renderCustomIcon,
57
- }) => {
58
- const [tooltipAnchor, setTooltipAnchor] = React.useState<HTMLDivElement | null>(null);
59
- const ref = React.useRef<HTMLDivElement>(null);
60
-
61
- React.useEffect(() => {
62
- if (!isCompact) {
63
- setTooltipAnchor(null);
64
- }
65
- }, [isCompact]);
66
-
67
- const icon = (slot && getFooterItemIcon(slot, view)) || settingsIcon;
68
- let iconPlaceNode: React.ReactNode;
69
-
70
- if (typeof renderCustomIcon === 'function') {
71
- iconPlaceNode = renderCustomIcon();
72
- } else {
73
- const iconData = typeof icon === 'string' ? footerItemIconMap[icon as never] : icon;
74
- iconPlaceNode = isCompact ? (
75
- <React.Fragment>
76
- <div
77
- onMouseEnter={(event) => setTooltipAnchor(event.currentTarget)}
78
- onMouseLeave={() => setTooltipAnchor(null)}
79
- className={b('btn-icon', {current: isCurrent})}
80
- >
81
- <Icon data={iconData} size={iconSize} className={b('icon')} />
82
- </div>
83
- {enableTooltip && (
84
- <AsideHeaderTooltip anchor={tooltipAnchor} text={tooltipText || text} />
85
- )}
86
- </React.Fragment>
87
- ) : (
88
- <div className={b('icon-wrap')}>
89
- <Icon data={iconData} size={iconSize} className={b('icon')} />
90
- </div>
91
- );
92
- }
93
-
94
- const anchorRef = popupAnchor || ref;
95
-
96
- const onClose = React.useCallback(
97
- (event: MouseEvent | KeyboardEvent) => {
98
- if (
99
- event instanceof MouseEvent &&
100
- event.target &&
101
- ref.current?.contains(event.target as Node)
102
- ) {
103
- return;
104
- }
105
- onClosePopup?.();
106
- },
107
- [onClosePopup],
108
- );
109
-
110
- const contentNode = (
111
- <React.Fragment>
112
- <div
113
- className={b({compact: isCompact, current: isCurrent}, className)}
114
- onClick={onClick}
115
- ref={ref}
116
- >
117
- <div className={b('icon-place')}>{iconPlaceNode}</div>
118
- {!isCompact && <div className={b('text')}>{text}</div>}
119
- </div>
120
- <Popup
121
- className={b('popup')}
122
- open={popupVisible}
123
- placement={popupPlacement}
124
- offset={popupOffset}
125
- anchorRef={anchorRef}
126
- onClose={onClose}
127
- >
128
- {renderPopupContent?.()}
129
- </Popup>
130
- </React.Fragment>
131
- );
132
-
133
- return slot ? (
134
- <AsideHeaderFooterSlot name={slot}>{contentNode}</AsideHeaderFooterSlot>
135
- ) : (
136
- contentNode
137
- );
138
- };
@@ -1,33 +0,0 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom';
3
- import {useSlot} from './SlotsContext';
4
-
5
- export enum SlotName {
6
- Settings = 'settings',
7
- User = 'user',
8
- Support = 'support',
9
- BugReport = 'bug-report',
10
- }
11
-
12
- interface AsideHeaderFooterSlotProps {
13
- name: SlotName;
14
- children: React.ReactNode;
15
- slotRef?: React.Ref<HTMLElement>;
16
- }
17
-
18
- export function AsideHeaderFooterSlot({name, slotRef, children}: AsideHeaderFooterSlotProps) {
19
- const slot = useSlot(name);
20
-
21
- if (typeof slotRef === 'function') {
22
- slotRef(slot || null);
23
- } else if (slotRef) {
24
- // @ts-ignore
25
- slotRef.current = slot;
26
- }
27
-
28
- if (slot) {
29
- return ReactDOM.createPortal(children, slot);
30
- }
31
-
32
- return null;
33
- }
@@ -1,49 +0,0 @@
1
- import React from 'react';
2
- import {SlotName} from './AsideHeaderFooterSlot';
3
-
4
- type Slots = Partial<Record<SlotName, HTMLElement | null>>;
5
-
6
- const SlotsContext = React.createContext<Slots | undefined>(undefined);
7
- export const SetSlotsContext = React.createContext<
8
- ((name: SlotName, node: HTMLElement | null) => void) | undefined
9
- >(undefined);
10
-
11
- export function SlotsProvider({children}: {children: React.ReactNode}) {
12
- const [slots, setSlots] = React.useState<Slots>({});
13
-
14
- const registerSlot = React.useCallback(
15
- (name: SlotName, node: HTMLElement | null) => {
16
- setSlots((prevSlots) => {
17
- if (prevSlots[name] === node) {
18
- return prevSlots;
19
- }
20
- return {
21
- ...prevSlots,
22
- [name]: node,
23
- };
24
- });
25
- },
26
- [setSlots],
27
- );
28
-
29
- return (
30
- <SetSlotsContext.Provider value={registerSlot}>
31
- <SlotsContext.Provider value={slots}>{children}</SlotsContext.Provider>
32
- </SetSlotsContext.Provider>
33
- );
34
- }
35
-
36
- function useSlotsValue() {
37
- const slots = React.useContext(SlotsContext);
38
-
39
- if (slots === undefined) {
40
- throw new Error('useSlots must be used within a SlotsProvider');
41
- }
42
-
43
- return slots;
44
- }
45
-
46
- export function useSlot(name: SlotName) {
47
- const slots = useSlotsValue();
48
- return slots[name];
49
- }