@cyber-harbour/ui 1.0.20 → 1.0.21
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/index.d.mts +26 -3
- package/dist/index.d.ts +26 -3
- package/dist/index.js +98 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +80 -36
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/Core/ContextMenu/ContextMenu.tsx +12 -3
- package/src/Core/IconComponents/Plus.tsx +20 -0
- package/src/Core/IconComponents/index.ts +1 -0
- package/src/Core/Select/Select.tsx +116 -0
- package/src/Core/Select/index.ts +1 -0
- package/src/Core/index.ts +1 -0
- package/src/Layouts/PageLayout/PageLayout.tsx +5 -1
- package/src/Theme/theme.ts +30 -1
- package/src/Theme/types.ts +4 -0
package/package.json
CHANGED
|
@@ -43,6 +43,15 @@ export const ContextMenu = ({
|
|
|
43
43
|
align={align}
|
|
44
44
|
onClickOutside={onClickOutside}
|
|
45
45
|
content={children}
|
|
46
|
+
containerStyle={{
|
|
47
|
+
backgroundColor: theme.colors.background,
|
|
48
|
+
border: `1px solid ${theme.colors.stroke.light}`,
|
|
49
|
+
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.25)',
|
|
50
|
+
borderRadius: '5px',
|
|
51
|
+
overflow: 'auto',
|
|
52
|
+
maxHeight: '500px',
|
|
53
|
+
zIndex: `${9999}`,
|
|
54
|
+
}}
|
|
46
55
|
>
|
|
47
56
|
<StyledButton
|
|
48
57
|
ref={buttonRef}
|
|
@@ -51,6 +60,8 @@ export const ContextMenu = ({
|
|
|
51
60
|
$fullWidth={fullWidth}
|
|
52
61
|
$size={size}
|
|
53
62
|
className={className}
|
|
63
|
+
type="button"
|
|
64
|
+
disabled={disabled}
|
|
54
65
|
>
|
|
55
66
|
<div>{anchor}</div>
|
|
56
67
|
{isOpen ? (
|
|
@@ -88,7 +99,7 @@ const StyledButton = styled.button<{
|
|
|
88
99
|
font-weight: 500;
|
|
89
100
|
display: inline-flex;
|
|
90
101
|
align-items: center;
|
|
91
|
-
justify-content: center;
|
|
102
|
+
justify-content: ${$fullWidth ? 'space-between' : 'center'};
|
|
92
103
|
text-decoration: none;
|
|
93
104
|
transition: all 0.2s ease;
|
|
94
105
|
outline: none;
|
|
@@ -118,5 +129,3 @@ const StyledButton = styled.button<{
|
|
|
118
129
|
`;
|
|
119
130
|
}}
|
|
120
131
|
`;
|
|
121
|
-
|
|
122
|
-
const StyledContainer = styled.div``;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SVGProps } from 'react';
|
|
2
|
+
|
|
3
|
+
interface PrintIconProps extends SVGProps<SVGSVGElement> {
|
|
4
|
+
fill?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const PlusIcon = ({ fill = 'currentColor', ...props }: PrintIconProps) => {
|
|
8
|
+
return (
|
|
9
|
+
<svg viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
|
10
|
+
<path
|
|
11
|
+
d="M9.21053 5.78952H0.789474C0.357895 5.78952 0 5.43162 0 5.00005C0 4.56847 0.357895 4.21057 0.789474 4.21057H9.21053C9.64211 4.21057 10 4.56847 10 5.00005C10 5.43162 9.64211 5.78952 9.21053 5.78952Z"
|
|
12
|
+
fill={fill}
|
|
13
|
+
/>
|
|
14
|
+
<path
|
|
15
|
+
d="M5.00041 10C4.56883 10 4.21094 9.64211 4.21094 9.21053V0.789474C4.21094 0.357895 4.56883 0 5.00041 0C5.43199 0 5.78988 0.357895 5.78988 0.789474V9.21053C5.78988 9.64211 5.43199 10 5.00041 10Z"
|
|
16
|
+
fill={fill}
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
|
+
import { PopoverAlign, PopoverPosition } from 'react-tiny-popover';
|
|
3
|
+
import { ContextMenu } from '../ContextMenu';
|
|
4
|
+
import { ButtonSize, getButtonSizeStyles } from '@/Theme';
|
|
5
|
+
import { styled } from 'styled-components';
|
|
6
|
+
|
|
7
|
+
interface SelectProps<T extends string | number> {
|
|
8
|
+
selected?: T;
|
|
9
|
+
options: { value: T; inputDisplay?: string }[];
|
|
10
|
+
handleSelect: (id: T) => void;
|
|
11
|
+
placeholder: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
positions?: PopoverPosition[] | PopoverPosition;
|
|
14
|
+
align?: PopoverAlign;
|
|
15
|
+
size?: ButtonSize;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const Select = <T extends string | number>({
|
|
19
|
+
options,
|
|
20
|
+
selected,
|
|
21
|
+
handleSelect,
|
|
22
|
+
placeholder,
|
|
23
|
+
disabled = false,
|
|
24
|
+
positions = ['bottom'],
|
|
25
|
+
align = 'start',
|
|
26
|
+
size = 'small',
|
|
27
|
+
}: SelectProps<T>) => {
|
|
28
|
+
const [isOpen, setIsOpen] = useState<boolean>(false);
|
|
29
|
+
const handleToggle = useCallback(() => {
|
|
30
|
+
if (!disabled) setIsOpen((prev) => !prev);
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<ContextMenu
|
|
35
|
+
isOpen={isOpen}
|
|
36
|
+
onClickOutside={() => setIsOpen(false)}
|
|
37
|
+
onClick={handleToggle}
|
|
38
|
+
disabled={disabled}
|
|
39
|
+
anchor={!selected ? placeholder : options.find((option) => option.value === selected)?.inputDisplay || selected}
|
|
40
|
+
fullWidth
|
|
41
|
+
positions={positions}
|
|
42
|
+
align={align}
|
|
43
|
+
size={size}
|
|
44
|
+
>
|
|
45
|
+
<StyledWrapper>
|
|
46
|
+
{options.map((item) => (
|
|
47
|
+
<StyledItem
|
|
48
|
+
onClick={() => {
|
|
49
|
+
handleSelect(item.value);
|
|
50
|
+
setIsOpen(false);
|
|
51
|
+
}}
|
|
52
|
+
type="button"
|
|
53
|
+
$selected={item.value === selected}
|
|
54
|
+
key={item.value}
|
|
55
|
+
disabled={disabled}
|
|
56
|
+
$size={size}
|
|
57
|
+
>
|
|
58
|
+
{item.inputDisplay || item.value}
|
|
59
|
+
</StyledItem>
|
|
60
|
+
))}
|
|
61
|
+
</StyledWrapper>
|
|
62
|
+
</ContextMenu>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const StyledWrapper = styled.div`
|
|
67
|
+
padding-block: 7px;
|
|
68
|
+
padding-inline: 5px;
|
|
69
|
+
button:not(:last-of-type) {
|
|
70
|
+
margin-bottom: 4px;
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
const StyledItem = styled.button<{ $size: ButtonSize; $selected: boolean }>`
|
|
75
|
+
${({ theme, $size, $selected }) => {
|
|
76
|
+
const sizes = getButtonSizeStyles(theme, $size);
|
|
77
|
+
return `
|
|
78
|
+
background: ${theme.select.item.default.background};
|
|
79
|
+
color: ${theme.select.item.default.text};
|
|
80
|
+
font-size: ${sizes.fontSize};
|
|
81
|
+
gap: ${sizes.gap};
|
|
82
|
+
padding-block: ${sizes.paddingBlock};
|
|
83
|
+
padding-inline: ${sizes.paddingInline};
|
|
84
|
+
border-radius: ${sizes.borderRadius};
|
|
85
|
+
border-width: ${sizes.borderWidth};
|
|
86
|
+
border: none;
|
|
87
|
+
width: 100%;
|
|
88
|
+
cursor: pointer;
|
|
89
|
+
font-weight: 400;
|
|
90
|
+
display: inline-flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: flex-start;
|
|
93
|
+
text-decoration: none;
|
|
94
|
+
transition: all 0.2s ease;
|
|
95
|
+
outline: none;
|
|
96
|
+
flex-direction: row;
|
|
97
|
+
|
|
98
|
+
&:hover {
|
|
99
|
+
background-color: ${theme.select.item.hover.background};
|
|
100
|
+
color: ${theme.select.item.hover.text};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
${
|
|
104
|
+
$selected &&
|
|
105
|
+
`background: ${theme.select.item.active.background};
|
|
106
|
+
color: ${theme.select.item.active.text};`
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&:disabled {
|
|
110
|
+
background: ${theme.select.item.disabled.background};
|
|
111
|
+
color: ${theme.select.item.disabled.text};
|
|
112
|
+
cursor: not-allowed;
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
}}
|
|
116
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Select';
|
package/src/Core/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ export const PageLayout = ({ children, header, sidebar }: PageLayoutProps) => {
|
|
|
12
12
|
<StyledContainer $withHeader={!!header} $withSidebar={!!sidebar}>
|
|
13
13
|
{header}
|
|
14
14
|
{sidebar}
|
|
15
|
-
<
|
|
15
|
+
<StyledMain>{children}</StyledMain>
|
|
16
16
|
</StyledContainer>
|
|
17
17
|
);
|
|
18
18
|
};
|
|
@@ -53,3 +53,7 @@ export const StyledContainer = styled.div<StyledContainerProps>(
|
|
|
53
53
|
}
|
|
54
54
|
`
|
|
55
55
|
);
|
|
56
|
+
|
|
57
|
+
const StyledMain = styled.main`
|
|
58
|
+
min-width: 0;
|
|
59
|
+
`;
|
package/src/Theme/theme.ts
CHANGED
|
@@ -497,7 +497,7 @@ export const lightThemePx: Theme = {
|
|
|
497
497
|
boxShadow: 'none',
|
|
498
498
|
},
|
|
499
499
|
disabled: {
|
|
500
|
-
background: '#
|
|
500
|
+
background: '#FAFAFA',
|
|
501
501
|
text: '#99989C',
|
|
502
502
|
border: ' #EBEBEB',
|
|
503
503
|
boxShadow: 'none',
|
|
@@ -516,6 +516,35 @@ export const lightThemePx: Theme = {
|
|
|
516
516
|
size: 7,
|
|
517
517
|
},
|
|
518
518
|
},
|
|
519
|
+
// Компонент Select
|
|
520
|
+
select: {
|
|
521
|
+
item: {
|
|
522
|
+
default: {
|
|
523
|
+
background: 'transparent',
|
|
524
|
+
text: '#101010',
|
|
525
|
+
border: ' none',
|
|
526
|
+
boxShadow: 'none',
|
|
527
|
+
},
|
|
528
|
+
hover: {
|
|
529
|
+
background: '#E5ECFD',
|
|
530
|
+
text: '#101010',
|
|
531
|
+
border: ' none',
|
|
532
|
+
boxShadow: 'none',
|
|
533
|
+
},
|
|
534
|
+
active: {
|
|
535
|
+
background: '#E8EAEE',
|
|
536
|
+
text: '#101010',
|
|
537
|
+
border: ' none',
|
|
538
|
+
boxShadow: 'none',
|
|
539
|
+
},
|
|
540
|
+
disabled: {
|
|
541
|
+
background: '#FAFAFA',
|
|
542
|
+
text: '#99989C',
|
|
543
|
+
border: ' none',
|
|
544
|
+
boxShadow: 'none',
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
},
|
|
519
548
|
};
|
|
520
549
|
|
|
521
550
|
// Конвертуємо всі розміри з px в rem
|