ydb-embedded-ui 3.2.0 → 3.2.1

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.
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
- }