next-helios-fe 1.8.87 → 1.8.88

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": "next-helios-fe",
3
- "version": "1.8.87",
3
+ "version": "1.8.88",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,17 +1,19 @@
1
1
  "use client";
2
- import React, { useState, useEffect } from "react";
2
+ import React, { useState, useEffect, useRef } from "react";
3
3
  import { Tooltip } from "../../../components";
4
4
  import { Icon } from "@iconify/react";
5
5
 
6
6
  export interface TextareaProps
7
7
  extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "rows"> {
8
8
  rows?: number;
9
- maxRows?: number;
10
9
  label?: string;
11
10
  description?: string;
12
11
  options?: {
13
12
  width?: "full" | "fit";
14
13
  height?: "short" | "medium" | "high";
14
+ autoGrow?: {
15
+ maxRows: number;
16
+ };
15
17
  disableResize?: boolean;
16
18
  hideInputDetail?: boolean;
17
19
  };
@@ -19,13 +21,13 @@ export interface TextareaProps
19
21
 
20
22
  export const Textarea: React.FC<TextareaProps> = ({
21
23
  rows,
22
- maxRows,
23
24
  options,
24
25
  label,
25
26
  description,
26
27
  ...rest
27
28
  }) => {
28
- const [tempRows, setTempRows] = useState<number>(rows || 10);
29
+ const mirrorInputRef = useRef<HTMLTextAreaElement>(null);
30
+ const [tempRows, setTempRows] = useState<number>(1);
29
31
  const width = options?.width === "fit" ? "w-fit" : "w-full";
30
32
  const height =
31
33
  options?.height === "short"
@@ -35,36 +37,56 @@ export const Textarea: React.FC<TextareaProps> = ({
35
37
  : "py-1.5";
36
38
 
37
39
  useEffect(() => {
38
- if (maxRows) {
39
- if (rest.value && (rest.value as string)?.includes("\n")) {
40
- if (((rest.value as string).match(/\n/g) || []).length < maxRows) {
41
- setTempRows(((rest.value as string).match(/\n/g) || []).length + 1);
42
- }
40
+ if (options?.autoGrow) {
41
+ if (
42
+ ((mirrorInputRef.current?.scrollHeight || 0) -
43
+ (options?.height === "short"
44
+ ? 4
45
+ : options?.height === "high"
46
+ ? 8
47
+ : 12)) /
48
+ 24 <=
49
+ options?.autoGrow.maxRows
50
+ ) {
51
+ setTempRows(
52
+ ((mirrorInputRef.current?.scrollHeight || 0) -
53
+ (options?.height === "short"
54
+ ? 4
55
+ : options?.height === "high"
56
+ ? 8
57
+ : 12)) /
58
+ 24
59
+ );
43
60
  } else {
44
- setTempRows(rows || 10);
61
+ setTempRows(options?.autoGrow.maxRows);
45
62
  }
46
63
  }
47
- }, [rows, maxRows, rest.value]);
64
+ }, [
65
+ options?.autoGrow,
66
+ mirrorInputRef.current?.scrollHeight,
67
+ rest.value,
68
+ options?.height,
69
+ ]);
48
70
 
49
71
  return (
50
- <label className={`flex flex-col gap-2 ${width}`}>
72
+ <label className={`relative flex flex-col gap-2 ${width}`}>
51
73
  {(label ||
52
74
  (!options?.hideInputDetail && (rest.maxLength || description))) && (
53
75
  <div className="flex items-center gap-2">
54
76
  {label && (
55
77
  <span
56
- className={`text-sm select-none ${
78
+ className={`select-none text-sm ${
57
79
  rest.required &&
58
- "after:content-['*'] after:ml-1 after:text-danger"
80
+ "after:ml-1 after:text-danger after:content-['*']"
59
81
  }`}
60
82
  >
61
83
  {label}
62
84
  </span>
63
85
  )}
64
86
  {!options?.hideInputDetail && (
65
- <div className="flex-1 flex justify-end items-center gap-2">
87
+ <div className="flex flex-1 items-center justify-end gap-2">
66
88
  {rest.maxLength && (
67
- <span className="text-sm select-none">
89
+ <span className="select-none text-sm">
68
90
  {rest.value ? (rest.value as string).length : 0}/
69
91
  {rest.maxLength}
70
92
  </span>
@@ -82,12 +104,20 @@ export const Textarea: React.FC<TextareaProps> = ({
82
104
  </div>
83
105
  )}
84
106
  <textarea
85
- rows={tempRows}
86
- className={`w-full px-4 border-default border rounded-md bg-secondary-bg placeholder:duration-300 placeholder:translate-x-0 focus:placeholder:translate-x-1 placeholder:text-silent focus:outline-none focus:ring-1 focus:ring-primary focus:shadow focus:shadow-primary focus:border-primary-dark disabled:bg-secondary-light disabled:text-disabled ${
107
+ rows={options?.autoGrow ? tempRows : rows || 10}
108
+ className={`w-full rounded-md border border-default bg-secondary-bg px-4 placeholder:translate-x-0 placeholder:text-silent placeholder:duration-300 focus:border-primary-dark focus:shadow focus:shadow-primary focus:outline-none focus:ring-1 focus:ring-primary focus:placeholder:translate-x-1 disabled:bg-secondary-light disabled:text-disabled ${
87
109
  options?.disableResize && "resize-none"
88
110
  } ${height}`}
89
111
  {...rest}
90
112
  />
113
+ <textarea
114
+ ref={mirrorInputRef}
115
+ rows={1}
116
+ className={`absolute w-full rounded-md border border-default bg-secondary-bg px-4 pointer-events-none opacity-0 placeholder:translate-x-0 placeholder:text-silent placeholder:duration-300 focus:border-primary-dark focus:shadow focus:shadow-primary focus:outline-none focus:ring-1 focus:ring-primary focus:placeholder:translate-x-1 disabled:bg-secondary-light disabled:text-disabled ${height}`}
117
+ readOnly
118
+ tabIndex={-1}
119
+ value={rest.value}
120
+ />
91
121
  </label>
92
122
  );
93
123
  };