@trackunit/react-form-components 0.0.343-alpha-869e1cbc10.0 → 0.0.343

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/index.cjs.js CHANGED
@@ -49,6 +49,8 @@ var ReactAsyncSelect__default = /*#__PURE__*/_interopDefaultLegacy(ReactAsyncSel
49
49
 
50
50
  var defaultTranslations = {
51
51
  "clearIndicator.icon.tooltip.clearAll": "Clear all",
52
+ "dropzone.input.title": "Drag-and-drop file input",
53
+ "dropzone.label.default": "<clickable>Browse</clickable> or drag files here...",
52
54
  "phoneField.error.INVALID_COUNTRY": "The country code is not valid",
53
55
  "phoneField.error.INVALID_LENGTH": "The phone number is not valid",
54
56
  "phoneField.error.INVALID_NUMBER": "The phone number is not valid",
@@ -95,6 +97,10 @@ const translations = {
95
97
  * Local useTranslation for this specific library
96
98
  */
97
99
  const useTranslation = () => i18nLibraryTranslation.useNamespaceTranslation(namespace);
100
+ /**
101
+ * Trans for this specific library.
102
+ */
103
+ const Trans = (props) => (jsxRuntime.jsx(i18nLibraryTranslation.NamespaceTrans, Object.assign({}, props, { namespace: namespace })));
98
104
  /**
99
105
  * Registers the translations for this library
100
106
  */
@@ -630,17 +636,32 @@ const cvaDropZoneLabel = cssClassVarianceUtilities.cvaMerge([
630
636
  "flex",
631
637
  "justify-center",
632
638
  ]);
639
+ const cvaDropZoneIconBackground = cssClassVarianceUtilities.cvaMerge(["relative", "flex", "items-center", "justify-center", "rounded-full", "p-3"], {
640
+ variants: {
641
+ invalid: { true: ["bg-red-100"], false: ["bg-slate-200"] },
642
+ },
643
+ });
644
+
645
+ /**
646
+ *
647
+ * Default UX-intuitive label for the DropZone - can be overwritten by the label prop
648
+ */
649
+ const DropZoneDefaultLabel = () => (jsxRuntime.jsx(Trans, { components: {
650
+ clickable: jsxRuntime.jsx("span", { className: "text-primary-600 hover:text-primary-700 cursor-pointer underline" }),
651
+ }, i18nKey: "dropzone.label.default", values: {} }));
633
652
 
634
653
  /**
635
- * The Drop Zone can be used to drag and drop files
654
+ * The Drop Zone can be used to drag and drop files or to browse and select files from the file system.
636
655
  *
637
656
  * @param {DropZoneProps} props - The props for the DropZone component
638
657
  * @returns {JSX.Element} DropZone component
639
658
  */
640
659
  const DropZone = (_a) => {
641
- var { className, dataTestId, filesSelected, label, size = "large", isInvalid = false, disabled = false } = _a, rest = __rest(_a, ["className", "dataTestId", "filesSelected", "label", "size", "isInvalid", "disabled"]);
642
- const [dragActive, setDragActive] = React__default["default"].useState(false);
643
- const [fileDropped, setFileDropped] = React__default["default"].useState(false);
660
+ var { className, dataTestId, filesSelected, label = jsxRuntime.jsx(DropZoneDefaultLabel, {}), size = "large", isInvalid = false, disabled = false, accept } = _a, rest = __rest(_a, ["className", "dataTestId", "filesSelected", "label", "size", "isInvalid", "disabled", "accept"]);
661
+ const [dragActive, setDragActive] = React.useState(false);
662
+ const [fileDropped, setFileDropped] = React.useState(false);
663
+ const [t] = useTranslation();
664
+ const inputLabelRef = React.useRef(null);
644
665
  // function that handles drag enter, drag leave and drag over
645
666
  const handleDrag = (e) => {
646
667
  e.preventDefault();
@@ -660,7 +681,7 @@ const DropZone = (_a) => {
660
681
  filesSelected(e.target.files);
661
682
  }
662
683
  };
663
- //funtion to handle drop
684
+ //function to handle drop
664
685
  const handleDrop = (e) => {
665
686
  e.preventDefault();
666
687
  e.stopPropagation();
@@ -670,12 +691,22 @@ const DropZone = (_a) => {
670
691
  setFileDropped(true);
671
692
  }
672
693
  };
694
+ //function to handle focusable button click (for accessibility)
695
+ const handleButtonClick = (e) => {
696
+ var _a;
697
+ e.preventDefault();
698
+ e.stopPropagation();
699
+ if (disabled) {
700
+ return;
701
+ }
702
+ (_a = inputLabelRef.current) === null || _a === void 0 ? void 0 : _a.click();
703
+ };
673
704
  return (jsxRuntime.jsxs("div", Object.assign({ className: cvaDropZone({ size, dropComplete: fileDropped, dragActive, disabled, invalid: isInvalid, className }), "data-testid": dataTestId, onClick: e => {
674
705
  if (disabled) {
675
706
  e.preventDefault();
676
707
  e.stopPropagation();
677
708
  }
678
- }, onDragEnter: handleDrag, onDragLeave: handleDrag, onDragOver: handleDrag, onDrop: handleDrop }, rest, { children: [jsxRuntime.jsx("input", { className: "hidden", id: "input-file-upload", onChange: handleChange, title: "Hidden File Input", type: "file" }), jsxRuntime.jsxs("label", { className: cvaDropZoneLabel(), "data-testid": dataTestId && `${dataTestId}-label`, htmlFor: "input-file-upload", children: [jsxRuntime.jsx(reactComponents.Icon, { color: isInvalid ? "danger" : "neutral", name: "ArrowUpCircle", style: !isInvalid ? { color: "rgb(156 163 175)" } : {}, type: "solid" }), jsxRuntime.jsx("span", { children: label })] })] })));
709
+ }, onDragEnter: handleDrag, onDragLeave: handleDrag, onDragOver: handleDrag, onDrop: handleDrop }, rest, { children: [jsxRuntime.jsx("input", { accept: accept, className: "hidden", id: "input-file-upload", onChange: handleChange, title: t("dropzone.input.title"), type: "file" }), jsxRuntime.jsxs("label", { className: cvaDropZoneLabel(), "data-testid": dataTestId && `${dataTestId}-label`, htmlFor: "input-file-upload", ref: inputLabelRef, children: [jsxRuntime.jsx("div", { className: cvaDropZoneIconBackground({ invalid: isInvalid }), children: jsxRuntime.jsx(reactComponents.Icon, { className: !isInvalid ? "text-gray-400" : "", color: isInvalid ? "danger" : "neutral", name: "ArrowUpCircle", type: "solid" }) }), jsxRuntime.jsx("button", { disabled: disabled, onClick: handleButtonClick, children: label })] })] })));
679
710
  };
