@kwiz/fluentui 1.0.39 → 1.0.40

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,9 @@
1
1
  import { ButtonProps } from "@fluentui/react-components";
2
2
  import * as React from "react";
3
+ type base64Result = {
4
+ base64: string;
5
+ filename: string;
6
+ };
3
7
  interface iProps {
4
8
  showTitleWithIcon?: boolean;
5
9
  title?: string;
@@ -8,11 +12,12 @@ interface iProps {
8
12
  limitFileTypes?: string[];
9
13
  allowMultiple?: boolean;
10
14
  icon?: JSX.Element;
11
- onChange?: (newFile: File | FileList) => void;
12
- /** only works for single file, reads it as base64 */
13
- asBase64?: (base64: string) => void;
15
+ onChange?: (newFile: File | File[], errors: string[]) => void;
16
+ asBase64?: (files: base64Result[], errors: string[]) => void;
14
17
  buttonProps?: ButtonProps;
15
18
  disabled?: boolean;
19
+ /** limit file size in MB, for the asBase64 */
20
+ fileSizeLimit?: number;
16
21
  }
17
22
  export declare const FileUpload: React.ForwardRefExoticComponent<iProps & React.RefAttributes<HTMLButtonElement>>;
18
23
  export {};
@@ -1,41 +1,123 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { isFunction, isNotEmptyArray, isNullOrEmptyString } from '@kwiz/common';
11
+ import { makeStyles, shorthands, tokens } from "@fluentui/react-components";
12
+ import { ArrowUploadRegular } from "@fluentui/react-icons";
13
+ import { isFunction, isNotEmptyArray, isNotEmptyString, isNullOrEmptyString, lastOrNull } from '@kwiz/common';
3
14
  import * as React from "react";
15
+ import { useDragDropContext } from "../helpers/drag-drop/drag-drop-context";
16
+ import { useEffectOnlyOnMount } from "../helpers/hooks";
4
17
  import { ButtonEX, CompoundButtonEXSecondary } from "./button";
18
+ const useStyles = makeStyles({
19
+ addRowIsOver: Object.assign({}, shorthands.borderColor(tokens.colorBrandBackground))
20
+ });
5
21
  export const FileUpload = React.forwardRef((props, ref) => {
22
+ const classes = useStyles();
6
23
  const hiddenFileInput = React.useRef(null);
7
24
  const isMulti = props.allowMultiple === true;
25
+ const icon = props.icon || _jsx(ArrowUploadRegular, {});
26
+ const title = isNotEmptyString(props.title) ? props.title : `Drop or select ${isMulti ? 'files' : 'file'}`;
27
+ const onGotFiles = React.useCallback((rawFiles) => __awaiter(void 0, void 0, void 0, function* () {
28
+ let errors = [];
29
+ let acceptedFiles = [];
30
+ if (rawFiles && rawFiles.length > 0) {
31
+ //filter by types and size
32
+ for (let i = 0; i < (isMulti ? rawFiles.length : 1); i++) {
33
+ const currentFile = rawFiles[i];
34
+ let hadError = false;
35
+ if (props.fileSizeLimit > 0) {
36
+ const megabytes = currentFile.size / (1024 * 1024);
37
+ if (megabytes > props.fileSizeLimit) {
38
+ errors.push(`File ${currentFile.name} is over the size limit`);
39
+ hadError = true;
40
+ }
41
+ }
42
+ if (!hadError) {
43
+ if (isNotEmptyArray(props.limitFileTypes)) {
44
+ let fileType = lastOrNull(currentFile.name.split('.')).toLowerCase();
45
+ if (props.limitFileTypes.indexOf(fileType) < 0) {
46
+ errors.push(`File ${currentFile.name} is not allowed`);
47
+ hadError = true;
48
+ }
49
+ }
50
+ }
51
+ if (!hadError)
52
+ acceptedFiles.push(currentFile);
53
+ }
54
+ }
55
+ if (isMulti) {
56
+ if (isFunction(props.onChange)) {
57
+ props.onChange(acceptedFiles, errors);
58
+ }
59
+ }
60
+ else {
61
+ const fileUploaded = acceptedFiles[0];
62
+ if (isFunction(props.onChange)) {
63
+ props.onChange(fileUploaded, errors);
64
+ }
65
+ }
66
+ if (isFunction(props.asBase64)) {
67
+ const filesAs64 = [];
68
+ for (let i = 0; i < (isMulti ? acceptedFiles.length : 1); i++) {
69
+ const currentFile = acceptedFiles[i];
70
+ let hadError = false;
71
+ if (props.fileSizeLimit > 0) {
72
+ const megabytes = currentFile.size / (1024 * 1024);
73
+ if (megabytes > props.fileSizeLimit) {
74
+ errors.push(`File ${currentFile.name} is over the size limit`);
75
+ hadError = true;
76
+ }
77
+ }
78
+ if (!hadError) {
79
+ let as64 = yield getFileAsBase64(acceptedFiles[i]);
80
+ if (as64)
81
+ filesAs64.push(as64);
82
+ else
83
+ errors.push(`Could not read file ${acceptedFiles[i].name}`);
84
+ }
85
+ }
86
+ props.asBase64(filesAs64, errors);
87
+ }
88
+ }), useEffectOnlyOnMount);
89
+ const dropContext = useDragDropContext({
90
+ dropInfo: {
91
+ acceptTypes: ["__NATIVE_FILE__"],
92
+ onItemDrop: item => {
93
+ onGotFiles(item.files);
94
+ }
95
+ }
96
+ });
8
97
  return _jsxs(_Fragment, { children: [isNullOrEmptyString(props.secondaryContent)
9
- ? _jsx(ButtonEX, Object.assign({ ref: ref }, (props.buttonProps || {}), { icon: props.icon, showTitleWithIcon: props.showTitleWithIcon, onClick: () => {
98
+ ? _jsx(ButtonEX, Object.assign({ ref: ref || dropContext.dragDropRef }, (props.buttonProps || {}), { icon: icon, showTitleWithIcon: props.showTitleWithIcon, onClick: () => {
10
99
  hiddenFileInput.current.value = "";
11
100
  hiddenFileInput.current.click();
12
- }, title: props.title, disabled: props.disabled }))
13
- : _jsx(CompoundButtonEXSecondary, Object.assign({ ref: ref }, (props.buttonProps || {}), { icon: props.icon, secondaryContent: props.secondaryContent, onClick: () => {
101
+ }, title: title, disabled: props.disabled, className: dropContext.drop.isOver && classes.addRowIsOver }))
102
+ : _jsx(CompoundButtonEXSecondary, Object.assign({ ref: ref || dropContext.dragDropRef }, (props.buttonProps || {}), { icon: icon, secondaryContent: props.secondaryContent, onClick: () => {
14
103
  hiddenFileInput.current.value = "";
15
104
  hiddenFileInput.current.click();
16
- }, title: props.title, disabled: props.disabled })), _jsx("input", { type: "file", ref: hiddenFileInput, style: { display: "none" }, multiple: isMulti, accept: isNotEmptyArray(props.limitFileTypes) ? props.limitFileTypes.map(ft => `.${ft}`).join() : undefined, onChange: (e) => {
17
- if (e.target.files && e.target.files.length > 0) {
18
- if (isMulti) {
19
- if (isFunction(props.onChange)) {
20
- props.onChange(e.target.files);
21
- }
22
- }
23
- else {
24
- const fileUploaded = e.target.files && e.target.files[0];
25
- if (isFunction(props.onChange)) {
26
- props.onChange(fileUploaded);
27
- }
28
- if (isFunction(props.asBase64) && fileUploaded) {
29
- const reader = new FileReader();
30
- reader.onloadend = () => {
31
- console.log(reader.result);
32
- if (!isNullOrEmptyString(reader.result))
33
- props.asBase64(reader.result);
34
- };
35
- reader.readAsDataURL(fileUploaded);
36
- }
37
- }
38
- }
39
- } })] });
105
+ }, title: title, disabled: props.disabled, className: dropContext.drop.isOver && classes.addRowIsOver })), _jsx("input", { type: "file", ref: hiddenFileInput, style: { display: "none" }, multiple: isMulti, accept: isNotEmptyArray(props.limitFileTypes) ? props.limitFileTypes.map(ft => `.${ft}`).join() : undefined, onChange: (e) => __awaiter(void 0, void 0, void 0, function* () { return onGotFiles(e.target.files); }) })] });
40
106
  });
