@bosonprotocol/react-kit 0.32.0-alpha.8 → 0.32.0

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.
Files changed (220) hide show
  1. package/dist/cjs/components/contractualAgreement/ContractualAgreement.js +2 -2
  2. package/dist/cjs/components/contractualAgreement/ContractualAgreement.js.map +1 -1
  3. package/dist/cjs/components/error/SimpleError.d.ts +7 -5
  4. package/dist/cjs/components/error/SimpleError.d.ts.map +1 -1
  5. package/dist/cjs/components/error/SimpleError.js +6 -5
  6. package/dist/cjs/components/error/SimpleError.js.map +1 -1
  7. package/dist/cjs/components/form/BaseTextArea.d.ts +5 -0
  8. package/dist/cjs/components/form/BaseTextArea.d.ts.map +1 -0
  9. package/dist/cjs/components/form/{Textarea.js → BaseTextArea.js} +6 -5
  10. package/dist/cjs/components/form/BaseTextArea.js.map +1 -0
  11. package/dist/cjs/components/form/Field.styles.d.ts +25 -2
  12. package/dist/cjs/components/form/Field.styles.d.ts.map +1 -1
  13. package/dist/cjs/components/form/Field.styles.js +35 -60
  14. package/dist/cjs/components/form/Field.styles.js.map +1 -1
  15. package/dist/cjs/components/form/FormField.d.ts +1 -1
  16. package/dist/cjs/components/form/FormField.d.ts.map +1 -1
  17. package/dist/cjs/components/form/FormField.js +5 -3
  18. package/dist/cjs/components/form/FormField.js.map +1 -1
  19. package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditor.d.ts +9 -0
  20. package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditor.d.ts.map +1 -0
  21. package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditor.js +65 -0
  22. package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditor.js.map +1 -0
  23. package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditorModal.d.ts +10 -0
  24. package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditorModal.d.ts.map +1 -0
  25. package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditorModal.js +100 -0
  26. package/dist/cjs/components/form/Upload/ImageEditorModal/ImageEditorModal.js.map +1 -0
  27. package/dist/cjs/components/form/Upload/Upload.d.ts +39 -2
  28. package/dist/cjs/components/form/Upload/Upload.d.ts.map +1 -1
  29. package/dist/cjs/components/form/Upload/Upload.js +81 -19
  30. package/dist/cjs/components/form/Upload/Upload.js.map +1 -1
  31. package/dist/cjs/components/form/Upload/WithUploadToIpfs.d.ts +1 -1
  32. package/dist/cjs/components/form/Upload/WithUploadToIpfs.d.ts.map +1 -1
  33. package/dist/cjs/components/form/Upload/WithUploadToIpfs.js +9 -7
  34. package/dist/cjs/components/form/Upload/WithUploadToIpfs.js.map +1 -1
  35. package/dist/cjs/components/form/index.d.ts +2 -2
  36. package/dist/cjs/components/form/index.d.ts.map +1 -1
  37. package/dist/cjs/components/form/index.js +3 -4
  38. package/dist/cjs/components/form/index.js.map +1 -1
  39. package/dist/cjs/components/form/types.d.ts +21 -5
  40. package/dist/cjs/components/form/types.d.ts.map +1 -1
  41. package/dist/cjs/components/license/License.js +2 -2
  42. package/dist/cjs/components/license/License.js.map +1 -1
  43. package/dist/cjs/components/modal/ModalComponents.d.ts +2 -0
  44. package/dist/cjs/components/modal/ModalComponents.d.ts.map +1 -1
  45. package/dist/cjs/components/modal/ModalComponents.js +3 -1
  46. package/dist/cjs/components/modal/ModalComponents.js.map +1 -1
  47. package/dist/cjs/components/modal/ModalContext.d.ts +2 -1
  48. package/dist/cjs/components/modal/ModalContext.d.ts.map +1 -1
  49. package/dist/cjs/components/modal/ModalContext.js.map +1 -1
  50. package/dist/cjs/components/modal/ModalTypes.d.ts +1 -0
  51. package/dist/cjs/components/modal/ModalTypes.d.ts.map +1 -1
  52. package/dist/cjs/components/modal/ModalTypes.js +2 -1
  53. package/dist/cjs/components/modal/ModalTypes.js.map +1 -1
  54. package/dist/cjs/components/modal/components/Redeem/Confirmation/Confirmation.js +3 -3
  55. package/dist/cjs/components/modal/components/Redeem/Confirmation/Confirmation.js.map +1 -1
  56. package/dist/cjs/components/modal/components/Redeem/ExchangeView/cancellation/CancelExchange.js +2 -2
  57. package/dist/cjs/components/modal/components/Redeem/ExchangeView/cancellation/CancelExchange.js.map +1 -1
  58. package/dist/cjs/components/modal/components/Redeem/ExchangeView/expireVoucher/ExpireVoucher.js +2 -2
  59. package/dist/cjs/components/modal/components/Redeem/ExchangeView/expireVoucher/ExpireVoucher.js.map +1 -1
  60. package/dist/cjs/components/modal/components/common/VariationSelects.js +2 -2
  61. package/dist/cjs/components/modal/components/common/VariationSelects.js.map +1 -1
  62. package/dist/cjs/components/modal/useModal.d.ts +3 -2
  63. package/dist/cjs/components/modal/useModal.d.ts.map +1 -1
  64. package/dist/cjs/components/step/MultiSteps.d.ts +23 -0
  65. package/dist/cjs/components/step/MultiSteps.d.ts.map +1 -0
  66. package/dist/cjs/components/step/MultiSteps.js +121 -0
  67. package/dist/cjs/components/step/MultiSteps.js.map +1 -0
  68. package/dist/cjs/components/step/Step.d.ts +28 -0
  69. package/dist/cjs/components/step/Step.d.ts.map +1 -0
  70. package/dist/cjs/components/step/Step.js +32 -0
  71. package/dist/cjs/components/step/Step.js.map +1 -0
  72. package/dist/cjs/components/step/Step.styles.d.ts +29 -0
  73. package/dist/cjs/components/step/Step.styles.d.ts.map +1 -0
  74. package/dist/cjs/components/step/Step.styles.js +196 -0
  75. package/dist/cjs/components/step/Step.styles.js.map +1 -0
  76. package/dist/cjs/hooks/images/useFileImage.d.ts +8 -0
  77. package/dist/cjs/hooks/images/useFileImage.d.ts.map +1 -0
  78. package/dist/cjs/hooks/images/useFileImage.js +26 -0
  79. package/dist/cjs/hooks/images/useFileImage.js.map +1 -0
  80. package/dist/cjs/hooks/images/useIpfsImage.d.ts +13 -0
  81. package/dist/cjs/hooks/images/useIpfsImage.d.ts.map +1 -0
  82. package/dist/cjs/hooks/images/useIpfsImage.js +26 -0
  83. package/dist/cjs/hooks/images/useIpfsImage.js.map +1 -0
  84. package/dist/cjs/index.d.ts +3 -0
  85. package/dist/cjs/index.d.ts.map +1 -1
  86. package/dist/cjs/index.js +3 -0
  87. package/dist/cjs/index.js.map +1 -1
  88. package/dist/cjs/lib/base64/base64.d.ts +4 -1
  89. package/dist/cjs/lib/base64/base64.d.ts.map +1 -1
  90. package/dist/cjs/lib/base64/base64.js +1 -1
  91. package/dist/cjs/lib/base64/base64.js.map +1 -1
  92. package/dist/esm/components/contractualAgreement/ContractualAgreement.js +1 -1
  93. package/dist/esm/components/contractualAgreement/ContractualAgreement.js.map +1 -1
  94. package/dist/esm/components/error/SimpleError.d.ts +7 -5
  95. package/dist/esm/components/error/SimpleError.d.ts.map +1 -1
  96. package/dist/esm/components/error/SimpleError.js +4 -4
  97. package/dist/esm/components/error/SimpleError.js.map +1 -1
  98. package/dist/esm/components/form/BaseTextArea.d.ts +5 -0
  99. package/dist/esm/components/form/BaseTextArea.d.ts.map +1 -0
  100. package/dist/esm/components/form/{Textarea.js → BaseTextArea.js} +3 -3
  101. package/dist/esm/components/form/BaseTextArea.js.map +1 -0
  102. package/dist/esm/components/form/Field.styles.d.ts +25 -2
  103. package/dist/esm/components/form/Field.styles.d.ts.map +1 -1
  104. package/dist/esm/components/form/Field.styles.js +35 -60
  105. package/dist/esm/components/form/Field.styles.js.map +1 -1
  106. package/dist/esm/components/form/FormField.d.ts +1 -1
  107. package/dist/esm/components/form/FormField.d.ts.map +1 -1
  108. package/dist/esm/components/form/FormField.js +3 -2
  109. package/dist/esm/components/form/FormField.js.map +1 -1
  110. package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditor.d.ts +9 -0
  111. package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditor.d.ts.map +1 -0
  112. package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditor.js +36 -0
  113. package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditor.js.map +1 -0
  114. package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditorModal.d.ts +10 -0
  115. package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditorModal.d.ts.map +1 -0
  116. package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditorModal.js +48 -0
  117. package/dist/esm/components/form/Upload/ImageEditorModal/ImageEditorModal.js.map +1 -0
  118. package/dist/esm/components/form/Upload/Upload.d.ts +39 -2
  119. package/dist/esm/components/form/Upload/Upload.d.ts.map +1 -1
  120. package/dist/esm/components/form/Upload/Upload.js +93 -19
  121. package/dist/esm/components/form/Upload/Upload.js.map +1 -1
  122. package/dist/esm/components/form/Upload/WithUploadToIpfs.d.ts +1 -1
  123. package/dist/esm/components/form/Upload/WithUploadToIpfs.d.ts.map +1 -1
  124. package/dist/esm/components/form/Upload/WithUploadToIpfs.js +9 -7
  125. package/dist/esm/components/form/Upload/WithUploadToIpfs.js.map +1 -1
  126. package/dist/esm/components/form/index.d.ts +2 -2
  127. package/dist/esm/components/form/index.d.ts.map +1 -1
  128. package/dist/esm/components/form/index.js +2 -2
  129. package/dist/esm/components/form/index.js.map +1 -1
  130. package/dist/esm/components/form/types.d.ts +21 -5
  131. package/dist/esm/components/form/types.d.ts.map +1 -1
  132. package/dist/esm/components/license/License.js +1 -1
  133. package/dist/esm/components/license/License.js.map +1 -1
  134. package/dist/esm/components/modal/ModalComponents.d.ts +2 -0
  135. package/dist/esm/components/modal/ModalComponents.d.ts.map +1 -1
  136. package/dist/esm/components/modal/ModalComponents.js +3 -1
  137. package/dist/esm/components/modal/ModalComponents.js.map +1 -1
  138. package/dist/esm/components/modal/ModalContext.d.ts +2 -1
  139. package/dist/esm/components/modal/ModalContext.d.ts.map +1 -1
  140. package/dist/esm/components/modal/ModalContext.js.map +1 -1
  141. package/dist/esm/components/modal/ModalTypes.d.ts +1 -0
  142. package/dist/esm/components/modal/ModalTypes.d.ts.map +1 -1
  143. package/dist/esm/components/modal/ModalTypes.js +2 -1
  144. package/dist/esm/components/modal/ModalTypes.js.map +1 -1
  145. package/dist/esm/components/modal/components/Redeem/Confirmation/Confirmation.js +1 -1
  146. package/dist/esm/components/modal/components/Redeem/Confirmation/Confirmation.js.map +1 -1
  147. package/dist/esm/components/modal/components/Redeem/ExchangeView/cancellation/CancelExchange.js +1 -1
  148. package/dist/esm/components/modal/components/Redeem/ExchangeView/cancellation/CancelExchange.js.map +1 -1
  149. package/dist/esm/components/modal/components/Redeem/ExchangeView/expireVoucher/ExpireVoucher.js +1 -1
  150. package/dist/esm/components/modal/components/Redeem/ExchangeView/expireVoucher/ExpireVoucher.js.map +1 -1
  151. package/dist/esm/components/modal/components/common/VariationSelects.js +1 -1
  152. package/dist/esm/components/modal/components/common/VariationSelects.js.map +1 -1
  153. package/dist/esm/components/modal/useModal.d.ts +3 -2
  154. package/dist/esm/components/modal/useModal.d.ts.map +1 -1
  155. package/dist/esm/components/step/MultiSteps.d.ts +23 -0
  156. package/dist/esm/components/step/MultiSteps.d.ts.map +1 -0
  157. package/dist/esm/components/step/MultiSteps.js +82 -0
  158. package/dist/esm/components/step/MultiSteps.js.map +1 -0
  159. package/dist/esm/components/step/Step.d.ts +28 -0
  160. package/dist/esm/components/step/Step.d.ts.map +1 -0
  161. package/dist/esm/components/step/Step.js +13 -0
  162. package/dist/esm/components/step/Step.js.map +1 -0
  163. package/dist/esm/components/step/Step.styles.d.ts +29 -0
  164. package/dist/esm/components/step/Step.styles.d.ts.map +1 -0
  165. package/dist/esm/components/step/Step.styles.js +170 -0
  166. package/dist/esm/components/step/Step.styles.js.map +1 -0
  167. package/dist/esm/hooks/images/useFileImage.d.ts +8 -0
  168. package/dist/esm/hooks/images/useFileImage.d.ts.map +1 -0
  169. package/dist/esm/hooks/images/useFileImage.js +13 -0
  170. package/dist/esm/hooks/images/useFileImage.js.map +1 -0
  171. package/dist/esm/hooks/images/useIpfsImage.d.ts +13 -0
  172. package/dist/esm/hooks/images/useIpfsImage.d.ts.map +1 -0
  173. package/dist/esm/hooks/images/useIpfsImage.js +16 -0
  174. package/dist/esm/hooks/images/useIpfsImage.js.map +1 -0
  175. package/dist/esm/index.d.ts +3 -0
  176. package/dist/esm/index.d.ts.map +1 -1
  177. package/dist/esm/index.js +3 -0
  178. package/dist/esm/index.js.map +1 -1
  179. package/dist/esm/lib/base64/base64.d.ts +4 -1
  180. package/dist/esm/lib/base64/base64.d.ts.map +1 -1
  181. package/dist/esm/lib/base64/base64.js +1 -1
  182. package/dist/esm/lib/base64/base64.js.map +1 -1
  183. package/package.json +7 -4
  184. package/src/components/contractualAgreement/ContractualAgreement.tsx +1 -1
  185. package/src/components/error/SimpleError.tsx +16 -11
  186. package/src/components/form/{Textarea.tsx → BaseTextArea.tsx} +8 -3
  187. package/src/components/form/Field.styles.ts +68 -64
  188. package/src/components/form/FormField.tsx +6 -4
  189. package/src/components/form/Upload/ImageEditorModal/ImageEditor.tsx +74 -0
  190. package/src/components/form/Upload/ImageEditorModal/ImageEditorModal.tsx +77 -0
  191. package/src/components/form/Upload/Upload.tsx +137 -41
  192. package/src/components/form/Upload/WithUploadToIpfs.tsx +13 -11
  193. package/src/components/form/index.ts +2 -2
  194. package/src/components/form/types.ts +20 -4
  195. package/src/components/license/License.tsx +1 -1
  196. package/src/components/modal/ModalComponents.tsx +3 -1
  197. package/src/components/modal/ModalContext.tsx +4 -3
  198. package/src/components/modal/ModalTypes.ts +2 -1
  199. package/src/components/modal/components/Redeem/Confirmation/Confirmation.tsx +1 -1
  200. package/src/components/modal/components/Redeem/ExchangeView/cancellation/CancelExchange.tsx +1 -1
  201. package/src/components/modal/components/Redeem/ExchangeView/expireVoucher/ExpireVoucher.tsx +1 -1
  202. package/src/components/modal/components/common/VariationSelects.tsx +1 -1
  203. package/src/components/step/MultiSteps.tsx +187 -0
  204. package/src/components/step/Step.styles.ts +209 -0
  205. package/src/components/step/Step.tsx +67 -0
  206. package/src/hooks/images/useFileImage.ts +24 -0
  207. package/src/hooks/images/useIpfsImage.ts +27 -0
  208. package/src/index.tsx +3 -0
  209. package/src/lib/base64/base64.ts +1 -1
  210. package/src/stories/buttons/Upload.stories.tsx +82 -0
  211. package/src/stories/form/{Input.stories.tsx → BaseInput.stories.tsx} +1 -1
  212. package/src/stories/form/BaseTextArea.stories.tsx +59 -0
  213. package/src/stories/multisteps/MultiSteps.stories.tsx +86 -0
  214. package/dist/cjs/components/form/Textarea.d.ts +0 -4
  215. package/dist/cjs/components/form/Textarea.d.ts.map +0 -1
  216. package/dist/cjs/components/form/Textarea.js.map +0 -1
  217. package/dist/esm/components/form/Textarea.d.ts +0 -4
  218. package/dist/esm/components/form/Textarea.d.ts.map +0 -1
  219. package/dist/esm/components/form/Textarea.js.map +0 -1
  220. /package/src/stories/buttons/{button.stories.tsx → Button.stories.tsx} +0 -0
