@cyber-harbour/ui 1.0.22 → 1.0.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyber-harbour/ui",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -114,21 +114,21 @@ const StyledButton = styled.button<{
114
114
  &:hover {
115
115
  background: ${theme.contextMenu.button.hover.background};
116
116
  color: ${theme.contextMenu.button.hover.text};
117
- border-color: ${theme.contextMenu.button.hover.border};
117
+ border-color: ${$hasBorder ? theme.contextMenu.button.hover.border : 'transparent'};
118
118
  box-shadow: ${theme.contextMenu.button.hover.boxShadow};
119
119
  }
120
120
 
121
121
  &:active {
122
122
  background: ${theme.contextMenu.button.active.background};
123
123
  color: ${theme.contextMenu.button.active.text};
124
- border-color: ${theme.contextMenu.button.active.border};
124
+ border-color: ${$hasBorder ? theme.contextMenu.button.active.border : 'transparent'};
125
125
  box-shadow: ${theme.contextMenu.button.active.boxShadow};
126
126
  }
127
127
 
128
128
  &:disabled {
129
129
  background: ${theme.contextMenu.button.disabled.background};
130
130
  color: ${theme.contextMenu.button.disabled.text};
131
- border-color: ${theme.contextMenu.button.disabled.border};
131
+ border-color: ${$hasBorder ? theme.contextMenu.button.disabled.border : 'transparent'};
132
132
  box-shadow: ${theme.contextMenu.button.disabled.boxShadow};
133
133
  }
134
134
 
@@ -0,0 +1,151 @@
1
+ import { ButtonColor, ButtonSize, getButtonSizeStyles } from '../../Theme';
2
+ import { useRef } from 'react';
3
+ import { Popover, PopoverAlign, PopoverPosition } from 'react-tiny-popover';
4
+ import { styled, useTheme } from 'styled-components';
5
+ import { BallsMenu } from '../IconComponents';
6
+ import { useContextMenuControl } from '../ContextMenu';
7
+ import { Button } from '../Button';
8
+
9
+ export type Action = {
10
+ label: string;
11
+ onClick: () => void;
12
+ color: ButtonColor;
13
+ };
14
+
15
+ interface RowActionsMenuProps {
16
+ items: Action[];
17
+ size?: ButtonSize;
18
+ disabled?: boolean;
19
+ className?: string;
20
+ positions?: PopoverPosition[] | PopoverPosition;
21
+ align?: PopoverAlign;
22
+ }
23
+
24
+ export const RowActionsMenu = ({
25
+ size = 'small',
26
+ disabled,
27
+ className,
28
+ positions = ['bottom'],
29
+ align = 'end',
30
+ items,
31
+ }: RowActionsMenuProps) => {
32
+ const buttonRef = useRef<HTMLButtonElement | null>(null);
33
+ const { isOpen, closeMenu, toggleMenu } = useContextMenuControl();
34
+
35
+ const theme = useTheme();
36
+
37
+ return (
38
+ <Popover
39
+ padding={theme.contextMenu.padding}
40
+ isOpen={isOpen}
41
+ positions={positions}
42
+ align={align}
43
+ onClickOutside={closeMenu}
44
+ content={
45
+ <ContentWrapper>
46
+ {items.map(({ label, onClick, color }, idx) => (
47
+ <Button
48
+ variant="empty"
49
+ key={`row-action-${idx}`}
50
+ color={color}
51
+ fullWidth
52
+ size={size}
53
+ onClick={() => {
54
+ onClick();
55
+ closeMenu();
56
+ }}
57
+ >
58
+ {label}
59
+ </Button>
60
+ ))}
61
+ </ContentWrapper>
62
+ }
63
+ containerStyle={{
64
+ backgroundColor: theme.colors.background,
65
+ border: `1px solid ${theme.colors.stroke.light}`,
66
+ boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.25)',
67
+ borderRadius: '5px',
68
+ zIndex: `${9999}`,
69
+ }}
70
+ >
71
+ <StyledButton
72
+ ref={buttonRef}
73
+ onClick={toggleMenu}
74
+ $disabled={disabled}
75
+ $size={size}
76
+ className={className}
77
+ type="button"
78
+ disabled={disabled}
79
+ >
80
+ <BallsMenu width={theme.rowActionsMenu.icon.size} height={theme.rowActionsMenu.icon.size} />
81
+ </StyledButton>
82
+ </Popover>
83
+ );
84
+ };
85
+
86
+ const StyledButton = styled.button<{
87
+ $size: ButtonSize;
88
+ $disabled?: boolean;
89
+ }>`
90
+ ${({ $size, $disabled, theme }) => {
91
+ const sizes = getButtonSizeStyles(theme, $size);
92
+ return `
93
+ background: ${theme.rowActionsMenu.button.default.background};
94
+ color: ${theme.rowActionsMenu.button.default.text};
95
+ border: none;
96
+ font-size: ${sizes.fontSize};
97
+ gap: ${sizes.gap};
98
+ padding: 4px;
99
+ border-radius: ${sizes.borderRadius};
100
+ width: auto;
101
+ cursor: ${$disabled ? 'not-allowed' : 'pointer'};
102
+ font-weight: 500;
103
+ display: inline-flex;
104
+ justify-content: center;
105
+ align-items: center;
106
+ text-decoration: none;
107
+ transition: all 0.2s ease;
108
+ outline: none;
109
+
110
+ &:hover {
111
+ background: ${theme.rowActionsMenu.button.hover.background};
112
+ color: ${theme.rowActionsMenu.button.hover.text};
113
+ }
114
+
115
+ &:active {
116
+ background: ${theme.rowActionsMenu.button.active.background};
117
+ color: ${theme.rowActionsMenu.button.active.text};
118
+ }
119
+
120
+ &:disabled {
121
+ background: ${theme.rowActionsMenu.button.disabled.background};
122
+ color: ${theme.rowActionsMenu.button.disabled.text};
123
+ }
124
+
125
+ `;
126
+ }}
127
+ `;
128
+ const ContentWrapper = styled.div(
129
+ ({ theme }) => `
130
+ padding: 5px 10px;
131
+ display: flex;
132
+ flex-direction: column;
133
+ button {
134
+ min-width: 110px;
135
+ justify-content: flex-start;
136
+ font-weight: 400;
137
+ }
138
+ button:not(:last-of-type) {
139
+ position: relative;
140
+ ::after {
141
+ position: absolute;
142
+ content: '';
143
+ bottom: 0;
144
+ left: 5px;
145
+ right: 5px;
146
+ height: 1px;
147
+ background-color: ${theme.rowActionsMenu.delimiterColor};
148
+ }
149
+ }
150
+ `
151
+ );
@@ -0,0 +1 @@
1
+ export * from './RowActionsMenu';
package/src/Core/index.ts CHANGED
@@ -8,3 +8,4 @@ export * from './Table';
8
8
  export * from './Pagination';