107
+ function getFileAsBase64(file) {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ return new Promise(resolve => {
110
+ const reader = new FileReader();
111
+ reader.onloadend = () => {
112
+ if (!isNullOrEmptyString(reader.result))
113
+ resolve({ filename: file.name, base64: reader.result });
114
+ else {
115
+ console.warn("Empty file selected");
116
+ resolve(null);
117
+ }
118
+ };
119
+ reader.readAsDataURL(file);
120
+ });
121
+ });
122
+ }
41
123
  //# sourceMappingURL=file-upload.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-upload.js","sourceRoot":"","sources":["../../src/controls/file-upload.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-upload.js","sourceRoot":"","sources":["../../src/controls/file-upload.tsx"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAe,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9G,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAE5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAE/D,MAAM,SAAS,GAAG,UAAU,CAAC;IACzB,YAAY,oBACL,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,oBAAoB,CAAC,CACzD;CACJ,CAAC,CAAC;AAmBH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAA8B,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACnF,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;IAC5B,MAAM,eAAe,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,KAAC,kBAAkB,KAAG,CAAC;IAClD,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAE3G,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,CAAO,QAAkB,EAAE,EAAE;QAC9D,IAAI,MAAM,GAAa,EAAE,CAAC;QAC1B,IAAI,aAAa,GAAW,EAAE,CAAC;QAC/B,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,0BAA0B;YAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvD,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAChC,IAAI,QAAQ,GAAG,KAAK,CAAC;gBACrB,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;oBAC1B,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;oBACnD,IAAI,SAAS,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;wBAClC,MAAM,CAAC,IAAI,CAAC,QAAQ,WAAW,CAAC,IAAI,yBAAyB,CAAC,CAAC;wBAC/D,QAAQ,GAAG,IAAI,CAAC;oBACpB,CAAC;gBACL,CAAC;gBACD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACZ,IAAI,eAAe,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;wBACxC,IAAI,QAAQ,GAAG,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;wBACrE,IAAI,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;4BAC7C,MAAM,CAAC,IAAI,CAAC,QAAQ,WAAW,CAAC,IAAI,iBAAiB,CAAC,CAAC;4BACvD,QAAQ,GAAG,IAAI,CAAC;wBACpB,CAAC;oBACL,CAAC;gBACL,CAAC;gBACD,IAAI,CAAC,QAAQ;oBAAE,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACnD,CAAC;QACL,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACV,IAAI,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,KAAK,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YAC1C,CAAC;QACL,CAAC;aACI,CAAC;YACF,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YACtC,IAAI,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YACzC,CAAC;QACL,CAAC;QAED,IAAI,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAmB,EAAE,CAAC;YACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5D,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;gBACrC,IAAI,QAAQ,GAAG,KAAK,CAAC;gBACrB,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;oBAC1B,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;oBACnD,IAAI,SAAS,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;wBAClC,MAAM,CAAC,IAAI,CAAC,QAAQ,WAAW,CAAC,IAAI,yBAAyB,CAAC,CAAC;wBAC/D,QAAQ,GAAG,IAAI,CAAC;oBACpB,CAAC;gBACL,CAAC;gBACD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACZ,IAAI,IAAI,GAAG,MAAM,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;oBACnD,IAAI,IAAI;wBAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;wBAC1B,MAAM,CAAC,IAAI,CAAC,uBAAuB,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBACrE,CAAC;YACL,CAAC;YACD,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;IACL,CAAC,CAAA,EAAE,oBAAoB,CAAC,CAAC;IAEzB,MAAM,WAAW,GAAG,kBAAkB,CAAmB;QACrD,QAAQ,EAAE;YACN,WAAW,EAAE,CAAC,iBAAiB,CAAC;YAChC,UAAU,EAAE,IAAI,CAAC,EAAE;gBACf,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC;SACJ;KACJ,CAAC,CAAC;IAEH,OAAO,8BACF,mBAAmB,CAAC,KAAK,CAAC,gBAAgB,CAAC;gBACxC,CAAC,CAAC,KAAC,QAAQ,kBAAC,GAAG,EAAE,GAAG,IAAI,WAAW,CAAC,WAAW,IAAM,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,IAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE;wBAClJ,eAAe,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;wBACnC,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;oBACpC,CAAC,EACG,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACtC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,YAAY,IAC5D;gBACF,CAAC,CAAC,KAAC,yBAAyB,kBAAC,GAAG,EAAE,GAAG,IAAI,WAAW,CAAC,WAAW,IAAM,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,IAAE,IAAI,EAAE,IAAI,EACvG,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EACxC,OAAO,EAAE,GAAG,EAAE;wBACV,eAAe,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;wBACnC,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;oBACpC,CAAC,EACD,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACtC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,YAAY,IAC5D,EACN,gBAAO,IAAI,EAAC,MAAM,EAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,EAClF,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,EAC3G,QAAQ,EAAE,CAAO,CAAC,EAAE,EAAE,kDAAC,OAAA,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,GAAA,GACnD,IACH,CAAC;AACR,CAAC,CAAC,CAAC;AAEH,SAAe,eAAe,CAAC,IAAU;;QACrC,OAAO,IAAI,OAAO,CAAe,OAAO,CAAC,EAAE;YACvC,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAChC,MAAM,CAAC,SAAS,GAAG,GAAG,EAAE;gBACpB,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC;oBACnC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAgB,EAAE,CAAC,CAAC;qBACjE,CAAC;oBACF,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;oBACpC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAClB,CAAC;YACL,CAAC,CAAC;YACF,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACP,CAAC;CAAA"}