@@ -4,15 +4,20 @@ import React from "react";
4
4
  import Error from "./Error";
5
5
  import { FieldTextArea } from "./Field.styles";
6
6
  import type { TextareaProps } from "./types";
7
-
8
- export default function Textarea({ name, ...props }: TextareaProps) {
7
+ export type BaseTextAreaProps = TextareaProps;
8
+ export function BaseTextArea({ name, theme, ...props }: TextareaProps) {
9
9
  const [field, meta] = useField(name);
10
10
  const errorMessage = meta.error && meta.touched ? meta.error : "";
11
11
  const displayError =
12
12
  typeof errorMessage === typeof "string" && errorMessage !== "";
13
13
  return (
14
14
  <>
15
- <FieldTextArea error={errorMessage} {...field} {...props} />
15
+ <FieldTextArea
16
+ $error={errorMessage}
17
+ {...field}
18
+ {...props}
19
+ theme={theme}
20
+ />
16
21
  <Error display={displayError} message={errorMessage} />
17
22
  </>
18
23
  );
@@ -61,7 +61,6 @@ export const FieldInput = styled.input<{
61
61
  border: 1px solid ${(props) => props.theme?.borderColor || colors.border};
62
62
  border-radius: ${(props) => props.theme?.borderRadius || 0}px;
63
63
  outline: none;
64
- font-family: "Plus Jakarta Sans";
65
64
 
66
65
  ${transition}
67
66
 
@@ -116,7 +115,7 @@ export const FieldInput = styled.input<{
116
115
  `};
117
116
  `;
118
117
 
119
- export const FileUploadWrapper = styled.div<{ choosen: any; error: any }>`
118
+ export const FileUploadWrapper = styled.div<{ error: any }>`
120
119
  position: relative;
121
120
  overflow: hidden;
122
121
  display: flex;
@@ -210,16 +209,38 @@ export const FieldFileUploadWrapper = styled.div<{ $disabled: boolean }>`
210
209
  background: ${colors.black}80;
211
210
  }
212
211
  `;
213
-
214
- export const FieldTextArea = styled.textarea<{ error: any }>`
212
+ export type TextAreaTheme = {
213
+ background: CSSProperties["backgroundColor"];
214
+ borderColor: CSSProperties["borderColor"];
215
+ borderRadius: CSSProperties["borderRadius"];
216
+ focus: {
217
+ caretColor: CSSProperties["caretColor"];
218
+ };
219
+ hover: {
220
+ borderColor: CSSProperties["borderColor"];
221
+ };
222
+ error: {
223
+ borderColor: CSSProperties["borderColor"];
224
+ hover: {
225
+ borderColor: CSSProperties["borderColor"];
226
+ };
227
+ focus: {
228
+ borderColor: CSSProperties["borderColor"];
229
+ caretColor: CSSProperties["caretColor"];
230
+ };
231
+ placeholder: {
232
+ color: CSSProperties["color"];
233
+ };
234
+ };
235
+ };
236
+ export const FieldTextArea = styled.textarea<{ $error: any }>`
215
237
  width: 100%;
216
238
  padding: 1rem;
217
239
  gap: 0.5rem;
218
- font-family: "Plus Jakarta Sans";
219
-
220
- background: ${colors.lightGrey};
221
- border: 1px solid ${colors.border};
222
- border-radius: 0;
240
+ font-family: inherit;
241
+ background: ${(props) => props.theme?.background || "transparent"};
242
+ border: 1px solid ${(props) => props.theme?.borderColor || colors.border};
243
+ border-radius: ${(props) => props.theme?.borderRadius || 0}px;
223
244
  outline: none;
224
245
 
225
246
  ${transition}
@@ -227,7 +248,9 @@ export const FieldTextArea = styled.textarea<{ error: any }>`
227
248
  &:not(:disabled) {
228
249
  &:focus,
229
250
  &:hover {
230
- border: 1px solid var(--secondary);
251
+ border: 1px solid
252
+ ${(props) => props.theme?.hover?.borderColor || colors.lightGrey};
253
+ caret-color: ${(props) => props.theme?.focus?.caretColor || "initial"};
231
254
  }
232
255
  }
233
256
 
@@ -236,39 +259,41 @@ export const FieldTextArea = styled.textarea<{ error: any }>`
236
259
  opacity: 0.5;
237
260
  }
238
261
 
239
- ${({ error }) =>
240
- !checkIfValueIsEmpty(error)
241
- ? css`
242
- border: 1px solid ${colors.orange};
243
- &::placeholder {
244
- color: ${colors.orange};
245
- opacity: 1;
246
- }
247
- &:-ms-input-placeholder {
248
- color: ${colors.orange};
249
- }
250
- &::-ms-input-placeholder {
251
- color: ${colors.orange};
252
- }
253
- &:not(:disabled) {
254
- &:hover {
255
- border: 1px solid ${colors.orange};
256
- }
257
- }
258
- &:not(:disabled) {
259
- &:focus {
260
- border: 1px solid var(--secondary);
261
- }
262
- }
263
- `
264
- : css`
265
- &:not(:disabled) {
266
- &:focus,
267
- &:hover {
268
- border: 1px solid var(--secondary);
269
- }
270
- }
271
- `}
262
+ ${({ $error }) =>
263
+ !checkIfValueIsEmpty($error) &&
264
+ css`
265
+ border: 1px solid
266
+ ${(props) => props.theme?.error?.borderColor || colors.orange};
267
+ &:not(:disabled) {
268
+ &:hover {
269
+ border: 1px solid
270
+ ${(props) =>
271
+ props.theme?.error?.hover?.borderColor || colors.orange};
272
+ }
273
+ }
274
+ &:not(:disabled) {
275
+ &:focus {
276
+ border: 1px solid
277
+ ${(props) =>
278
+ props.theme?.error?.focus?.borderColor || colors.lightGrey};
279
+ caret-color: ${(props) =>
280
+ props.theme?.error?.focus?.caretColor || colors.orange};
281
+ }
282
+ }
283
+ &::placeholder {
284
+ color: ${(props) =>
285
+ props.theme?.error?.placeholder?.color || colors.orange};
286
+ opacity: 1;
287
+ }
288
+ &:-ms-input-placeholder {
289
+ color: ${(props) =>
290
+ props.theme?.error?.placeholder?.color || colors.orange};
291
+ }
292
+ &::-ms-input-placeholder {
293
+ color: ${(props) =>
294
+ props.theme?.error?.placeholder?.color || colors.orange};
295
+ }
296
+ `}
272
297
  `;
273
298
 
274
299
  export const FormFieldWrapper = styled(Grid)`
@@ -277,31 +302,10 @@ export const FormFieldWrapper = styled(Grid)`
277
302
  line-height: 150%;
278
303
  }
279
304
 
280
- // theme white
281
- margin-bottom: 0.5rem;
282
- input,
283
- textarea {
284
- background: ${colors.white};
285
- &:disabled {
286
- opacity: 1;
287
- }
288
- }
289
- input {
290
- border-width: 0;
291
- &:hover {
292
- border-width: 0;
293
- }
294
- }
295
- input + div {
296
- background: ${colors.white};
297
- }
298
- // end theme white
299
-
300
305
  [data-header] {
301
306
  margin: 0;
302
307
  font-weight: 600;
303
308
  font-size: 1rem;
304
- color: ${colors.black};
305
309
  + div button {
306
310
  margin-left: 0.5rem;
307
311
  padding: 0;
@@ -13,15 +13,16 @@ import type { FormFieldProps } from "./types";
13
13
 
14
14
  const colors = theme.colors.light;
15
15
 
16
- export default function FormField({
16
+ export function FormField({
17
17
  title,
18
+ titleIcon,
18
19
  subTitle = false,
19
20
  required = false,
20
21
  tooltip,
21
22
  children,
22
23
  style = {},
23
- theme = "",
24
- valueToCopy
24
+ valueToCopy,
25
+ copyIconColor = colors.secondary
25
26
  }: FormFieldProps) {
26
27
  return (
27
28
  <FormFieldWrapper
@@ -59,10 +60,11 @@ export default function FormField({
59
60
  }
60
61
  }}
61
62
  >
62
- <Copy size={24} color={colors.secondary} weight="light" />
63
+ <Copy size={24} color={copyIconColor} weight="light" />
63
64
  </CopyButton>
64
65
  )}
65
66
  </Typography>
67
+ {titleIcon}
66
68
  {tooltip && <Tooltip content={tooltip} size={16} />}
67
69
  </Grid>
68
70
  {subTitle && (
@@ -0,0 +1,74 @@
1
+ import React, { ChangeEvent, forwardRef, useState } from "react";
2
+ import AvatarEditor, { AvatarEditorProps } from "react-avatar-editor";
3
+ import Dropzone from "react-dropzone";
4
+ import styled from "styled-components";
5
+ import { Grid } from "../../../ui/Grid";
6
+ import { useIpfsImage } from "../../../../hooks/images/useIpfsImage";
7
+
8
+ const StyledCanvasWrapper = styled.div`
9
+ display: flex;
10
+ justify-content: center;
11
+ > :first-child {
12
+ max-width: 100%;
13
+ object-fit: contain;
14
+ width: auto !important;
15
+ height: auto !important;
16
+ }
17
+ `;
18
+
19
+ export type ImageEditorProps = Pick<
20
+ AvatarEditorProps,
21
+ "borderRadius" | "width" | "height"
22
+ > & {
23
+ url?: string;
24
+ };
25
+
26
+ export const ImageEditor = forwardRef<AvatarEditor, ImageEditorProps>(
27
+ ({ url, borderRadius, width, height }, editorRef) => {
28
+ const [scale, setScale] = useState<number>();
29
+ const handleScale = (e: ChangeEvent<HTMLInputElement>) => {
30
+ const scale = parseFloat(e.target.value);
31
+ setScale(scale);
32
+ };
33
+ const { data } = useIpfsImage({ url: url ?? "" }, { enabled: !!url });
34
+ const image = data?.base64;
35
+ const { width: imageWidth, height: imageHeight } = data || {};
36
+ const w = borderRadius ? width : width || imageWidth;
37
+ const h = borderRadius ? height : height || imageHeight;
38
+ return (
39
+ <>
40
+ {image && (
41
+ <div style={{ margin: "2rem 0", maxWidth: "100%" }}>
42
+ <Dropzone noClick noKeyboard>
43
+ {({ getRootProps, getInputProps }) => (
44
+ <StyledCanvasWrapper {...getRootProps()}>
45
+ <AvatarEditor
46
+ image={image}
47
+ ref={editorRef}
48
+ width={w}
49
+ height={h}
50
+ scale={scale}
51
+ borderRadius={borderRadius}
52
+ />
53
+ <input {...getInputProps()} />
54
+ </StyledCanvasWrapper>
55
+ )}
56
+ </Dropzone>
57
+ <Grid alignItems="center" justifyContent="center">
58
+ Zoom:
59
+ <input
60
+ name="scale"
61
+ type="range"
62
+ onChange={handleScale}
63
+ min={"0.1"}
64
+ max="2"
65
+ step="0.01"
66
+ defaultValue="1"
67
+ />
68
+ </Grid>
69
+ </div>
70
+ )}
71
+ </>
72
+ );
73
+ }
74
+ );
@@ -0,0 +1,77 @@
1
+ import * as Sentry from "@sentry/browser";
2
+ import React, { useRef, useState } from "react";
3
+ import AvatarEditor from "react-avatar-editor";
4
+ import { dataURItoBlob } from "../../../../lib/base64/base64";
5
+ import Modal from "../../../modal/Modal";
6
+ import { Grid } from "../../../ui/Grid";
7
+ import { Spinner } from "../../../ui/loading/Spinner";
8
+ import { BaseButton, BaseButtonTheme } from "../../../buttons/BaseButton";
9
+ import { ImageEditor, ImageEditorProps } from "./ImageEditor";
10
+ import { useFileImage } from "../../../../hooks/images/useFileImage";
11
+
12
+ export type ImageEditorModalProps = Omit<ImageEditorProps, "url"> & {
13
+ files: File[] | null;
14
+ hideModal: (files?: File[]) => Promise<void>;
15
+ saveButtonTheme: BaseButtonTheme;
16
+ };
17
+
18
+ export const ImageEditorModal: React.FC<ImageEditorModalProps> = ({
19
+ hideModal,
20
+ files,
21
+ saveButtonTheme,
22
+ ...rest
23
+ }) => {
24
+ const originalFile = files?.[0];
25
+ const { data: url } = useFileImage(
26
+ { file: originalFile },
27
+ { enabled: !!originalFile }
28
+ );
29
+ const editorRef = useRef<AvatarEditor>(null);
30
+ const [isSaving, setSaving] = useState<boolean>(false);
31
+ const onClickSave = async () => {
32
+ setSaving(true);
33
+ try {
34
+ const img = editorRef.current?.getImageScaledToCanvas().toDataURL();
35
+ if (!img) {
36
+ return;
37
+ }
38
+ const blob = dataURItoBlob(img);
39
+ const file = new File([blob], originalFile?.name ?? "edited", {
40
+ type: originalFile?.type,
41
+ lastModified: originalFile?.lastModified
42
+ });
43
+ if (!file) {
44
+ return;
45
+ }
46
+ await hideModal([file]);
47
+ } catch (error) {
48
+ Sentry.captureException(error);
49
+ } finally {
50
+ setSaving(false);
51
+ }
52
+ };
53
+ return (
54
+ <Modal
55
+ modalType="IMAGE_EDITOR"
56
+ hideModal={() => hideModal()}
57
+ size="auto"
58
+ maxWidths={{
59
+ s: "50rem"
60
+ }}
61
+ theme="light"
62
+ >
63
+ <Grid flexDirection="column">
64
+ <ImageEditor url={url} {...rest} ref={editorRef} />
65
+ <BaseButton
66
+ type="button"
67
+ theme={saveButtonTheme}
68
+ onClick={() => onClickSave()}
69
+ disabled={isSaving}
70
+ >
71
+ {isSaving ? "Saving" : "Save"}
72
+ {isSaving && <Spinner />}
73
+ </BaseButton>
74
+ </Grid>
75
+ </Modal>
76
+ );
77
+ };
@@ -1,3 +1,4 @@
1
+ import * as Sentry from "@sentry/browser";
1
2
  import { useField } from "formik";
2
3
  import { Image, Trash, VideoCamera } from "phosphor-react";
3
4
  import React, { useCallback, useEffect, useRef, useState } from "react";
@@ -19,6 +20,8 @@ import {
19
20
  import type { UploadFileType, UploadProps, FileProps } from "../types";
20
21
  import UploadedFiles from "./UploadedFiles";
21
22
  import { WithUploadToIpfs, WithUploadToIpfsProps } from "./WithUploadToIpfs";
23
+ import { useModal } from "../../modal/useModal";
24
+ import { ImageEditorModal } from "./ImageEditorModal/ImageEditorModal";
22
25
  const colors = theme.colors.light;
23
26
 
24
27
  function Upload({
@@ -33,11 +36,21 @@ function Upload({
33
36
  wrapperProps,
34
37
  onLoadSinglePreviewImage,
35
38
  withUpload,
39
+ withEditor,
36
40
  saveToIpfs,
37
41
  loadMedia,
38
42
  onLoading,
43
+ width,
44
+ height,
45
+ borderRadius,
46
+ imgPreviewStyle,
47
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
48
+ removeFile,
49
+ saveButtonTheme,
39
50
  ...props
40
51
  }: UploadProps & WithUploadToIpfsProps) {
52
+ const { updateProps, store } = useModal();
53
+ const [showEditor, setShowEditor] = useState<boolean>(false);
41
54
  const [isLoading, setIsLoading] = useState<boolean>(false);
42
55
  const [preview, setPreview] = useState<string | null>();
43
56
  const [field, meta, helpers] = useField(name);
@@ -51,10 +64,10 @@ function Upload({
51
64
  );
52
65
 
53
66
  const errorMessage = meta.error && meta.touched ? meta.error : "";
54
- const displayError =
55
- typeof errorMessage === typeof "string" && errorMessage !== "";
67
+ const displayError = typeof errorMessage === "string" && errorMessage !== "";
56
68
 
57
69
  const inputRef = useRef<HTMLInputElement | null>(null);
70
+ const [nativeFiles, setNativeFiles] = useState<File[] | null>(null);
58
71
  const setFiles = useCallback(
59
72
  (value: unknown) => {
60
73
  helpers.setValue(value);
@@ -74,7 +87,7 @@ function Upload({
74
87
  useEffect(() => {
75
88
  onFilesSelect?.(files);
76
89
  helpers.setValue(files);
77
-
90
+ console.log("useEffect", { files });
78
91
  if (!multiple && files && files?.length !== 0) {
79
92
  if (isImageOnly) {
80
93
  if (withUpload) {
@@ -104,10 +117,17 @@ function Upload({
104
117
  }
105
118
  handleLoading(true);
106
119
  try {
107
- const imagePreview: string = await loadMedia(fileSrc || "");
108
- setPreview(imagePreview);
120
+ const imagePreview = await loadMedia(fileSrc || "");
121
+ if (imagePreview) {
122
+ setPreview(imagePreview);
123
+ } else {
124
+ console.warn(
125
+ `imagePreview ${imagePreview} is falsy in loadIpfsImagePreview`
126
+ );
127
+ }
109
128
  } catch (error) {
110
129
  console.error(error);
130
+ Sentry.captureException(error);
111
131
  } finally {
112
132
  handleLoading(false);
113
133
  }
@@ -120,11 +140,18 @@ function Upload({
120
140
  }
121
141
  try {
122
142
  handleLoading(true);
123
- const imagePreview: string = await loadMedia(fileSrc || "");
124
- setPreview(imagePreview);
125
- onLoadSinglePreviewImage?.(imagePreview);
143
+ const imagePreview = await loadMedia(fileSrc || "");
144
+ if (imagePreview) {
145
+ setPreview(imagePreview);
146
+ onLoadSinglePreviewImage?.(imagePreview);
147
+ } else {
148
+ console.warn(
149
+ `imagePreview ${imagePreview} is falsy in loadIpfsImagePreview`
150
+ );
151
+ }
126
152
  } catch (error) {
127
153
  console.error(error);
154
+ Sentry.captureException(error);
128
155
  } finally {
129
156
  handleLoading(false);
130
157
  }
@@ -152,41 +179,83 @@ function Upload({
152
179
  setFiles(newArray);
153
180
  };
154
181
 
155
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
156
- if (!meta.touched) {
157
- helpers.setTouched(true);
158
- }
182
+ const handleChange = useCallback(
183
+ async (filesArray: File[] | null) => {
184
+ if (!meta.touched) {
185
+ helpers.setTouched(true);
186
+ }
159
187
 
160
- if (!e.target.files) {
161
- return;
162
- }
163
- const { files } = e.target;
164
- const filesArray = Object.values(files);
165
- for (const file of filesArray) {
166
- if (maxSize) {
167
- if (file.size > maxSize) {
168
- const error = `File size cannot exceed more than ${bytesToSize(
169
- maxSize
170
- )}`;
171
- // TODO: change to notification
172
- console.error(error);
188
+ if (!filesArray) {
189
+ return;
190
+ }
191
+ for (const file of filesArray) {
192
+ if (maxSize) {
193
+ if (file.size > maxSize) {
194
+ const error = `File size cannot exceed more than ${bytesToSize(
195
+ maxSize
196
+ )}`;
197
+ // TODO: change to notification
198
+ console.error(error);
199
+ }
173
200
  }
174
201
  }
175
- }
176
- setFiles(filesArray);
177
- };
202
+ setFiles(filesArray);
203
+ },
204
+ [helpers, maxSize, meta.touched, setFiles]
205
+ );
178
206
 
179
207
  const handleSave = useCallback(
180
- async (e: React.ChangeEvent<HTMLInputElement>) => {
208
+ async (efiles: File[] | null) => {
209
+ if (!meta.touched) {
210
+ helpers.setTouched(true);
211
+ }
181
212
  handleLoading(true);
182
- const files: FileProps[] = await saveToIpfs(e);
183
- setFiles(files);
213
+ const files = await saveToIpfs(efiles);
214
+ if (files) {
215
+ setFiles(files);
216
+ } else {
217
+ setFiles([]);
218
+ console.warn(
219
+ `There has been an error because 'files' ${files} is falsy in handleSave`
220
+ );
221
+ }
222
+ handleLoading(false);
184
223
  },
185
- [saveToIpfs, setFiles, handleLoading]
224
+ [meta.touched, handleLoading, saveToIpfs, helpers, setFiles]
186
225
  );
187
-
226
+ const saveFn = withUpload ? handleSave : handleChange;
227
+ const style = {
228
+ borderRadius: borderRadius ? `${borderRadius}%` : "",
229
+ width: width ? `100%` : ""
230
+ };
188
231
  return (
189
232
  <>
233
+ {withEditor && showEditor && (
234
+ <ImageEditorModal
235
+ saveButtonTheme={saveButtonTheme}
236
+ files={nativeFiles}
237
+ borderRadius={borderRadius}
238
+ width={width}
239
+ height={height}
240
+ hideModal={async (fileList) => {
241
+ if (fileList) {
242
+ await saveFn(fileList);
243
+ }
244
+
245
+ setShowEditor(false);
246
+ updateProps({
247
+ ...store,
248
+ modalType: store.modalType,
249
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
250
+ // @ts-ignore
251
+ modalProps: {
252
+ ...store.modalProps,
253
+ hidden: false
254
+ }
255
+ });
256
+ }}
257
+ />
258
+ )}
190
259
  <FieldFileUploadWrapper {...wrapperProps} $disabled={!!disabled}>
191
260
  <FieldInput
192
261
  {...props}
@@ -194,7 +263,29 @@ function Upload({
194
263
  type="file"
195
264
  accept={accept}
196
265
  multiple={multiple}
197
- onChange={withUpload ? handleSave : handleChange}
266
+ onChange={async (e) => {
267
+ const files = e.target.files
268
+ ? Object.values(e.target.files)
269
+ : e.target.files;
270
+
271
+ if (files && withEditor) {
272
+ setNativeFiles(files);
273
+ setShowEditor(true);
274
+ updateProps({
275
+ ...store,
276
+ modalType: store.modalType,
277
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
278
+ // @ts-ignore
279
+ modalProps: {
280
+ ...store.modalProps,
281
+ hidden: true
282
+ }
283
+ });
284
+ } else {
285
+ await saveFn(files);
286
+ }
287
+ e.target.value = ""; // allow user to select the same file again
288
+ }}
198
289
  ref={(ref) => {
199
290
  inputRef.current = ref;
200
291
  }}
@@ -206,10 +297,10 @@ function Upload({
206
297
  </ThemedButton>
207
298
  ) : (
208
299
  <FileUploadWrapper
209
- choosen={files !== null}
210
300
  data-disabled={disabled}
211
301
  onClick={handleChooseFile}
212
302
  error={errorMessage}
303
+ style={style}
213
304
  >
214
305
  {isLoading ? (
215
306
  <Loading size={2} />
@@ -220,17 +311,22 @@ function Upload({
220
311
  {isVideoOnly ? (
221
312
  <VideoPreview
222
313
  src={
223
- "data:video/mp4;base64," +
224
- preview?.substring(
225
- "data:application/octet-stream;base64,".length
226
- )
314
+ preview?.startsWith("http")
315
+ ? preview
316
+ : "data:video/mp4;base64," +
317
+ preview?.substring(
318
+ "data:application/octet-stream;base64,".length
319
+ )
227
320
  }
228
321
  autoPlay
229
322
  muted
230
323
  loop
231
324
  />
232
325
  ) : (
233
- <ImagePreview src={preview} />
326
+ <ImagePreview
327
+ style={{ ...imgPreviewStyle }}
328
+ src={preview}
329
+ />
234
330
  )}
235
331
  </>
236
332
  ) : isVideoOnly ? (
@@ -248,7 +344,7 @@ function Upload({
248
344
  </FileUploadWrapper>
249
345
  )}
250
346
  {!disabled && field.value && field.value?.length !== 0 && preview && (
251
- <div onClick={handleRemoveAllFiles} data-remove>
347
+ <div onClick={handleRemoveAllFiles} data-remove style={style}>
252
348
  <Trash size={24} color={colors.white} />
253
349
  </div>
254
350
  )}