@cyber-harbour/ui 1.0.53 → 1.0.54

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.54",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -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
  {
@@ -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,5 @@ 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';
@@ -36,7 +36,7 @@ export const darkThemePx: Theme = {
36
36
  },
37
37
  disable: '#080A0C',
38
38
  success: '#27AE60',
39
- error: '#FF3B30',
39
+ error: '#C93939',
40
40
  warning: '#F2994A',
41
41
  info: '#2F80ED',
42
42
  },
@@ -776,6 +776,24 @@ export const darkThemePx: Theme = {
776
776
  color: '#ffffff',
777
777
  helpTextColor: '#535353',
778
778
  },
779
+ leanerProgress: {
780
+ background: '#1E2226',
781
+ progressColor: '#158EFF',
782
+ },
783
+ switch: {
784
+ default: {
785
+ background: '#34404C',
786
+ color: '#0F1317',
787
+ },
788
+ checked: {
789
+ background: '#158EFF',
790
+ color: '#0F1317',
791
+ },
792
+ disabled: {
793
+ background: '#1E2226',
794
+ color: '#0F1317',
795
+ },
796
+ },
779
797
  };
780
798
 
781
799
  export const darkTheme = convertPaletteToRem(darkThemePx, darkThemePx.baseSize) as DefaultTheme;
@@ -35,7 +35,7 @@ export const lightThemePx: Theme = {
35
35
  },
36
36
  disable: '#FAFAFA',
37
37
  success: '#27AE60',
38
- error: '#FF3B30',
38
+ error: '#C93939',
39
39
  warning: '#F2994A',
40
40
  info: '#2F80ED',
41
41
  },
@@ -775,6 +775,24 @@ export const lightThemePx: Theme = {
775
775
  color: '#101010',
776
776
  helpTextColor: '#99989C',
777
777
  },
778
+ leanerProgress: {
779
+ background: '#EBEBEB',
780
+ progressColor: '#0042EC',
781
+ },
782
+ switch: {
783
+ default: {
784
+ background: '#C7C5C5',
785
+ color: '#FFFFFF',
786
+ },
787
+ checked: {
788
+ background: '#0042EC',
789
+ color: '#FFFFFF',
790
+ },
791
+ disabled: {
792
+ background: '#EBEBEB',
793
+ color: '#FFFFFF',
794
+ },
795
+ },
778
796
  };
779
797
 
780
798
  export const lightTheme = convertPaletteToRem(lightThemePx, lightThemePx.baseSize) as DefaultTheme;
@@ -30,6 +30,7 @@ export type LabelSizeStyle = {
30
30
  helpText: { fontSize: number | string; marginTop: number | string };
31
31
  };
32
32
 
33
+ export type SwitchState = 'default' | 'checked' | 'disabled';
33
34
  // Типи для spacing та breakpoints
34
35
  export type Breakpoint = 'xs' | 's' | 'm' | 'l' | 'xl';
35
36
 
@@ -287,6 +288,17 @@ export type Theme = {
287
288
  color: string;
288
289
  helpTextColor: string;
289
290
  };
291
+ leanerProgress: {
292
+ background: string;
293
+ progressColor: string;
294
+ };
295
+ switch: Record<
296
+ SwitchState,
297
+ {
298
+ background: string;
299
+ color: string;
300
+ }
301
+ >;
290
302
  };
291
303
 
292
304
  //TODO check and refactoring