@@ -2,12 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Menu, MenuButton, MenuItem, MenuList, MenuPopover, MenuTrigger, Overflow, OverflowItem, useIsOverflowItemVisible, useOverflowMenu } from "@fluentui/react-components";
3
3
  import { MoreHorizontalFilled } from "@fluentui/react-icons";
4
4
  import { isNumber } from '@kwiz/common';
5
+ import { useKWIZFluentContext } from "../helpers/context";
5
6
  const OverflowMenu = (props) => {
7
+ const ctx = useKWIZFluentContext();
6
8
  const { ref, isOverflowing, overflowCount } = useOverflowMenu();
7
9
  if (!isOverflowing) {
8
10
  return null;
9
11
  }
10
- let menu = _jsxs(Menu, { children: [_jsx(MenuTrigger, { disableButtonEnhancement: true, children: props.menuTrigger
12
+ let menu = _jsxs(Menu, { mountNode: ctx.mountNode, children: [_jsx(MenuTrigger, { disableButtonEnhancement: true, children: props.menuTrigger
11
13
  ? props.menuTrigger(props.menuRef || ref, overflowCount)
12
14
  : _jsx(MenuButton, { icon: _jsx(MoreHorizontalFilled, {}), ref: props.menuRef || ref, "aria-label": "More items", appearance: "subtle" }) }), _jsx(MenuPopover, { children: _jsx(MenuList, { children: props.items.map((item, index) => (_jsx(OverflowMenuItem, Object.assign({}, props, { item: item, index: index }), props.getKey(item, index)))) }) })] });
13
15
  return (props.menuWrapper
@@ -1 +1 @@
1
- {"version":3,"file":"kwizoverflow.js","sourceRoot":"","sources":["../../src/controls/kwizoverflow.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kwizoverflow.js","sourceRoot":"","sources":["../../src/controls/kwizoverflow.tsx"],"names":[],"mappings":";AAAA,OAAO,EACH,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EACtF,wBAAwB,EAAE,eAAe,EAC5C,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAc1D,MAAM,YAAY,GAAG,CAAY,KAAuB,EAAE,EAAE;IACxD,MAAM,GAAG,GAAG,oBAAoB,EAAE,CAAC;IAEnC,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,aAAa,EAAE,GACvC,eAAe,EAAqB,CAAC;IAEzC,IAAI,CAAC,aAAa,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,IAAI,GAAG,MAAC,IAAI,IAAC,SAAS,EAAE,GAAG,CAAC,SAAS,aACrC,KAAC,WAAW,IAAC,wBAAwB,kBAChC,KAAK,CAAC,WAAW;oBACd,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,IAAI,GAAG,EAAE,aAAa,CAAC;oBACxD,CAAC,CAAC,KAAC,UAAU,IACT,IAAI,EAAE,KAAC,oBAAoB,KAAG,EAC9B,GAAG,EAAE,KAAK,CAAC,OAAO,IAAI,GAAG,gBACd,YAAY,EACvB,UAAU,EAAC,QAAQ,GACrB,GACI,EACd,KAAC,WAAW,cACR,KAAC,QAAQ,cACJ,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC9B,KAAC,gBAAgB,oBAAqC,KAAK,IAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,KAA9D,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAyC,CAC5F,CAAC,GACK,GACD,IACX,CAAC;IAER,OAAO,CACH,KAAK,CAAC,WAAW;QACb,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC;QACzB,CAAC,CAAC,IAAI,CACb,CAAC;AACN,CAAC,CAAA;AAED,MAAM,gBAAgB,GAAG,CAAY,KAA2D,EAAE,EAAE;IAChG,MAAM,SAAS,GAAG,wBAAwB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAElF,IAAI,SAAS,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,CACH,KAAC,QAAQ,cACJ,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,IADrC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAEzC,CACd,CAAC;AACN,CAAC,CAAC;AACF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAY,KAAuB,EAAE,EAAE;IAC/D,IAAI,OAAO,GAAkB,EAAE,CAAC;IAChC,IAAI,OAAO,GAAG,GAAG,EAAE;QACf,IAAI,SAAS,IAAI,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,KAAC,YAAY,oBAAyB,KAAK,GAAzB,eAAe,CAAc,CAAC,CAAC;;YAE9E,OAAO,CAAC,IAAI,CAAC,KAAC,YAAY,oBAAyB,KAAK,GAAzB,eAAe,CAAc,CAAC,CAAC;IACtE,CAAC,CAAC;IAEF,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC;IAEnB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAChC,kDAAkD;QAClD,IAAI,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9E,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC;YAClC,SAAS,GAAG,KAAK,CAAC;QAEtB,OAAO,CAAC,IAAI,CAAC,KAAC,YAAY,IAAiC,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,EACpF,QAAQ,EAAE,QAAQ,YACjB,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,IAFF,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAG1C,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,CAAC;IAEV,OAAO,CACH,KAAC,QAAQ,IAAC,cAAc,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,YACpC,cAAK,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,YAEtD,KAAK,CAAC,YAAY;gBACd,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC;gBAC7B,CAAC,CAAC,OAAO,GAEf,IAPqC,YAAY,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAQpE,CACd,CAAA;AACL,CAAC,CAAC"}
@@ -1,4 +1,12 @@
1
+ import { NativeTypes } from 'react-dnd-html5-backend';
2
+ import { iDraggedItemType } from './use-draggable';
3
+ import { iDroppableProps } from './use-droppable';
1
4
  export { DragDropContainer } from './drag-drop-container';
2
5
  export { DragDropContextProvider, useDragDropContext } from "./drag-drop-context";
3
6
  export type { iDraggedItemType } from "./use-draggable";
4
7
  export type { iDroppableProps } from "./use-droppable";
8
+ type fileNativeType = typeof NativeTypes.FILE;
9
+ interface dragFiles extends iDraggedItemType<fileNativeType> {
10
+ files: FileList;
11
+ }
12
+ export type dropFiles = iDroppableProps<fileNativeType, dragFiles>;
@@ -1 +1 @@
1
- {"version":3,"file":"exports.js","sourceRoot":"","sources":["../../../src/helpers/drag-drop/exports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"exports.js","sourceRoot":"","sources":["../../../src/helpers/drag-drop/exports.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kwiz/fluentui",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "KWIZ common controls for FluentUI",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,8 +1,19 @@
1
- import { ButtonProps } from "@fluentui/react-components";
2
- import { isFunction, isNotEmptyArray, isNullOrEmptyString } from '@kwiz/common';
1
+ import { ButtonProps, makeStyles, shorthands, tokens } from "@fluentui/react-components";
2
+ import { ArrowUploadRegular } from "@fluentui/react-icons";
3
+ import { isFunction, isNotEmptyArray, isNotEmptyString, isNullOrEmptyString, lastOrNull } from '@kwiz/common';
3
4
  import * as React from "react";
5
+ import { useDragDropContext } from "../helpers/drag-drop/drag-drop-context";
6
+ import { dropFiles } from "../helpers/drag-drop/exports";
7
+ import { useEffectOnlyOnMount } from "../helpers/hooks";
4
8
  import { ButtonEX, CompoundButtonEXSecondary } from "./button";
5
9
 
10
+ const useStyles = makeStyles({
11
+ addRowIsOver: {
12
+ ...shorthands.borderColor(tokens.colorBrandBackground)
13
+ }
14
+ });
15
+
16
+ type base64Result = { base64: string, filename: string };
6
17
  interface iProps {
7
18
  showTitleWithIcon?: boolean;
8
19
  title?: string;
@@ -11,58 +22,128 @@ interface iProps {
11
22
  limitFileTypes?: string[];
12
23
  allowMultiple?: boolean;
13
24
  icon?: JSX.Element;
14
- onChange?: (newFile: File | FileList) => void;
15
- /** only works for single file, reads it as base64 */
16
- asBase64?: (base64: string) => void;
25
+ onChange?: (newFile: File | File[], errors: string[]) => void;
26
+ asBase64?: (files: base64Result[], errors: string[]) => void;
17
27
  buttonProps?: ButtonProps;
18
28
  disabled?: boolean;
29
+ /** limit file size in MB, for the asBase64 */
30
+ fileSizeLimit?: number;
19
31
  }
20
32
 
21
33
  export const FileUpload = React.forwardRef<HTMLButtonElement, (iProps)>((props, ref) => {
34
+ const classes = useStyles();
22
35
  const hiddenFileInput = React.useRef(null);
23
36
  const isMulti = props.allowMultiple === true;
37
+ const icon = props.icon || <ArrowUploadRegular />;
38
+ const title = isNotEmptyString(props.title) ? props.title : `Drop or select ${isMulti ? 'files' : 'file'}`;
39
+
40
+ const onGotFiles = React.useCallback(async (rawFiles: FileList) => {
41
+ let errors: string[] = [];
42
+ let acceptedFiles: File[] = [];
43
+ if (rawFiles && rawFiles.length > 0) {
44
+ //filter by types and size
45
+ for (let i = 0; i < (isMulti ? rawFiles.length : 1); i++) {
46
+ const currentFile = rawFiles[i];
47
+ let hadError = false;
48
+ if (props.fileSizeLimit > 0) {
49
+ const megabytes = currentFile.size / (1024 * 1024);
50
+ if (megabytes > props.fileSizeLimit) {
51
+ errors.push(`File ${currentFile.name} is over the size limit`);
52
+ hadError = true;
53
+ }
54
+ }
55
+ if (!hadError) {
56
+ if (isNotEmptyArray(props.limitFileTypes)) {
57
+ let fileType = lastOrNull(currentFile.name.split('.')).toLowerCase();
58
+ if (props.limitFileTypes.indexOf(fileType) < 0) {
59
+ errors.push(`File ${currentFile.name} is not allowed`);
60
+ hadError = true;
61
+ }
62
+ }
63
+ }
64
+ if (!hadError) acceptedFiles.push(currentFile);
65
+ }
66
+ }
67
+
68
+ if (isMulti) {
69
+ if (isFunction(props.onChange)) {
70
+ props.onChange(acceptedFiles, errors);
71
+ }
72
+ }
73
+ else {
74
+ const fileUploaded = acceptedFiles[0];
75
+ if (isFunction(props.onChange)) {
76
+ props.onChange(fileUploaded, errors);
77
+ }
78
+ }
79
+
80
+ if (isFunction(props.asBase64)) {
81
+ const filesAs64: base64Result[] = [];
82
+ for (let i = 0; i < (isMulti ? acceptedFiles.length : 1); i++) {
83
+ const currentFile = acceptedFiles[i];
84
+ let hadError = false;
85
+ if (props.fileSizeLimit > 0) {
86
+ const megabytes = currentFile.size / (1024 * 1024);
87
+ if (megabytes > props.fileSizeLimit) {
88
+ errors.push(`File ${currentFile.name} is over the size limit`);
89
+ hadError = true;
90
+ }
91
+ }
92
+ if (!hadError) {
93
+ let as64 = await getFileAsBase64(acceptedFiles[i]);
94
+ if (as64) filesAs64.push(as64);
95
+ else errors.push(`Could not read file ${acceptedFiles[i].name}`);
96
+ }
97
+ }
98
+ props.asBase64(filesAs64, errors);
99
+ }
100
+ }, useEffectOnlyOnMount);
101
+
102
+ const dropContext = useDragDropContext<never, dropFiles>({
103
+ dropInfo: {
104
+ acceptTypes: ["__NATIVE_FILE__"],
105
+ onItemDrop: item => {
106
+ onGotFiles(item.files);
107
+ }
108
+ }
109
+ });
110
+
24
111
  return <>
25
112
  {isNullOrEmptyString(props.secondaryContent)
26
- ? <ButtonEX ref={ref} {...(props.buttonProps || {})} icon={props.icon} showTitleWithIcon={props.showTitleWithIcon} onClick={() => {
113
+ ? <ButtonEX ref={ref || dropContext.dragDropRef} {...(props.buttonProps || {})} icon={icon} showTitleWithIcon={props.showTitleWithIcon} onClick={() => {
27
114
  hiddenFileInput.current.value = "";
28
115
  hiddenFileInput.current.click();
29
- }} title={props.title}
30
- disabled={props.disabled}
116
+ }}
117
+ title={title} disabled={props.disabled}
118
+ className={dropContext.drop.isOver && classes.addRowIsOver}
31
119
  />
32
- : <CompoundButtonEXSecondary ref={ref} {...(props.buttonProps || {})} icon={props.icon}
120
+ : <CompoundButtonEXSecondary ref={ref || dropContext.dragDropRef} {...(props.buttonProps || {})} icon={icon}
33
121
  secondaryContent={props.secondaryContent}
34
122
  onClick={() => {
35
123
  hiddenFileInput.current.value = "";
36
124
  hiddenFileInput.current.click();
37
- }} title={props.title}
38
- disabled={props.disabled}
125
+ }}
126
+ title={title} disabled={props.disabled}
127
+ className={dropContext.drop.isOver && classes.addRowIsOver}
39
128
  />}
40
129
  <input type="file" ref={hiddenFileInput} style={{ display: "none" }} multiple={isMulti}
41
130
  accept={isNotEmptyArray(props.limitFileTypes) ? props.limitFileTypes.map(ft => `.${ft}`).join() : undefined}
42
- onChange={(e) => {
43
- if (e.target.files && e.target.files.length > 0) {
44
- if (isMulti) {
45
- if (isFunction(props.onChange)) {
46
- props.onChange(e.target.files);
47
- }
48
- }
49
- else {
50
- const fileUploaded = e.target.files && e.target.files[0];
51
- if (isFunction(props.onChange)) {
52
- props.onChange(fileUploaded);
53
- }
54
- if (isFunction(props.asBase64) && fileUploaded) {
55
- const reader = new FileReader();
56
- reader.onloadend = () => {
57
- console.log(reader.result);
58
- if (!isNullOrEmptyString(reader.result))
59
- props.asBase64(reader.result as string);
60
- };
61
- reader.readAsDataURL(fileUploaded);
62
- }
63
- }
64
- }
65
- }}
131
+ onChange={async (e) => onGotFiles(e.target.files)}
66
132
  />
67
133
  </>;
68
- });
134
+ });
135
+
136
+ async function getFileAsBase64(file: File): Promise<base64Result> {
137
+ return new Promise<base64Result>(resolve => {
138
+ const reader = new FileReader();
139
+ reader.onloadend = () => {
140
+ if (!isNullOrEmptyString(reader.result))
141
+ resolve({ filename: file.name, base64: reader.result as string });
142
+ else {
143
+ console.warn("Empty file selected");
144
+ resolve(null);
145
+ }
146
+ };
147
+ reader.readAsDataURL(file);
148
+ });
149
+ }
@@ -4,6 +4,7 @@ import {
4
4
  } from "@fluentui/react-components";
5
5
  import { MoreHorizontalFilled } from "@fluentui/react-icons";
6
6
  import { isNumber } from '@kwiz/common';
7
+ import { useKWIZFluentContext } from "../helpers/context";
7
8
 
8
9
  interface IProps<ItemType> {
9
10
  /** you cannot have a menu with trigger in overflow items. put those in groupWrapper controls before/after rendering children. */
@@ -18,6 +19,8 @@ interface IProps<ItemType> {
18
19
  className?: string;
19
20
  }
20
21
  const OverflowMenu = <ItemType,>(props: IProps<ItemType>) => {
22
+ const ctx = useKWIZFluentContext();
23
+
21
24
  const { ref, isOverflowing, overflowCount } =
22
25
  useOverflowMenu<HTMLButtonElement>();
23
26
 
@@ -25,12 +28,12 @@ const OverflowMenu = <ItemType,>(props: IProps<ItemType>) => {
25
28
  return null;
26
29
  }
27
30
 
28
- let menu = <Menu>
31
+ let menu = <Menu mountNode={ctx.mountNode}>
29
32
  <MenuTrigger disableButtonEnhancement>
30
33
  {props.menuTrigger
31
34
  ? props.menuTrigger(props.menuRef || ref, overflowCount)
32
35
  : <MenuButton
33
- icon={<MoreHorizontalFilled/>}
36
+ icon={<MoreHorizontalFilled />}
34
37
  ref={props.menuRef || ref}
35
38
  aria-label="More items"
36
39
  appearance="subtle"
@@ -1,4 +1,14 @@
1
+ import { NativeTypes } from 'react-dnd-html5-backend';
2
+ import { iDraggedItemType } from './use-draggable';
3
+ import { iDroppableProps } from './use-droppable';
4
+
1
5
  export { DragDropContainer } from './drag-drop-container';
2
6
  export { DragDropContextProvider, useDragDropContext } from "./drag-drop-context";
3
7
  export type { iDraggedItemType } from "./use-draggable";
4
- export type { iDroppableProps } from "./use-droppable";
8
+ export type { iDroppableProps } from "./use-droppable";
9
+
10
+ type fileNativeType = typeof NativeTypes.FILE;
11
+ interface dragFiles extends iDraggedItemType<fileNativeType> {
12
+ files: FileList;
13
+ }
14
+ export type dropFiles = iDroppableProps<fileNativeType, dragFiles>;