@cyber-harbour/ui 1.0.53 → 1.0.55

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.53",
3
+ "version": "1.0.55",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -27,6 +27,7 @@
27
27
  "license": "ISC",
28
28
  "description": "",
29
29
  "dependencies": {
30
+ "@types/react-dom": "^19.1.6",
30
31
  "d3": "^7.9.0",
31
32
  "lodash.clonedeep": "^4.5.0",
32
33
  "react-content-loader": "^7.0.2",
@@ -1,26 +1,41 @@
1
- import { createComponent, FabricComponent, generatePropertySpaceStyle } from '../../Theme';
1
+ import {
2
+ ColorVariant,
3
+ createComponent,
4
+ FabricComponent,
5
+ generatePropertySpaceStyle,
6
+ resolveThemeColor,
7
+ } from '../../Theme';
2
8
  import { styled } from 'styled-components';
3
9
 
4
10
  type BoxProps = FabricComponent<
5
11
  {
6
12
  children: any;
13
+ element?: 'div' | 'section';
14
+ hasBorder?: boolean;
15
+ color?: ColorVariant | string;
7
16
  } & React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
8
17
  >;
9
18
 
10
- export const Box = ({ children, ...props }: BoxProps) => {
11
- return <StyledBox {...props}>{children}</StyledBox>;
19
+ export const Box = ({ children, element = 'div', hasBorder = true, color, ...props }: BoxProps) => {
20
+ return (
21
+ <StyledBox as={element} $hasBorder={hasBorder} $color={color} {...props}>
22
+ {children}
23
+ </StyledBox>
24
+ );
12
25
  };
13
26
 
27
+ type StyledProps = { $hasBorder: boolean; $color?: string };
28
+
14
29
  const StyledBox = createComponent(
15
- styled('div')<FabricComponent>(
16
- ({ theme, px = theme.box.padding, py = theme.box.padding }) => `
30
+ styled('div')<FabricComponent<StyledProps>>(
31
+ ({ theme, $hasBorder, $color, px = theme.box.padding, py = theme.box.padding }) => `
17
32
  ${generatePropertySpaceStyle(theme, 'padding-inline', px)}
18
33
  ${generatePropertySpaceStyle(theme, 'padding-block', py)}
19
34
  border-radius: ${theme.box.borderRadius};
20
35
  background-color: ${theme.box.background};
21
- border-width: ${theme.box.border.width};
36
+ border-width: ${$hasBorder ? theme.box.border.width : 0};
22
37
  border-style: ${theme.box.border.style};
23
- border-color: ${theme.box.border.color};
38
+ border-color: ${resolveThemeColor(theme, $color) || theme.box.border.color};
24
39
  `
25
40
  ),
26
41
  {
@@ -0,0 +1,84 @@
1
+ import { createPortal } from 'react-dom';
2
+ import { styled } from 'styled-components';
3
+ import { pxToRem } from '../../Theme';
4
+ import { CrossIcon } from '../IconComponents';
5
+ import { useEffect, useRef } from 'react';
6
+
7
+ type DrawerProps = {
8
+ isOpen: boolean;
9
+ onClose: () => void;
10
+ children: any;
11
+ header?: number;
12
+ width?: number;
13
+ };
14
+ export const Drawer = (props: DrawerProps) => {
15
+ if (!props.isOpen) return null;
16
+ return createPortal(<DrawerWithOutclick {...props} />, document.body);
17
+ };
18
+
19
+ const DrawerWithOutclick = ({ onClose, children, width, header }: DrawerProps) => {
20
+ const drawerRef = useRef<HTMLDivElement>(null);
21
+
22
+ useEffect(() => {
23
+ const handleClick = (e: MouseEvent) => {
24
+ if (drawerRef.current && !drawerRef.current.contains(e.target as Node)) {
25
+ onClose();
26
+ }
27
+ };
28
+ document.addEventListener('mousedown', handleClick);
29
+ return () => {
30
+ document.removeEventListener('mousedown', handleClick);
31
+ };
32
+ }, [onClose]);
33
+ return (
34
+ <StyledDrawer $header={header} $width={width} ref={drawerRef}>
35
+ <CloseButton onClick={onClose}>
36
+ <CrossIcon width={14} height={14} color="currentColor" />
37
+ </CloseButton>
38
+ <Content>{children}</Content>
39
+ </StyledDrawer>
40
+ );
41
+ };
42
+
43
+ const CloseButton = styled.button(
44
+ ({ theme }) => `
45
+ display: block;
46
+ position: absolute;
47
+ background-color: inherit;
48
+ top: ${pxToRem(16, theme.baseSize)};
49
+ right: ${pxToRem(16, theme.baseSize)};
50
+ cursor: pointer;
51
+ z-index: 1;
52
+
53
+ color: ${theme.colors.text.light};
54
+ padding: ${pxToRem(4, theme.baseSize)};
55
+ border: none;
56
+ outline: none;
57
+ transition: color 0.2s ease;
58
+ &: hover {
59
+ color: ${theme.colors.primary.light};
60
+ }
61
+ `
62
+ );
63
+
64
+ const Content = styled.div(
65
+ ({ theme }) => `
66
+ max-height: 100%;
67
+ overflow-y: auto;
68
+ `
69
+ );
70
+ const StyledDrawer = styled.div<{ $header?: number; $width?: number }>(
71
+ ({ theme, $header, $width }) => `
72
+ position: fixed;
73
+ z-index: ${theme.zIndex.sticky};
74
+ top: ${pxToRem($header || 0, theme.baseSize)};
75
+ bottom: 0;
76
+ right: 0;
77
+ width: ${$width ? pxToRem($width, theme.baseSize) : theme.drawer.width};
78
+ max-width: 100%;
79
+ padding: ${theme.drawer.padding};
80
+ background-color: ${theme.colors.background};
81
+ box-shadow: ${theme.drawer.shadow};
82
+ border-left: 1px solid ${theme.colors.stroke.lighter};
83
+ `
84
+ );
@@ -0,0 +1 @@
1
+ export * from './Drawer';
@@ -0,0 +1,32 @@
1
+ import { SVGProps } from 'react';
2
+
3
+ interface FolderAlertIconProps extends SVGProps<SVGSVGElement> {
4
+ fill?: string;
5
+ }
6
+
7
+ export const FolderAlertIcon = ({ fill = 'currentColor', ...props }: FolderAlertIconProps) => {
8
+ return (
9
+ <svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
10
+ <path
11
+ d="M13.7386 2.02034H14.8293C15.3096 2.02034 16 2.77034 16.01 3.26034V12.1703C15.97 12.6703 15.6498 13.1203 15.1995 13.3403C14.7492 13.5603 14.2989 13.4503 13.8086 13.4803C13.0181 15.7803 10.2764 16.7303 8.21513 15.3903C7.50469 14.9303 7.0344 14.2503 6.7242 13.4703H1.24078C0.590369 13.3703 0.08005 12.8603 0 12.2003V3.26034C0 2.77034 0.700438 2.02034 1.18074 2.02034H2.27142V0.300345C2.27142 0.240345 2.47154 0.0303449 2.55159 0.0203449L13.3684 0.000344886C13.4784 -0.00965511 13.7286 0.200345 13.7286 0.300345V2.02034H13.7386ZM12.848 0.880345H3.15197V2.01034H4.77298C5.40338 2.01034 6.44403 3.49035 6.90431 3.95035C6.92433 3.97035 6.93433 4.00034 6.93433 4.03034H12.858V0.880345H12.848ZM13.9887 12.5903H14.5991C14.8593 12.5903 15.1395 12.2303 15.1194 11.9803V5.53034C15.0894 5.15034 14.8793 4.95035 14.5091 4.92034H6.63415C6.54409 4.90034 6.47405 4.86034 6.41401 4.80034C5.9237 4.35035 5.48343 3.65035 5.00313 3.16035C4.83302 2.99035 4.74296 2.93035 4.50281 2.91035C3.54221 2.97035 2.49156 2.84035 1.54096 2.91035C1.15072 2.94035 0.930582 3.12034 0.890557 3.52034V12.0203C0.890557 12.2703 1.17073 12.6003 1.41088 12.6003H6.5641C6.37398 10.0903 8.61539 8.12035 11.0969 8.65034C12.8981 9.04035 14.1588 10.7603 13.9987 12.6003L13.9887 12.5903ZM15.1194 4.12034V3.41035C15.1194 3.20035 14.8093 2.89035 14.5991 2.89035H13.7286V4.02034H14.8193C14.8193 4.02034 15.0994 4.14035 15.1194 4.11034V4.12034ZM10.1363 9.45035C7.91495 9.55035 6.67417 12.1003 7.97498 13.9203C9.13571 15.5603 11.6573 15.4603 12.6879 13.7303C13.8386 11.8003 12.3877 9.35034 10.1363 9.45035Z"
12
+ fill={fill}
13
+ />
14
+ <path
15
+ d="M2.07172 9.07031H4.83345C5.28373 9.19031 5.29373 9.82031 4.83345 9.94031H2.09173C1.65146 9.81031 1.63145 9.22031 2.06171 9.07031H2.07172Z"
16
+ fill={fill}
17
+ />
18
+ <path
19
+ d="M2.07172 10.8398H4.83345C5.28373 10.9598 5.29373 11.5898 4.83345 11.7098H2.09173C1.65146 11.5798 1.63145 10.9898 2.06171 10.8398H2.07172Z"
20
+ fill={fill}
21
+ />
22
+ <path
23
+ d="M10.1371 10.3314C10.3772 10.2814 10.6674 10.4014 10.7074 10.6614C10.7475 10.9214 10.7475 12.1214 10.7074 12.3914C10.6374 12.8414 9.90694 12.8314 9.82689 12.3914C9.78687 12.1514 9.78687 10.9014 9.82689 10.6614C9.84691 10.5314 10.007 10.3614 10.1271 10.3314H10.1371Z"
24
+ fill={fill}
25
+ />
26
+ <path
27
+ d="M10.1372 13.3494C10.7876 13.2194 10.8976 14.0694 10.4273 14.2094C9.76694 14.4094 9.61684 13.4594 10.1372 13.3494Z"
28
+ fill={fill}
29
+ />
30
+ </svg>
31
+ );
32
+ };
@@ -0,0 +1,28 @@
1
+ import { SVGProps } from 'react';
2
+
3
+ interface RelationIconProps extends SVGProps<SVGSVGElement> {
4
+ fill?: string;
5
+ }
6
+
7
+ export const RelationIcon = ({ fill = 'currentColor', ...props }: RelationIconProps) => {
8
+ return (
9
+ <svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
10
+ <path
11
+ d="M8.40767 2.3898C7.62079 0.918033 6.09073 0 4.41496 0C4.26924 0 4.13809 0 3.99237 0.0291439C2.50603 0.145719 1.19456 1.04918 0.495103 2.43352C-0.218923 3.84699 -0.160635 5.49363 0.669966 6.8051C1.486 8.13115 2.89947 8.91803 4.45867 8.91803C6.01787 8.91803 7.34392 8.17486 8.15995 6.93625C9.09255 5.53734 9.17998 3.84699 8.40767 2.3898ZM4.47324 8.102C3.7155 8.102 2.98691 7.86885 2.34574 7.43169C2.47689 6.68852 2.98691 6.03279 3.68636 5.77049C3.93408 5.66849 4.19638 5.62477 4.45867 5.62477C5.26013 5.62477 5.98873 6.0765 6.35303 6.79053C6.45503 6.99454 6.57161 7.37341 6.57161 7.41712C6.52789 7.46084 6.17816 7.66485 6.09073 7.70856C5.58071 7.97086 5.04155 8.102 4.47324 8.102ZM4.9104 4.6776C4.76468 4.76503 4.61896 4.80874 4.45867 4.80874C4.16723 4.80874 3.89037 4.66302 3.73008 4.40073C3.56978 4.16758 3.55521 3.87614 3.67179 3.59927C3.77379 3.36612 4.03609 3.14754 4.25467 3.1184C4.31295 3.1184 4.37124 3.1184 4.4441 3.1184C4.92498 3.1184 5.20184 3.45355 5.28927 3.74499C5.36213 4.03643 5.31842 4.42987 4.9104 4.69217V4.6776ZM7.22734 6.79053C6.97962 6.06193 6.44046 5.44991 5.69729 5.07104C6.0033 4.73588 6.16359 4.28415 6.11987 3.81785C6.07616 3.26412 5.77015 2.76867 5.2747 2.4918C5.01241 2.34608 4.73554 2.27322 4.4441 2.27322C3.81751 2.27322 3.23463 2.65209 2.95776 3.2204C2.66632 3.80328 2.73918 4.47359 3.16177 5.01275C3.16177 5.01275 3.19091 5.05647 3.23463 5.08561C2.54975 5.37705 1.96687 6.00364 1.69 6.76138C1.69 6.76138 1.67543 6.77596 1.67543 6.8051C1.63171 6.76138 1.57343 6.68853 1.51514 6.60109C0.69911 5.46448 0.582534 4.06557 1.20913 2.82696C1.85029 1.58834 3.07434 0.816029 4.42953 0.816029C4.8084 0.816029 5.20184 0.874317 5.58071 0.990893C6.77561 1.36976 7.67907 2.34608 7.98508 3.61384C8.26195 4.76503 7.98508 5.93078 7.22734 6.79053Z"
12
+ fill={fill}
13
+ />
14
+ <path
15
+ d="M15.3874 9.29697C14.5713 7.91263 13.1433 7.08203 11.555 7.08203C11.4529 7.08203 11.3364 7.08203 11.2198 7.0966C9.52945 7.21318 8.11597 8.21864 7.44566 9.77784C6.77535 11.337 7.02308 13.0565 8.1014 14.3826C8.94657 15.4026 10.1998 16.0001 11.5258 16.0001C13.1724 16.0001 14.6151 15.1549 15.4165 13.7414C16.2034 12.3425 16.1888 10.6959 15.3874 9.29697ZM11.555 15.184C10.8992 15.184 10.258 15.0092 9.64603 14.6449C9.57317 14.6157 9.45659 14.5283 9.42745 14.5283C9.38373 14.3972 9.73346 13.6977 9.90832 13.4791C10.3163 12.9837 10.8846 12.7068 11.5112 12.7068C12.4584 12.7068 13.493 13.348 13.697 14.4554C13.1142 14.9217 12.3564 15.184 11.555 15.184ZM10.6952 11.1039C10.6661 10.7104 10.8701 10.2733 11.3801 10.1859C11.4384 10.1859 11.4967 10.1713 11.555 10.1713C12.1087 10.1713 12.371 10.623 12.3856 11.031C12.3856 11.4536 12.1378 11.8762 11.5258 11.9053C11.0012 11.9053 10.7389 11.4973 10.6952 11.1039ZM14.3091 13.8871C14.0759 13.144 13.493 12.4882 12.779 12.1822C13.1724 11.7305 13.3182 11.1039 13.1287 10.5064C12.9101 9.8507 12.3564 9.41354 11.6715 9.36983H11.555C10.8264 9.36983 10.2289 9.77784 9.98118 10.4482C9.74803 11.0456 9.87918 11.7013 10.3018 12.1822C9.60231 12.4882 9.03401 13.1148 8.75714 13.8871C7.86825 12.8234 7.64967 11.4099 8.2034 10.1276C8.78628 8.75781 10.054 7.89806 11.5112 7.89806C11.6861 7.89806 11.861 7.91263 12.0358 7.9272C13.4056 8.11664 14.5276 9.04924 14.9794 10.3899C15.4019 11.6139 15.1397 12.94 14.3091 13.8871Z"
16
+ fill={fill}
17
+ />
18
+ <path
19
+ d="M14.2213 6.73181C14.2213 6.81924 14.163 6.87753 14.0756 6.87753H13.551C13.551 6.87753 13.4781 6.86295 13.449 6.83381C13.4198 6.80467 13.4052 6.77552 13.4052 6.73181C13.4198 5.65348 12.9972 4.61887 12.1958 3.81742C11.4089 3.03053 10.3889 2.59337 9.29596 2.59337C9.2231 2.59337 9.12109 2.52051 9.12109 2.44765V1.92306C9.12109 1.83563 9.17938 1.77734 9.26681 1.77734C10.5929 1.77734 11.8606 2.31651 12.7932 3.24911C13.7258 4.21086 14.2358 5.4349 14.2213 6.73181Z"
20
+ fill={fill}
21
+ />
22
+ <path
23
+ d="M6.88038 13.551V14.0901C6.88038 14.0901 6.82209 14.2213 6.73466 14.2213H6.67637C5.39404 14.2358 4.15542 13.7113 3.22282 12.7641C2.29022 11.8169 1.76562 10.5491 1.76562 9.26681C1.76562 9.17938 1.83848 9.12109 1.91134 9.12109H2.43593C2.43593 9.12109 2.52337 9.13567 2.55251 9.16481C2.56708 9.19395 2.58165 9.2231 2.58165 9.26681C2.58165 10.3451 3.00424 11.3797 3.79113 12.1812C4.57801 12.9681 5.61262 13.4198 6.70552 13.4198C6.79295 13.4198 6.88038 13.4781 6.88038 13.551Z"
24
+ fill={fill}
25
+ />
26
+ </svg>
27
+ );
28
+ };
@@ -53,3 +53,5 @@ export { FileIcon } from './FileIcon';
53
53
  export { IosIcon } from './IosIcon';
54
54
  export { AndroidIcon } from './AndroidIcon';
55
55
  export { MicrosoftIcon } from './MicrosoftIcon';
56
+ export { FolderAlertIcon } from './FolderAlertIcon';
57
+ export { RelationIcon } from './RelationIcon';
@@ -41,6 +41,7 @@ export const Input: any = forwardRef<InputRefElement<InputProps['multiline']>, I
41
41
  $size={size}
42
42
  $variant={variant}
43
43
  $disabled={!!disabled}
44
+ $multiline={multiline}
44
45
  >
45
46
  {!!prepend && prepend}
46
47
  <InputGroup $size={size} $variant={variant}>
@@ -52,7 +53,7 @@ export const Input: any = forwardRef<InputRefElement<InputProps['multiline']>, I
52
53
  ref={ref as Ref<InputRefElement<true>>}
53
54
  />
54
55
  ) : (
55
- <input disabled={disabled} {...(props as InputElementProps)} ref={ref as Ref<InputRefElement<false>>} />
56
+ <StyledInput disabled={disabled} {...(props as InputElementProps)} ref={ref as Ref<InputRefElement<false>>} />
56
57
  )}
57
58
  {!!error && (
58
59
  <IconWrapper $variant={variant}>
@@ -88,31 +89,38 @@ const TextAreaInput = forwardRef<HTMLTextAreaElement, TextAreaInputProps>(functi
88
89
 
89
90
  return (
90
91
  <div style={{ position: 'relative', width: '100%' }}>
91
- <textarea disabled={disabled} {...props} rows={areaSize} ref={ref} />
92
- <div
92
+ <StyledTextarea disabled={disabled} {...props} rows={areaSize} ref={ref} />
93
+ <SizeContainer
93
94
  ref={divRef}
95
+ $size={size}
94
96
  style={{
95
- position: 'absolute',
96
- top: 0,
97
- left: 0,
98
- right: 0,
99
- height: 'auto',
100
- opacity: 0,
101
- zIndex: -1,
102
- pointerEvents: 'none',
103
97
  minHeight: rowHeight.current * Number(rows),
104
- wordBreak: 'break-word',
105
- whiteSpace: 'pre-wrap',
106
98
  }}
107
99
  >
108
- {props.value}
109
- </div>
100
+ {(props.value || '') + '\u200B'}
101
+ </SizeContainer>
110
102
  </div>
111
103
  );
112
104
  });
113
105
 
114
- const InputGroup = styled.div<{ $size: InputSize; $variant?: InputVariant }>(
115
- ({ theme, $size, $variant = 'outlined' }) => `
106
+ type StyledInputProps = { $size: InputSize; $variant: InputVariant };
107
+ type StyledGroupProps = StyledInputProps & {
108
+ $align: 'flex-start' | 'center';
109
+ $disabled: boolean;
110
+ $error?: boolean;
111
+ $multiline?: boolean;
112
+ };
113
+
114
+ const StyledTextarea = styled.textarea`
115
+ resize: none;
116
+ margin: 0;
117
+ display: block;
118
+ `;
119
+
120
+ const StyledInput = styled.input``;
121
+
122
+ const InputGroup = styled.div<StyledInputProps>(
123
+ ({ theme, $size, $variant }) => `
116
124
  display: inline-flex;
117
125
  align-items: center;
118
126
  width: 100%;
@@ -123,7 +131,7 @@ const InputGroup = styled.div<{ $size: InputSize; $variant?: InputVariant }>(
123
131
  height: ${theme.input.sizes[$size].iconSize};
124
132
  }
125
133
 
126
- & input, & textarea, & ${EditableContainer} {
134
+ & ${StyledInput}, & ${StyledTextarea}{
127
135
  font-size: ${theme.input.sizes[$size].fontSize};
128
136
  color: inherit;
129
137
  background: transparent;
@@ -148,12 +156,24 @@ const InputGroup = styled.div<{ $size: InputSize; $variant?: InputVariant }>(
148
156
  outline: none;
149
157
  }
150
158
  }
159
+ `
160
+ );
151
161
 
152
- & textarea {
153
- resize: none;
154
- margin: 0;
155
- display: block;
156
- }
162
+ const SizeContainer = styled.div<{ $size: InputSize }>(
163
+ ({ theme, $size }) => `
164
+ position: absolute;
165
+ top: 0;
166
+ left: 0;
167
+ right: 0;
168
+ height: auto;
169
+ opacity: 0;
170
+ z-index: -1;
171
+ pointer-events: none;
172
+ padding-inline: ${theme.input.sizes[$size].paddingInline};
173
+ font-size: ${theme.input.sizes[$size].fontSize};
174
+ line-height: ${theme.input.sizes[$size].lineHeight};
175
+ word-break: break-word;
176
+ white-space: pre-wrap;
157
177
  `
158
178
  );
159
179
 
@@ -168,20 +188,14 @@ const IconWrapper = styled.span<{ $variant: InputVariant }>(
168
188
  `
169
189
  );
170
190
 
171
- const Group = styled.div<{
172
- $align: 'flex-start' | 'center';
173
- $disabled: boolean;
174
- $error?: boolean;
175
- $size: InputSize;
176
- $variant: InputVariant;
177
- }>(
178
- ({ theme, $align = 'center', $disabled, $error, $size, $variant }) => `
191
+ const Group = styled.div<StyledGroupProps>(
192
+ ({ theme, $align = 'center', $disabled, $error, $size, $variant, $multiline }) => `
179
193
  display: inline-flex;
180
194
  align-items: ${$align};
181
195
  width: 100%;
182
196
  border: 1px solid;
183
197
  border-radius: ${theme.input.sizes[$size].borderRadius};
184
- height: ${theme.input.sizes[$size].height};
198
+ height: ${$multiline ? 'auto' : theme.input.sizes[$size].height};
185
199
  overflow: hidden;
186
200
  transition: all 0.2s ease;
187
201
 
@@ -226,27 +240,3 @@ const Group = styled.div<{
226
240
  }
227
241
  `
228
242
  );
229
-
230
- const EditableContainer = styled.div<{ $placeholder?: string }>(
231
- ({ $placeholder, theme }) => `
232
- outline-style: none;
233
- outline-width: 0px;
234
- position: relative;
235
-
236
- ${
237
- $placeholder
238
- ? `
239
- &:after {
240
- content: '${$placeholder}';
241
- position: absolute;
242
- top: 0;
243
- left: 0;
244
- color: ${theme.input.outlined.default.placeholder};
245
- }
246
- `
247
- : ''
248
- }
249
-
250
-
251
- `
252
- );
@@ -37,10 +37,12 @@ export const Label = ({
37
37
 
38
38
  return (
39
39
  <StyledLabel $size={size} $direction={direction} $fullWidth={fullWidth} $isRow={$isRow} {...props}>
40
- <LabelWrapper $width={$width}>
41
- {!!label && <LabelText $size={size}>{label}</LabelText>}
42
- {!!helpText && <HelpText $size={size}>{helpText}</HelpText>}
43
- </LabelWrapper>
40
+ {Boolean(label || helpText) && (
41
+ <LabelWrapper $width={$width}>
42
+ {!!label && <LabelText $size={size}>{label}</LabelText>}
43
+ {!!helpText && <HelpText $size={size}>{helpText}</HelpText>}
44
+ </LabelWrapper>
45
+ )}
44
46
  <Wrapper $width={$width}>
45
47
  {children}
46
48
  {!!errorText && <ErrorText $size={size}>{errorText}</ErrorText>}
@@ -0,0 +1,53 @@
1
+ import { createComponent, FabricComponent, propToRem, pxToRem } from '../../Theme';
2
+ import { styled } from 'styled-components';
3
+
4
+ type Direction = 'horizontal' | 'vertical';
5
+
6
+ type LinerProgressProps = FabricComponent<
7
+ {
8
+ height?: number;
9
+ width?: string | number;
10
+ direction?: Direction;
11
+ value: number;
12
+ } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, 'children'>
13
+ >;
14
+
15
+ export const LinerProgress = ({
16
+ height = 21,
17
+ width = '100%',
18
+ direction = 'horizontal',
19
+ value,
20
+ ...props
21
+ }: LinerProgressProps) => {
22
+ return <StyledLine {...props} $height={height} $value={value} $width={width} $direction={direction} />;
23
+ };
24
+
25
+ interface StyledLineProps {
26
+ $height: number;
27
+ $value: number;
28
+ $width: string | number;
29
+ $direction: Direction;
30
+ }
31
+
32
+ const StyledLine = createComponent(
33
+ styled.div<StyledLineProps>(
34
+ ({ theme, $height, $value, $width, $direction }) => `
35
+ width: ${propToRem($width, theme.baseSize)};
36
+ height: ${propToRem($height, theme.baseSize)};
37
+ background-color: ${theme.leanerProgress.background};
38
+ position: relative;
39
+ overflow: hidden;
40
+ border-radius: ${pxToRem(2, theme.baseSize)};
41
+ &::after {
42
+ position: absolute;
43
+ content: '';
44
+ left: 0;
45
+ bottom: 0;
46
+ width: ${$direction === 'horizontal' ? `${$value}%` : propToRem($width, theme.baseSize)};
47
+ height: ${$direction === 'horizontal' ? '100%' : `${$value}%`};
48
+ background-color: ${theme.leanerProgress.progressColor};
49
+ border-radius: ${pxToRem(2, theme.baseSize)};
50
+ }
51
+ `
52
+ )
53
+ );
@@ -0,0 +1 @@
1
+ export * from './LinerProgress';
@@ -0,0 +1,71 @@
1
+ import { InputHTMLAttributes } from 'react';
2
+ import { createComponent, destructSpaceProps, FabricComponent, pxToRem } from '../../Theme';
3
+ import { styled } from 'styled-components';
4
+
5
+ type SwitchProps = FabricComponent<Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>>;
6
+
7
+ export const Switch = ({ className, ...props }: SwitchProps) => {
8
+ const spaceProps = destructSpaceProps(props);
9
+ return (
10
+ <StyledLabel className={className} {...spaceProps}>
11
+ <HiddenInput type="checkbox" {...props} />
12
+ <StyledSwitch />
13
+ </StyledLabel>
14
+ );
15
+ };
16
+
17
+ const StyledSwitch = styled.span(
18
+ ({ theme }) => `
19
+ position: relative;
20
+ cursor: pointer;
21
+ display: inline-block;
22
+ width: ${pxToRem(41, theme.baseSize)};
23
+ height: ${pxToRem(21, theme.baseSize)};
24
+ border-radius: ${pxToRem(15, theme.baseSize)};
25
+ background-color: ${theme.switch.default.background};
26
+ &::before {
27
+ position: absolute;
28
+ display: block;
29
+ top: 50%;
30
+ transform: translateY(-50%);
31
+ height: ${pxToRem(15, theme.baseSize)};
32
+ width: ${pxToRem(15, theme.baseSize)};
33
+ border-radius: 50%;
34
+ background-color: ${theme.switch.default.color};
35
+ content: '';
36
+ }
37
+ `
38
+ );
39
+ const HiddenInput = styled.input(
40
+ ({ theme }) => `
41
+ appearance: none;
42
+ border: none;
43
+ outline: none;
44
+ position: absolute;
45
+ height: 1px;
46
+ width: 1px;
47
+ margin: -1px;
48
+ top: 0;
49
+ left: 0;
50
+ &:not(:checked) + ${StyledSwitch}::before {
51
+ left: ${pxToRem(3, theme.baseSize)};
52
+ }
53
+ &:checked + ${StyledSwitch} {
54
+ background-color: ${theme.switch.checked.background};
55
+ &::before {
56
+ right: ${pxToRem(3, theme.baseSize)};
57
+ }
58
+ }
59
+ &:disabled + ${StyledSwitch} {
60
+ background-color: ${theme.switch.disabled.background};
61
+ cursor: not-allowed;
62
+ }
63
+ `
64
+ );
65
+
66
+ const StyledLabel = createComponent(
67
+ styled.label`
68
+ position: relative;
69
+ display: inline-block;
70
+ `
71
+ );
@@ -0,0 +1 @@
1
+ export * from './Switch';
package/src/Core/index.ts CHANGED
@@ -18,3 +18,6 @@ export * from './Tag';
18
18
  export * from './Alert';
19
19
  export * from './Label';
20
20
  export * from './Checkbox';
21
+ export * from './LinerProgress';
22
+ export * from './Switch';
23
+ export * from './Drawer';
@@ -4,3 +4,4 @@ export * from './utils';
4
4
  export * from './types';
5
5
  export * from './themes';
6
6
  export * from './componentFabric';
7
+ export * from './useTheme';