680
711
 
681
712
  // Doing the same check as we do on the backend
package/index.esm.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
2
+ import { registerTranslations, useNamespaceTranslation, NamespaceTrans } from '@trackunit/i18n-library-translation';
3
3
  import { IconButton, Icon, Tooltip, Heading, Text, MenuItem, Tag, Spinner } from '@trackunit/react-components';
4
4
  import { useCopyToClipboard } from 'react-use';
5
5
  import { cvaMerge } from '@trackunit/css-class-variance-utilities';
6
6
  import * as React from 'react';
7
- import React__default, { useMemo, forwardRef, useCallback, cloneElement, useState, useRef, useEffect, useImperativeHandle } from 'react';
7
+ import React__default, { useMemo, forwardRef, useState, useRef, useCallback, cloneElement, useEffect, useImperativeHandle } from 'react';
8
8
  import { v4 } from 'uuid';
9
9
  import { format } from 'date-fns';
10
10
  import parsePhoneNumberFromString, { isSupportedCountry, getCountries, getCountryCallingCode, AsYouType, parseIncompletePhoneNumber, isValidPhoneNumber } from 'libphonenumber-js';
@@ -19,6 +19,8 @@ import { z } from 'zod';
19
19
 
20
20
  var defaultTranslations = {
21
21
  "clearIndicator.icon.tooltip.clearAll": "Clear all",
22
+ "dropzone.input.title": "Drag-and-drop file input",
23
+ "dropzone.label.default": "<clickable>Browse</clickable> or drag files here...",
22
24
  "phoneField.error.INVALID_COUNTRY": "The country code is not valid",
23
25
  "phoneField.error.INVALID_LENGTH": "The phone number is not valid",
24
26
  "phoneField.error.INVALID_NUMBER": "The phone number is not valid",
@@ -65,6 +67,10 @@ const translations = {
65
67
  * Local useTranslation for this specific library
66
68
  */
67
69
  const useTranslation = () => useNamespaceTranslation(namespace);
70
+ /**
71
+ * Trans for this specific library.
72
+ */
73
+ const Trans = (props) => (jsx(NamespaceTrans, Object.assign({}, props, { namespace: namespace })));
68
74
  /**
69
75
  * Registers the translations for this library
70
76
  */
@@ -600,17 +606,32 @@ const cvaDropZoneLabel = cvaMerge([
600
606
  "flex",
601
607
  "justify-center",
602
608
  ]);
609
+ const cvaDropZoneIconBackground = cvaMerge(["relative", "flex", "items-center", "justify-center", "rounded-full", "p-3"], {
610
+ variants: {
611
+ invalid: { true: ["bg-red-100"], false: ["bg-slate-200"] },
612
+ },
613
+ });
614
+
615
+ /**
616
+ *
617
+ * Default UX-intuitive label for the DropZone - can be overwritten by the label prop
618
+ */
619
+ const DropZoneDefaultLabel = () => (jsx(Trans, { components: {
620
+ clickable: jsx("span", { className: "text-primary-600 hover:text-primary-700 cursor-pointer underline" }),
621
+ }, i18nKey: "dropzone.label.default", values: {} }));
603
622
 
604
623
  /**
605
- * The Drop Zone can be used to drag and drop files
624
+ * The Drop Zone can be used to drag and drop files or to browse and select files from the file system.
606
625
  *
607
626
  * @param {DropZoneProps} props - The props for the DropZone component
608
627
  * @returns {JSX.Element} DropZone component
609
628
  */
610
629
  const DropZone = (_a) => {
611
- var { className, dataTestId, filesSelected, label, size = "large", isInvalid = false, disabled = false } = _a, rest = __rest(_a, ["className", "dataTestId", "filesSelected", "label", "size", "isInvalid", "disabled"]);
612
- const [dragActive, setDragActive] = React__default.useState(false);
613
- const [fileDropped, setFileDropped] = React__default.useState(false);
630
+ var { className, dataTestId, filesSelected, label = jsx(DropZoneDefaultLabel, {}), size = "large", isInvalid = false, disabled = false, accept } = _a, rest = __rest(_a, ["className", "dataTestId", "filesSelected", "label", "size", "isInvalid", "disabled", "accept"]);
631
+ const [dragActive, setDragActive] = useState(false);
632
+ const [fileDropped, setFileDropped] = useState(false);
633
+ const [t] = useTranslation();
634
+ const inputLabelRef = useRef(null);
614
635
  // function that handles drag enter, drag leave and drag over
615
636
  const handleDrag = (e) => {
616
637
  e.preventDefault();
@@ -630,7 +651,7 @@ const DropZone = (_a) => {
630
651
  filesSelected(e.target.files);
631
652
  }
632
653
  };
633
- //funtion to handle drop
654
+ //function to handle drop
634
655
  const handleDrop = (e) => {
635
656
  e.preventDefault();
636
657
  e.stopPropagation();
@@ -640,12 +661,22 @@ const DropZone = (_a) => {
640
661
  setFileDropped(true);
641
662
  }
642
663
  };
664
+ //function to handle focusable button click (for accessibility)
665
+ const handleButtonClick = (e) => {
666
+ var _a;
667
+ e.preventDefault();
668
+ e.stopPropagation();
669
+ if (disabled) {
670
+ return;
671
+ }
672
+ (_a = inputLabelRef.current) === null || _a === void 0 ? void 0 : _a.click();
673
+ };
643
674
  return (jsxs("div", Object.assign({ className: cvaDropZone({ size, dropComplete: fileDropped, dragActive, disabled, invalid: isInvalid, className }), "data-testid": dataTestId, onClick: e => {
644
675
  if (disabled) {
645
676
  e.preventDefault();
646
677
  e.stopPropagation();
647
678
  }
648
- }, onDragEnter: handleDrag, onDragLeave: handleDrag, onDragOver: handleDrag, onDrop: handleDrop }, rest, { children: [jsx("input", { className: "hidden", id: "input-file-upload", onChange: handleChange, title: "Hidden File Input", type: "file" }), jsxs("label", { className: cvaDropZoneLabel(), "data-testid": dataTestId && `${dataTestId}-label`, htmlFor: "input-file-upload", children: [jsx(Icon, { color: isInvalid ? "danger" : "neutral", name: "ArrowUpCircle", style: !isInvalid ? { color: "rgb(156 163 175)" } : {}, type: "solid" }), jsx("span", { children: label })] })] })));
679
+ }, onDragEnter: handleDrag, onDragLeave: handleDrag, onDragOver: handleDrag, onDrop: handleDrop }, rest, { children: [jsx("input", { accept: accept, className: "hidden", id: "input-file-upload", onChange: handleChange, title: t("dropzone.input.title"), type: "file" }), jsxs("label", { className: cvaDropZoneLabel(), "data-testid": dataTestId && `${dataTestId}-label`, htmlFor: "input-file-upload", ref: inputLabelRef, children: [jsx("div", { className: cvaDropZoneIconBackground({ invalid: isInvalid }), children: jsx(Icon, { className: !isInvalid ? "text-gray-400" : "", color: isInvalid ? "danger" : "neutral", name: "ArrowUpCircle", type: "solid" }) }), jsx("button", { disabled: disabled, onClick: handleButtonClick, children: label })] })] })));
649
680
  };