9
9
  export * from './ContextMenu';
10
10
  export * from './Select';
11
+ export * from './RowActionsMenu';
@@ -545,6 +545,39 @@ export const lightThemePx: Theme = {
545
545
  },
546
546
  },
547
547
  },
548
+ // Компонент RowActionsMenu
549
+ rowActionsMenu: {
550
+ button: {
551
+ default: {
552
+ background: 'transparent',
553
+ text: '#101010',
554
+ border: ' none',
555
+ boxShadow: 'none',
556
+ },
557
+ hover: {
558
+ background: 'transparent',
559
+ text: '#0042EC',
560
+ border: ' none',
561
+ boxShadow: 'none',
562
+ },
563
+ active: {
564
+ background: 'transparent',
565
+ text: '#0042EC',
566
+ border: ' none',
567
+ boxShadow: 'none',
568
+ },
569
+ disabled: {
570
+ background: '#FAFAFA',
571
+ text: '#99989C',
572
+ border: ' none',
573
+ boxShadow: 'none',
574
+ },
575
+ },
576
+ delimiterColor: '#EBEBEB',
577
+ icon: {
578
+ size: 16,
579
+ },
580
+ },
548
581
  };
549
582
 
550
583
  // Конвертуємо всі розміри з px в rem
@@ -151,6 +151,13 @@ export type Theme = {
151
151
  select: {
152
152
  item: Record<ButtonState, ButtonElementStyle>;
153
153
  };
154
+ rowActionsMenu: {
155
+ button: Record<ButtonState, ButtonElementStyle>;
156
+ delimiterColor: string;
157
+ icon: {
158
+ size: number | string;
159
+ };
160
+ };
154
161
  };
155
162
 
156
163
  //TODO check and refactoring