@cyber-harbour/ui 1.0.44 → 1.0.46

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.44",
3
+ "version": "1.0.46",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -27,8 +27,8 @@
27
27
  "license": "ISC",
28
28
  "description": "",
29
29
  "dependencies": {
30
- "@types/d3-force": "^3.0.10",
31
- "d3-force": "^3.0.0",
30
+ "d3": "^7.9.0",
31
+ "lodash.clonedeep": "^4.5.0",
32
32
  "react-content-loader": "^7.0.2",
33
33
  "react-force-graph-2d": "^1.27.1",
34
34
  "react-tiny-popover": "^8.1.6",
@@ -47,6 +47,8 @@
47
47
  "@storybook/react": "^8.6.14",
48
48
  "@storybook/react-vite": "^8.6.14",
49
49
  "@storybook/test": "^8.6.14",
50
+ "@types/d3": "^7.4.3",
51
+ "@types/lodash.clonedeep": "^4.5.9",
50
52
  "@types/styled-components": "^5.1.34",
51
53
  "@vitest/browser": "^3.1.3",
52
54
  "@vitest/coverage-v8": "^3.1.3",
@@ -1,9 +1,9 @@
1
- import { InputSize, InputSizeStyle, InputVariant, getInputStyles } from '../../Theme';
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
- export type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> & {
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 const Input: any = forwardRef<HTMLInputElement, InputProps>(function Input(
15
- { error, append, prepend, size = 'small', variant = 'outlined', disabled, className, ...props },
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 className={className} $error={error} $size={size} $variant={variant} $disabled={!!disabled}>
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
- <input ref={ref} disabled={disabled} {...props} />
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<{ $disabled: boolean; $error?: boolean; $size: InputSize; $variant: InputVariant }>(
82
- ({ theme, $disabled, $error, $size, $variant }) => `
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: center;
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
+ );