650
681
 
651
682
  // Doing the same check as we do on the backend
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-form-components",
3
- "version": "0.0.343-alpha-869e1cbc10.0",
3
+ "version": "0.0.343",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -4,9 +4,9 @@ import { BaseInputProps } from "../BaseInput";
4
4
  type BaseInputExposedProps = Omit<BaseInputProps, "type" | "suffix" | "prefix" | "addonAfter" | "addonBefore" | "actions" | "placeholder" | "fieldSize" | "size" | "nonInteractive">;
5
5
  export interface DropZoneProps extends BaseInputExposedProps, CommonProps {
6
6
  /**
7
- * A string to set the label in Drop Zone.
7
+ * A JSX element or a string to set a focusable label in Drop Zone. If not provided, the default label will be used.
8
8
  */
9
- label: string;
9
+ label?: JSX.Element | string;
10
10
  /**
11
11
  * A flag to disable the drop zone.
12
12
  */
@@ -25,10 +25,10 @@ export interface DropZoneProps extends BaseInputExposedProps, CommonProps {
25
25
  filesSelected: (file: FileList) => void;
26
26
  }
27
27
  /**
28
- * The Drop Zone can be used to drag and drop files
28
+ * The Drop Zone can be used to drag and drop files or to browse and select files from the file system.
29
29
  *
30
30
  * @param {DropZoneProps} props - The props for the DropZone component
31
31
  * @returns {JSX.Element} DropZone component
32
32
  */
33
- export declare const DropZone: ({ className, dataTestId, filesSelected, label, size, isInvalid, disabled, ...rest }: DropZoneProps) => JSX.Element;
33
+ export declare const DropZone: ({ className, dataTestId, filesSelected, label, size, isInvalid, disabled, accept, ...rest }: DropZoneProps) => JSX.Element;
34
34
  export {};
@@ -6,3 +6,6 @@ export declare const cvaDropZone: (props?: ({
6
6
  invalid?: boolean | null | undefined;
7
7
  } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
8
8
  export declare const cvaDropZoneLabel: (props?: import("class-variance-authority/dist/types").ClassProp | undefined) => string;
9
+ export declare const cvaDropZoneIconBackground: (props?: ({
10
+ invalid?: boolean | null | undefined;
11
+ } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
@@ -0,0 +1,6 @@
1
+ /// <reference types="react" />
2
+ /**
3
+ *
4
+ * Default UX-intuitive label for the DropZone - can be overwritten by the label prop
5
+ */
6
+ export declare const DropZoneDefaultLabel: () => JSX.Element;
@@ -15,8 +15,8 @@ export declare const translations: TranslationResource<TranslationKeys>;
15
15
  /**
16
16
  * Local useTranslation for this specific library
17
17
  */
18
- export declare const useTranslation: () => [TransForLibs<"clearIndicator.icon.tooltip.clearAll" | "phoneField.error.INVALID_COUNTRY" | "phoneField.error.INVALID_LENGTH" | "phoneField.error.INVALID_NUMBER" | "phoneField.error.NOT_A_NUMBER" | "phoneField.error.REQUIRED" | "phoneField.error.REQUIRED_COUNTRY" | "phoneField.error.TOO_LONG" | "phoneField.error.TOO_SHORT" | "phoneField.error.undefined">, import("i18next").i18n, boolean] & {
19
- t: TransForLibs<"clearIndicator.icon.tooltip.clearAll" | "phoneField.error.INVALID_COUNTRY" | "phoneField.error.INVALID_LENGTH" | "phoneField.error.INVALID_NUMBER" | "phoneField.error.NOT_A_NUMBER" | "phoneField.error.REQUIRED" | "phoneField.error.REQUIRED_COUNTRY" | "phoneField.error.TOO_LONG" | "phoneField.error.TOO_SHORT" | "phoneField.error.undefined">;
18
+ export declare const useTranslation: () => [TransForLibs<"clearIndicator.icon.tooltip.clearAll" | "dropzone.input.title" | "dropzone.label.default" | "phoneField.error.INVALID_COUNTRY" | "phoneField.error.INVALID_LENGTH" | "phoneField.error.INVALID_NUMBER" | "phoneField.error.NOT_A_NUMBER" | "phoneField.error.REQUIRED" | "phoneField.error.REQUIRED_COUNTRY" | "phoneField.error.TOO_LONG" | "phoneField.error.TOO_SHORT" | "phoneField.error.undefined">, import("i18next").i18n, boolean] & {
19
+ t: TransForLibs<"clearIndicator.icon.tooltip.clearAll" | "dropzone.input.title" | "dropzone.label.default" | "phoneField.error.INVALID_COUNTRY" | "phoneField.error.INVALID_LENGTH" | "phoneField.error.INVALID_NUMBER" | "phoneField.error.NOT_A_NUMBER" | "phoneField.error.REQUIRED" | "phoneField.error.REQUIRED_COUNTRY" | "phoneField.error.TOO_LONG" | "phoneField.error.TOO_SHORT" | "phoneField.error.undefined">;
20
20
  i18n: import("i18next").i18n;
21
21
  ready: boolean;
22
22
  };