@cyber-harbour/ui 1.0.43 → 1.0.45
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 +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +123 -97
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +123 -97
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/Core/Input/Input.tsx +134 -14
- package/src/Theme/themes/dark.ts +8 -5
- package/src/Theme/themes/light.ts +3 -0
- package/src/Theme/types.ts +1 -0
- package/src/Theme/utils.ts +10 -0
package/package.json
CHANGED
package/src/Core/Input/Input.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { InputSize,
|
|
2
|
-
import { forwardRef, InputHTMLAttributes, Ref } from 'react';
|
|
3
|
-
import { styled } from 'styled-components';
|
|
1
|
+
import { InputSize, InputVariant, remToPx } from '../../Theme';
|
|
2
|
+
import { forwardRef, InputHTMLAttributes, Ref, TextareaHTMLAttributes, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { styled, useTheme } from 'styled-components';
|
|
4
4
|
import { InfoCircleFilledIcon } from '../IconComponents';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
type BaseInputProps = {
|
|
7
7
|
error?: boolean;
|
|
8
8
|
append?: any;
|
|
9
9
|
prepend?: any;
|
|
@@ -11,15 +11,49 @@ export type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> & {
|
|
|
11
11
|
variant?: InputVariant;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export
|
|
15
|
-
|
|
14
|
+
export type InputElementProps = BaseInputProps &
|
|
15
|
+
InputHTMLAttributes<HTMLInputElement> & {
|
|
16
|
+
multiline?: false;
|
|
17
|
+
};
|
|
18
|
+
export type TextAreaElementProps = BaseInputProps &
|
|
19
|
+
TextareaHTMLAttributes<HTMLTextAreaElement> & {
|
|
20
|
+
multiline: true;
|
|
21
|
+
autoResize?: boolean;
|
|
22
|
+
};
|
|
23
|
+
export type InputProps = InputElementProps | TextAreaElementProps;
|
|
24
|
+
|
|
25
|
+
type TextAreaInputProps = TextareaHTMLAttributes<HTMLTextAreaElement> & {
|
|
26
|
+
size?: InputSize;
|
|
27
|
+
autoResize?: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type InputRefElement<T> = T extends true ? HTMLTextAreaElement : HTMLInputElement | null;
|
|
31
|
+
|
|
32
|
+
export const Input: any = forwardRef<InputRefElement<InputProps['multiline']>, InputProps>(function Input(
|
|
33
|
+
{ error, append, prepend, size = 'small', variant = 'outlined', multiline, disabled, className, ...props },
|
|
16
34
|
ref
|
|
17
35
|
) {
|
|
18
36
|
return (
|
|
19
|
-
<Group
|
|
37
|
+
<Group
|
|
38
|
+
$align={multiline ? 'flex-start' : 'center'}
|
|
39
|
+
className={className}
|
|
40
|
+
$error={error}
|
|
41
|
+
$size={size}
|
|
42
|
+
$variant={variant}
|
|
43
|
+
$disabled={!!disabled}
|
|
44
|
+
>
|
|
20
45
|
{!!prepend && prepend}
|
|
21
46
|
<InputGroup $size={size} $variant={variant}>
|
|
22
|
-
|
|
47
|
+
{multiline ? (
|
|
48
|
+
<TextAreaInput
|
|
49
|
+
size={size}
|
|
50
|
+
disabled={disabled}
|
|
51
|
+
{...(props as TextAreaElementProps)}
|
|
52
|
+
ref={ref as Ref<InputRefElement<true>>}
|
|
53
|
+
/>
|
|
54
|
+
) : (
|
|
55
|
+
<input disabled={disabled} {...(props as InputElementProps)} ref={ref as Ref<InputRefElement<false>>} />
|
|
56
|
+
)}
|
|
23
57
|
{!!error && (
|
|
24
58
|
<IconWrapper $variant={variant}>
|
|
25
59
|
<InfoCircleFilledIcon />
|
|
@@ -31,6 +65,52 @@ export const Input: any = forwardRef<HTMLInputElement, InputProps>(function Inpu
|
|
|
31
65
|
);
|
|
32
66
|
});
|
|
33
67
|
|
|
68
|
+
const TextAreaInput = forwardRef<HTMLTextAreaElement, TextAreaInputProps>(function Input(
|
|
69
|
+
{ size = 'small', disabled, className, rows = '1', autoResize = false, ...props },
|
|
70
|
+
ref
|
|
71
|
+
) {
|
|
72
|
+
const [areaSize, setAreaSize] = useState(Number(rows));
|
|
73
|
+
const rowsRef = useRef(Number(rows));
|
|
74
|
+
const divRef = useRef<HTMLDivElement>(null);
|
|
75
|
+
const theme = useTheme();
|
|
76
|
+
const rowHeight = useRef(remToPx(theme.input.sizes[size].lineHeight, theme.baseSize) || theme.baseSize);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (divRef.current && autoResize) {
|
|
80
|
+
const height = divRef.current.getBoundingClientRect().height;
|
|
81
|
+
const areaSize = Math.round(height / rowHeight.current);
|
|
82
|
+
if (rowsRef.current !== areaSize) {
|
|
83
|
+
rowsRef.current = areaSize;
|
|
84
|
+
setAreaSize(areaSize);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}, [props.value]);
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div style={{ position: 'relative', width: '100%' }}>
|
|
91
|
+
<textarea disabled={disabled} {...props} rows={areaSize} ref={ref} />
|
|
92
|
+
<div
|
|
93
|
+
ref={divRef}
|
|
94
|
+
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
|
+
minHeight: rowHeight.current * Number(rows),
|
|
104
|
+
wordBreak: 'break-word',
|
|
105
|
+
whiteSpace: 'pre-wrap',
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
{props.value}
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
34
114
|
const InputGroup = styled.div<{ $size: InputSize; $variant?: InputVariant }>(
|
|
35
115
|
({ theme, $size, $variant = 'outlined' }) => `
|
|
36
116
|
display: inline-flex;
|
|
@@ -43,7 +123,7 @@ const InputGroup = styled.div<{ $size: InputSize; $variant?: InputVariant }>(
|
|
|
43
123
|
height: ${theme.input.sizes[$size].iconSize};
|
|
44
124
|
}
|
|
45
125
|
|
|
46
|
-
& input {
|
|
126
|
+
& input, & textarea, & ${EditableContainer} {
|
|
47
127
|
font-size: ${theme.input.sizes[$size].fontSize};
|
|
48
128
|
color: inherit;
|
|
49
129
|
background: transparent;
|
|
@@ -63,6 +143,16 @@ const InputGroup = styled.div<{ $size: InputSize; $variant?: InputVariant }>(
|
|
|
63
143
|
cursor: not-allowed;
|
|
64
144
|
color: inherit;
|
|
65
145
|
}
|
|
146
|
+
|
|
147
|
+
&:focus, &:focus-visible, &:focus:focus-visible {
|
|
148
|
+
outline: none;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
& textarea {
|
|
153
|
+
resize: none;
|
|
154
|
+
margin: 0;
|
|
155
|
+
display: block;
|
|
66
156
|
}
|
|
67
157
|
`
|
|
68
158
|
);
|
|
@@ -74,14 +164,20 @@ const IconWrapper = styled.span<{ $variant: InputVariant }>(
|
|
|
74
164
|
align-items: center;
|
|
75
165
|
color: ${theme.input[$variant].error.icon};
|
|
76
166
|
margin-right: 10px;
|
|
77
|
-
|
|
167
|
+
|
|
78
168
|
`
|
|
79
169
|
);
|
|
80
170
|
|
|
81
|
-
const Group = styled.div<{
|
|
82
|
-
|
|
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 }) => `
|
|
83
179
|
display: inline-flex;
|
|
84
|
-
align-items:
|
|
180
|
+
align-items: ${$align};
|
|
85
181
|
width: 100%;
|
|
86
182
|
border: 1px solid;
|
|
87
183
|
border-radius: ${theme.input.sizes[$size].borderRadius};
|
|
@@ -110,7 +206,7 @@ const Group = styled.div<{ $disabled: boolean; $error?: boolean; $size: InputSiz
|
|
|
110
206
|
&:hover {
|
|
111
207
|
border-color: ${theme.input[$variant].focus.border};
|
|
112
208
|
}
|
|
113
|
-
|
|
209
|
+
|
|
114
210
|
&:focus-within {
|
|
115
211
|
border-color: ${theme.input[$variant].focus.border};
|
|
116
212
|
color: ${theme.input[$variant].focus.text};
|
|
@@ -130,3 +226,27 @@ const Group = styled.div<{ $disabled: boolean; $error?: boolean; $size: InputSiz
|
|
|
130
226
|
}
|
|
131
227
|
`
|
|
132
228
|
);
|
|
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
|
+
);
|
package/src/Theme/themes/dark.ts
CHANGED
|
@@ -488,7 +488,7 @@ export const darkThemePx: Theme = {
|
|
|
488
488
|
boxShadow: 'none',
|
|
489
489
|
},
|
|
490
490
|
disabled: {
|
|
491
|
-
background: '#
|
|
491
|
+
background: '#080A0C',
|
|
492
492
|
text: '#99989C',
|
|
493
493
|
border: ' #1E2226',
|
|
494
494
|
boxShadow: 'none',
|
|
@@ -529,7 +529,7 @@ export const darkThemePx: Theme = {
|
|
|
529
529
|
boxShadow: 'none',
|
|
530
530
|
},
|
|
531
531
|
disabled: {
|
|
532
|
-
background: '#
|
|
532
|
+
background: '#080A0C',
|
|
533
533
|
text: '#99989C',
|
|
534
534
|
border: ' none',
|
|
535
535
|
boxShadow: 'none',
|
|
@@ -558,7 +558,7 @@ export const darkThemePx: Theme = {
|
|
|
558
558
|
boxShadow: 'none',
|
|
559
559
|
},
|
|
560
560
|
disabled: {
|
|
561
|
-
background: '#
|
|
561
|
+
background: '#080A0C',
|
|
562
562
|
text: '#99989C',
|
|
563
563
|
border: ' none',
|
|
564
564
|
boxShadow: 'none',
|
|
@@ -579,6 +579,7 @@ export const darkThemePx: Theme = {
|
|
|
579
579
|
borderRadius: 0,
|
|
580
580
|
iconSize: 14,
|
|
581
581
|
height: 'auto',
|
|
582
|
+
lineHeight: 16,
|
|
582
583
|
},
|
|
583
584
|
small: {
|
|
584
585
|
fontSize: 14,
|
|
@@ -587,6 +588,7 @@ export const darkThemePx: Theme = {
|
|
|
587
588
|
borderRadius: 5,
|
|
588
589
|
iconSize: 14,
|
|
589
590
|
height: 40,
|
|
591
|
+
lineHeight: 16,
|
|
590
592
|
},
|
|
591
593
|
medium: {
|
|
592
594
|
fontSize: 16,
|
|
@@ -595,6 +597,7 @@ export const darkThemePx: Theme = {
|
|
|
595
597
|
borderRadius: 5,
|
|
596
598
|
iconSize: 16,
|
|
597
599
|
height: 40,
|
|
600
|
+
lineHeight: 18,
|
|
598
601
|
},
|
|
599
602
|
},
|
|
600
603
|
outlined: {
|
|
@@ -623,7 +626,7 @@ export const darkThemePx: Theme = {
|
|
|
623
626
|
icon: '#C93939',
|
|
624
627
|
},
|
|
625
628
|
disabled: {
|
|
626
|
-
background: '#
|
|
629
|
+
background: '#080A0C',
|
|
627
630
|
text: '#99989C',
|
|
628
631
|
placeholder: '#99989C',
|
|
629
632
|
border: ' #1E2226',
|
|
@@ -657,7 +660,7 @@ export const darkThemePx: Theme = {
|
|
|
657
660
|
icon: '#C93939',
|
|
658
661
|
},
|
|
659
662
|
disabled: {
|
|
660
|
-
background: '
|
|
663
|
+
background: 'transparent',
|
|
661
664
|
text: '#99989C',
|
|
662
665
|
placeholder: '#99989C',
|
|
663
666
|
border: 'transparent',
|
|
@@ -578,6 +578,7 @@ export const lightThemePx: Theme = {
|
|
|
578
578
|
borderRadius: 0,
|
|
579
579
|
iconSize: 14,
|
|
580
580
|
height: 'auto',
|
|
581
|
+
lineHeight: 16,
|
|
581
582
|
},
|
|
582
583
|
small: {
|
|
583
584
|
fontSize: 14,
|
|
@@ -586,6 +587,7 @@ export const lightThemePx: Theme = {
|
|
|
586
587
|
borderRadius: 5,
|
|
587
588
|
iconSize: 14,
|
|
588
589
|
height: 40,
|
|
590
|
+
lineHeight: 16,
|
|
589
591
|
},
|
|
590
592
|
medium: {
|
|
591
593
|
fontSize: 16,
|
|
@@ -594,6 +596,7 @@ export const lightThemePx: Theme = {
|
|
|
594
596
|
borderRadius: 5,
|
|
595
597
|
iconSize: 16,
|
|
596
598
|
height: 40,
|
|
599
|
+
lineHeight: 18,
|
|
597
600
|
},
|
|
598
601
|
},
|
|
599
602
|
outlined: {
|
package/src/Theme/types.ts
CHANGED
package/src/Theme/utils.ts
CHANGED
|
@@ -73,6 +73,16 @@ export const pxToRem = (pxValue: number | string, baseSize: number = 16): string
|
|
|
73
73
|
return `${remValue}rem`;
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
+
export const remToPx = (remValue: number | string, baseSize: number = 16): number => {
|
|
77
|
+
// If remValue is a string with 'rem' suffix, extract the numeric value
|
|
78
|
+
const numericValue = typeof remValue === 'string' ? parseFloat(remValue.replace('rem', '')) : remValue;
|
|
79
|
+
if (isNaN(numericValue)) {
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return numericValue * baseSize;
|
|
84
|
+
};
|
|
85
|
+
|
|
76
86
|
const IGNORE_CONVERT_KEYS: Record<string, string[] | boolean> = {
|
|
77
87
|
contextMenu: ['padding'],
|
|
78
88
|
baseSize: true,
|