next-helios-fe 1.3.0 → 1.3.1

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.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,29 +1,27 @@
1
1
  "use client";
2
- import React, { useState, useEffect, useRef } from "react";
2
+ import React, { useState, useEffect } from "react";
3
3
  import { Icon } from "@iconify/react";
4
4
 
5
5
  export interface FileProps extends React.InputHTMLAttributes<HTMLInputElement> {
6
6
  options?: {
7
- variant?: "simple" | "drag&drop";
8
- buttonOnly?: boolean;
9
- maxFileSize?: number;
7
+ variant?: "default" | "drag&drop";
8
+ maxSizeInMb?: number;
10
9
  width?: "full" | "fit";
11
10
  height?: "short" | "medium" | "high";
12
11
  };
13
12
  label?: string;
14
- files?: any;
15
- onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
13
+ defaultValue?: [];
14
+ value?: [];
16
15
  }
17
16
 
18
17
  export const File: React.FC<FileProps> = ({
19
18
  options,
20
19
  label,
21
- files,
22
- onChange,
20
+ defaultValue,
21
+ value,
23
22
  ...rest
24
23
  }) => {
25
- const inputRef = useRef<HTMLInputElement>(null);
26
- const [tempValue, setTempValue] = useState<any>();
24
+ const [tempFile, setTempFile] = useState<any>([]);
27
25
  const width = options?.width === "fit" ? "w-fit" : "w-full";
28
26
  const height =
29
27
  options?.height === "short"
@@ -33,26 +31,35 @@ export const File: React.FC<FileProps> = ({
33
31
  : "py-1.5";
34
32
 
35
33
  useEffect(() => {
36
- if (files) {
37
- setTempValue(files);
34
+ document
35
+ .querySelector("input[type=file]")
36
+ ?.addEventListener("cancel", (e) => {
37
+ setTempFile([]);
38
+ rest.onChange && rest.onChange({ target: { files: [] } } as any);
39
+ });
40
+ }, []);
41
+
42
+ useEffect(() => {
43
+ if (value) {
44
+ setTempFile(value);
45
+ return;
46
+ } else if (defaultValue) {
47
+ setTempFile(defaultValue);
38
48
  return;
39
49
  }
40
- }, [files]);
50
+ }, [value, defaultValue]);
41
51
 
42
52
  useEffect(() => {
43
- onChange &&
44
- onChange({
45
- target: { files: tempValue } as any,
46
- } as React.ChangeEvent<HTMLInputElement>);
47
- }, [tempValue]);
53
+ if (tempFile.length !== 0) {
54
+ rest.onChange &&
55
+ rest.onChange({
56
+ target: { files: tempFile } as HTMLInputElement,
57
+ } as any);
58
+ }
59
+ }, [tempFile]);
48
60
 
49
61
  return (
50
- <div
51
- className={`grid gap-2 ${width}`}
52
- onClick={() => {
53
- inputRef.current?.click();
54
- }}
55
- >
62
+ <label className={`grid gap-2 ${width}`}>
56
63
  {label && (
57
64
  <span
58
65
  className={`text-sm select-none ${
@@ -62,128 +69,123 @@ export const File: React.FC<FileProps> = ({
62
69
  {label}
63
70
  </span>
64
71
  )}
65
- {options?.variant !== "drag&drop" ? (
66
- <div className="w-full flex items-center gap-4">
67
- <button
68
- type="button"
69
- className="p-2 rounded-full hover:bg-secondary-light"
70
- disabled={rest.disabled}
71
- >
72
- <Icon icon="mi:attachment" className="text-xl" />
73
- </button>
74
- {!options?.buttonOnly && (
72
+ <div className="flex flex-row-reverse items-center gap-4">
73
+ {options?.variant !== "drag&drop" ? (
74
+ <div className="relative flex-1 flex items-center">
75
75
  <input
76
- type="text"
77
- className={`flex-1 px-4 border-default border rounded-md bg-secondary-bg cursor-pointer caret-transparent placeholder:duration-300 placeholder:translate-x-0 focus:placeholder:translate-x-1 placeholder:text-slate-300 focus:outline-none focus:ring-1 focus:ring-primary focus:shadow focus:shadow-primary focus:border-primary-dark disabled:bg-secondary-light disabled:text-slate-400 disabled:cursor-default ${height}`}
78
- placeholder={rest.placeholder}
79
- disabled={rest.disabled}
80
- value={
81
- tempValue
82
- ? `${tempValue?.name} (${
83
- tempValue?.size < 1000000
84
- ? `${tempValue?.size / 1000} KB`
85
- : `${tempValue?.size / 1000000} MB`
86
- })`
87
- : ""
88
- }
76
+ type="file"
77
+ className={`peer/file w-full px-4 border-default border rounded-md bg-secondary-bg text-transparent file:hidden focus:outline-none focus:ring-1 focus:ring-primary focus:shadow focus:shadow-primary focus:border-primary-dark disabled:bg-secondary-light disabled:text-slate-400 ${height}`}
78
+ onChange={(e) => {
79
+ rest.onChange && rest.onChange(e);
80
+ setTempFile(e.target.files);
81
+ }}
82
+ {...rest}
89
83
  />
90
- )}
91
- </div>
92
- ) : (
93
- <button
94
- type="button"
95
- className="relative flex flex-col justify-center items-center gap-8 w-full min-h-60 h-full px-4 py-1.5 border border-dashed rounded-md bg-secondary-bg disabled:bg-secondary-light"
96
- onDragEnter={(e) => {
97
- if (!rest.disabled) {
98
- e.preventDefault();
99
- e.stopPropagation();
100
- e.currentTarget.classList.add(
101
- "border-primary",
102
- "bg-secondary-light"
103
- );
104
- }
105
- }}
106
- onDragLeave={(e) => {
107
- if (!rest.disabled) {
108
- e.preventDefault();
109
- e.stopPropagation();
110
- e.currentTarget.classList.remove(
111
- "border-primary",
112
- "bg-secondary-light"
113
- );
114
- }
115
- }}
116
- onDragOver={(e) => {
117
- if (!rest.disabled) {
118
- e.preventDefault();
119
- e.stopPropagation();
120
- }
121
- }}
122
- onDrop={(e) => {
123
- if (!rest.disabled) {
124
- e.preventDefault();
125
- e.stopPropagation();
126
- e.currentTarget.classList.remove(
127
- "border-primary",
128
- "bg-secondary-light"
129
- );
130
- setTempValue(e.dataTransfer.files[0]);
131
- }
132
- }}
133
- disabled={rest.disabled}
134
- >
135
- <Icon
136
- icon={tempValue ? "mdi:file-outline" : "mynaui:upload"}
137
- className={`text-5xl pointer-events-none ${
138
- tempValue ? "" : "text-slate-400"
139
- }`}
140
- />
141
- <div className="flex flex-col gap-2 items-center pointer-events-none">
142
- {tempValue ? (
143
- <span>{tempValue?.name}</span>
144
- ) : (
145
- <div className="flex gap-2 text-slate-400">
146
- <span className="underline underline-offset-2">
147
- Click to upload
148
- </span>
149
- <span>or drag and drop</span>
150
- </div>
151
- )}
152
84
  <span
153
- className={`text-sm font-light ${
154
- tempValue ? "" : "text-slate-400"
85
+ className={`absolute px-4 pointer-events-none ${
86
+ tempFile.length === 0 &&
87
+ "text-slate-300 duration-300 translate-x-0 peer-focus/file:translate-x-1"
155
88
  }`}
156
89
  >
157
- {tempValue
158
- ? `${
159
- tempValue?.size < 1000000
160
- ? `${tempValue?.size / 1000} KB`
161
- : `${tempValue?.size / 1000000} MB`
162
- }`
163
- : `Maximum file size ${options?.maxFileSize} MB`}
90
+ {tempFile[0]?.name ?? rest.placeholder}
164
91
  </span>
165
92
  </div>
166
- {tempValue && (
167
- <div
168
- className="absolute top-4 right-4 p-1 rounded-full hover:bg-secondary-light"
169
- onClick={() => {
170
- setTempValue(null);
93
+ ) : (
94
+ <div className="relative flex-1 flex items-center">
95
+ <input
96
+ type="file"
97
+ className={`w-full h-60 px-4 border-default border border-dashed rounded-md bg-secondary-bg text-transparent cursor-pointer file:hidden focus:outline-none focus:ring-1 focus:ring-primary focus:shadow focus:shadow-primary focus:border-primary-dark disabled:bg-secondary-light`}
98
+ onChange={(e) => {
99
+ rest.onChange && rest.onChange(e);
100
+ setTempFile(e.target.files);
171
101
  }}
172
- >
173
- <Icon icon="pajamas:close" />
102
+ onDragEnter={(e) => {
103
+ if (!rest.disabled) {
104
+ e.preventDefault();
105
+ e.stopPropagation();
106
+ e.currentTarget.classList.add(
107
+ "border-primary",
108
+ "bg-primary-transparent"
109
+ );
110
+ e.currentTarget.classList.remove("bg-secondary-bg");
111
+ }
112
+ }}
113
+ onDragLeave={(e) => {
114
+ if (!rest.disabled) {
115
+ e.preventDefault();
116
+ e.stopPropagation();
117
+ e.currentTarget.classList.remove(
118
+ "border-primary",
119
+ "bg-primary-transparent"
120
+ );
121
+ }
122
+ }}
123
+ onDragOver={(e) => {
124
+ if (!rest.disabled) {
125
+ e.preventDefault();
126
+ e.stopPropagation();
127
+ }
128
+ }}
129
+ onDrop={(e) => {
130
+ if (!rest.disabled) {
131
+ e.preventDefault();
132
+ e.stopPropagation();
133
+ e.currentTarget.classList.remove(
134
+ "border-primary",
135
+ "bg-primary-transparent"
136
+ );
137
+ setTempFile([e.dataTransfer.files[0]]);
138
+ }
139
+ }}
140
+ {...rest}
141
+ />
142
+ <div className="absolute flex flex-col gap-8 justify-center items-center w-full h-full px-4 pointer-events-none">
143
+ <Icon
144
+ icon={
145
+ tempFile.length !== 0 ? "mdi:file-outline" : "mynaui:upload"
146
+ }
147
+ className={`text-5xl ${
148
+ tempFile.length !== 0 ? "" : "text-slate-400"
149
+ }`}
150
+ />
151
+ <div className="flex flex-col gap-2 items-center">
152
+ {tempFile.length !== 0 ? (
153
+ <span>{tempFile[0]?.name}</span>
154
+ ) : (
155
+ <div className="flex gap-2 text-slate-400">
156
+ <span className="underline underline-offset-2">
157
+ Click to upload
158
+ </span>
159
+ <span>or drag and drop</span>
160
+ </div>
161
+ )}
162
+ <span
163
+ className={`text-sm font-light ${
164
+ tempFile.length !== 0 ? "" : "text-slate-400"
165
+ }`}
166
+ >
167
+ {tempFile.length !== 0
168
+ ? `${
169
+ tempFile[0]?.size < 1000000
170
+ ? `${tempFile[0]?.size / 1000} KB`
171
+ : `${tempFile[0]?.size / 1000000} MB`
172
+ }`
173
+ : `Maximum file size ${options?.maxSizeInMb} MB`}
174
+ </span>
175
+ </div>
174
176
  </div>
175
- )}
176
- </button>
177
- )}
178
- <input
179
- ref={inputRef}
180
- type="file"
181
- className="hidden"
182
- onChange={(e) => {
183
- setTempValue(e.target.files![0]);
184
- }}
185
- {...rest}
186
- />
187
- </div>
177
+ </div>
178
+ )}
179
+ {options?.variant !== "drag&drop" && (
180
+ <button
181
+ type="button"
182
+ className="p-2 rounded-full hover:bg-secondary-light"
183
+ disabled={rest.disabled}
184
+ >
185
+ <Icon icon="mi:attachment" className="text-xl" />
186
+ </button>
187
+ )}
188
+ </div>
189
+ </label>
188
190
  );
189
191
  };