@kwiz/fluentui 1.0.16 → 1.0.19
Sign up to get free protection for your applications and to get access to all the features.
- package/.github/workflows/npm-publish.yml +34 -0
- package/LICENSE +21 -21
- package/README.md +26 -26
- package/package.json +72 -72
- package/src/_modules/config.ts +9 -9
- package/src/_modules/constants.ts +3 -3
- package/src/controls/accordion.tsx +48 -48
- package/src/controls/button.tsx +169 -169
- package/src/controls/centered.tsx +22 -22
- package/src/controls/date.tsx +39 -39
- package/src/controls/dropdown.tsx +51 -51
- package/src/controls/error-boundary.tsx +41 -41
- package/src/controls/field-editor.tsx +40 -40
- package/src/controls/file-upload.tsx +67 -67
- package/src/controls/horizontal.tsx +34 -34
- package/src/controls/input.tsx +60 -60
- package/src/controls/kwizoverflow.tsx +103 -103
- package/src/controls/list.tsx +117 -117
- package/src/controls/loading.tsx +10 -10
- package/src/controls/please-wait.tsx +32 -32
- package/src/controls/prompt.tsx +96 -96
- package/src/controls/search.tsx +65 -65
- package/src/controls/section.tsx +51 -51
- package/src/controls/svg.tsx +120 -120
- package/src/controls/toolbar.tsx +48 -48
- package/src/controls/vertical-content.tsx +49 -49
- package/src/controls/vertical.tsx +34 -34
- package/src/helpers/context.ts +39 -39
- package/src/helpers/hooks.tsx +335 -335
- package/src/index.ts +26 -26
- package/src/styles/styles.ts +87 -87
- package/src/styles/theme.ts +90 -90
- package/dist/_modules/build.d.ts +0 -2
- package/dist/_modules/build.js +0 -3
- package/dist/_modules/build.js.map +0 -1
- package/dist/_modules/config.d.ts +0 -1
- package/dist/_modules/config.js +0 -9
- package/dist/_modules/config.js.map +0 -1
- package/dist/_modules/constants.d.ts +0 -2
- package/dist/_modules/constants.js +0 -3
- package/dist/_modules/constants.js.map +0 -1
- package/dist/_modules/exports-index.d.ts +0 -1
- package/dist/_modules/exports-index.js +0 -2
- package/dist/_modules/exports-index.js.map +0 -1
- package/dist/controls/accordion.d.ts +0 -13
- package/dist/controls/accordion.js +0 -27
- package/dist/controls/accordion.js.map +0 -1
- package/dist/controls/button.d.ts +0 -28
- package/dist/controls/button.js +0 -113
- package/dist/controls/button.js.map +0 -1
- package/dist/controls/centered.d.ts +0 -5
- package/dist/controls/centered.js +0 -14
- package/dist/controls/centered.js.map +0 -1
- package/dist/controls/date.d.ts +0 -8
- package/dist/controls/date.js +0 -32
- package/dist/controls/date.js.map +0 -1
- package/dist/controls/dropdown.d.ts +0 -29
- package/dist/controls/dropdown.js +0 -27
- package/dist/controls/dropdown.js.map +0 -1
- package/dist/controls/error-boundary.d.ts +0 -23
- package/dist/controls/error-boundary.js +0 -33
- package/dist/controls/error-boundary.js.map +0 -1
- package/dist/controls/exports-index.d.ts +0 -17
- package/dist/controls/exports-index.js +0 -18
- package/dist/controls/exports-index.js.map +0 -1
- package/dist/controls/field-editor.d.ts +0 -13
- package/dist/controls/field-editor.js +0 -15
- package/dist/controls/field-editor.js.map +0 -1
- package/dist/controls/file-upload.d.ts +0 -18
- package/dist/controls/file-upload.js +0 -41
- package/dist/controls/file-upload.js.map +0 -1
- package/dist/controls/horizontal.d.ts +0 -8
- package/dist/controls/horizontal.js +0 -23
- package/dist/controls/horizontal.js.map +0 -1
- package/dist/controls/input.d.ts +0 -13
- package/dist/controls/input.js +0 -43
- package/dist/controls/input.js.map +0 -1
- package/dist/controls/kwizoverflow.d.ts +0 -14
- package/dist/controls/kwizoverflow.js +0 -45
- package/dist/controls/kwizoverflow.js.map +0 -1
- package/dist/controls/list.d.ts +0 -21
- package/dist/controls/list.js +0 -72
- package/dist/controls/list.js.map +0 -1
- package/dist/controls/loading copy.d.ts +0 -5
- package/dist/controls/loading copy.js +0 -7
- package/dist/controls/loading copy.js.map +0 -1
- package/dist/controls/loading.d.ts +0 -5
- package/dist/controls/loading.js +0 -7
- package/dist/controls/loading.js.map +0 -1
- package/dist/controls/please-wait.d.ts +0 -18
- package/dist/controls/please-wait.js +0 -16
- package/dist/controls/please-wait.js.map +0 -1
- package/dist/controls/prompt.d.ts +0 -32
- package/dist/controls/prompt.js +0 -31
- package/dist/controls/prompt.js.map +0 -1
- package/dist/controls/search.d.ts +0 -13
- package/dist/controls/search.js +0 -47
- package/dist/controls/search.js.map +0 -1
- package/dist/controls/section.d.ts +0 -14
- package/dist/controls/section.js +0 -27
- package/dist/controls/section.js.map +0 -1
- package/dist/controls/svg.d.ts +0 -23
- package/dist/controls/svg.js +0 -45
- package/dist/controls/svg.js.map +0 -1
- package/dist/controls/toolbar.d.ts +0 -12
- package/dist/controls/toolbar.js +0 -23
- package/dist/controls/toolbar.js.map +0 -1
- package/dist/controls/vertical-content.d.ts +0 -6
- package/dist/controls/vertical-content.js +0 -37
- package/dist/controls/vertical-content.js.map +0 -1
- package/dist/controls/vertical.d.ts +0 -8
- package/dist/controls/vertical.js +0 -23
- package/dist/controls/vertical.js.map +0 -1
- package/dist/exports-index.d.ts +0 -3
- package/dist/exports-index.js +0 -4
- package/dist/exports-index.js.map +0 -1
- package/dist/helpers/context.d.ts +0 -26
- package/dist/helpers/context.js +0 -15
- package/dist/helpers/context.js.map +0 -1
- package/dist/helpers/hooks.d.ts +0 -62
- package/dist/helpers/hooks.js +0 -287
- package/dist/helpers/hooks.js.map +0 -1
- package/dist/index.d.ts +0 -25
- package/dist/index.js +0 -25
- package/dist/index.js.map +0 -1
- package/dist/styles/exports-index.d.ts +0 -2
- package/dist/styles/exports-index.js +0 -3
- package/dist/styles/exports-index.js.map +0 -1
- package/dist/styles/styles.d.ts +0 -19
- package/dist/styles/styles.js +0 -79
- package/dist/styles/styles.js.map +0 -1
- package/dist/styles/theme.d.ts +0 -6
- package/dist/styles/theme.js +0 -77
- package/dist/styles/theme.js.map +0 -1
@@ -1,41 +1,41 @@
|
|
1
|
-
import { Field, mergeClasses, Textarea } from '@fluentui/react-components';
|
2
|
-
import { isNullOrUndefined } from '@kwiz/common';
|
3
|
-
import React from 'react';
|
4
|
-
import { GetLogger } from '../_modules/config';
|
5
|
-
import { InputEx } from './input';
|
6
|
-
|
7
|
-
const logger = GetLogger('FieldEditor');
|
8
|
-
|
9
|
-
interface IProps {
|
10
|
-
required?: boolean;
|
11
|
-
error?: string;
|
12
|
-
value: string;
|
13
|
-
onChange: (newValue: string) => void;
|
14
|
-
css: string[];
|
15
|
-
label: string;
|
16
|
-
description?: string;
|
17
|
-
type?: "text" | "multiline"
|
18
|
-
}
|
19
|
-
export const FieldEditor: React.FunctionComponent<IProps> = (props) => {
|
20
|
-
if (isNullOrUndefined(props.value)) {
|
21
|
-
logger.error(`${props.label}: value should not be null`);
|
22
|
-
}
|
23
|
-
return (
|
24
|
-
<Field required={props.required}
|
25
|
-
validationMessage={props.error || props.description}
|
26
|
-
validationState={props.error ? "error" : "none"}>
|
27
|
-
{props.type === "multiline"
|
28
|
-
? <Textarea className={props.css && mergeClasses(...props.css)}
|
29
|
-
required={props.required}
|
30
|
-
placeholder={props.label}
|
31
|
-
value={props.value || ""}
|
32
|
-
onChange={(e, data) => props.onChange(data.value)}
|
33
|
-
/>
|
34
|
-
: <InputEx className={props.css && mergeClasses(...props.css)}
|
35
|
-
required={props.required}
|
36
|
-
placeholder={props.label}
|
37
|
-
value={props.value || ""}
|
38
|
-
onChange={(e, data) => props.onChange(data.value)} />}
|
39
|
-
</Field>
|
40
|
-
);
|
1
|
+
import { Field, mergeClasses, Textarea } from '@fluentui/react-components';
|
2
|
+
import { isNullOrUndefined } from '@kwiz/common';
|
3
|
+
import React from 'react';
|
4
|
+
import { GetLogger } from '../_modules/config';
|
5
|
+
import { InputEx } from './input';
|
6
|
+
|
7
|
+
const logger = GetLogger('FieldEditor');
|
8
|
+
|
9
|
+
interface IProps {
|
10
|
+
required?: boolean;
|
11
|
+
error?: string;
|
12
|
+
value: string;
|
13
|
+
onChange: (newValue: string) => void;
|
14
|
+
css: string[];
|
15
|
+
label: string;
|
16
|
+
description?: string;
|
17
|
+
type?: "text" | "multiline"
|
18
|
+
}
|
19
|
+
export const FieldEditor: React.FunctionComponent<IProps> = (props) => {
|
20
|
+
if (isNullOrUndefined(props.value)) {
|
21
|
+
logger.error(`${props.label}: value should not be null`);
|
22
|
+
}
|
23
|
+
return (
|
24
|
+
<Field required={props.required}
|
25
|
+
validationMessage={props.error || props.description}
|
26
|
+
validationState={props.error ? "error" : "none"}>
|
27
|
+
{props.type === "multiline"
|
28
|
+
? <Textarea className={props.css && mergeClasses(...props.css)}
|
29
|
+
required={props.required}
|
30
|
+
placeholder={props.label}
|
31
|
+
value={props.value || ""}
|
32
|
+
onChange={(e, data) => props.onChange(data.value)}
|
33
|
+
/>
|
34
|
+
: <InputEx className={props.css && mergeClasses(...props.css)}
|
35
|
+
required={props.required}
|
36
|
+
placeholder={props.label}
|
37
|
+
value={props.value || ""}
|
38
|
+
onChange={(e, data) => props.onChange(data.value)} />}
|
39
|
+
</Field>
|
40
|
+
);
|
41
41
|
}
|
@@ -1,68 +1,68 @@
|
|
1
|
-
import { ButtonProps } from "@fluentui/react-components";
|
2
|
-
import { isFunction, isNotEmptyArray, isNullOrEmptyString } from '@kwiz/common';
|
3
|
-
import * as React from "react";
|
4
|
-
import { ButtonEX, CompoundButtonEXSecondary } from "./button";
|
5
|
-
|
6
|
-
interface iProps {
|
7
|
-
showTitleWithIcon?: boolean;
|
8
|
-
title?: string;
|
9
|
-
/** Passing this will turn the button into a compound button */
|
10
|
-
secondaryContent?: string;
|
11
|
-
limitFileTypes?: string[];
|
12
|
-
allowMultiple?: boolean;
|
13
|
-
icon?: JSX.Element;
|
14
|
-
onChange?: (newFile: File | FileList) => void;
|
15
|
-
/** only works for single file, reads it as base64 */
|
16
|
-
asBase64?: (base64: string) => void;
|
17
|
-
buttonProps?: ButtonProps;
|
18
|
-
disabled?: boolean;
|
19
|
-
}
|
20
|
-
|
21
|
-
export const FileUpload = React.forwardRef<HTMLButtonElement, (iProps)>((props, ref) => {
|
22
|
-
const hiddenFileInput = React.useRef(null);
|
23
|
-
const isMulti = props.allowMultiple === true;
|
24
|
-
return <>
|
25
|
-
{isNullOrEmptyString(props.secondaryContent)
|
26
|
-
? <ButtonEX ref={ref} {...(props.buttonProps || {})} icon={props.icon} showTitleWithIcon={props.showTitleWithIcon} onClick={() => {
|
27
|
-
hiddenFileInput.current.value = "";
|
28
|
-
hiddenFileInput.current.click();
|
29
|
-
}} title={props.title}
|
30
|
-
disabled={props.disabled}
|
31
|
-
/>
|
32
|
-
: <CompoundButtonEXSecondary ref={ref} {...(props.buttonProps || {})} icon={props.icon}
|
33
|
-
secondaryContent={props.secondaryContent}
|
34
|
-
onClick={() => {
|
35
|
-
hiddenFileInput.current.value = "";
|
36
|
-
hiddenFileInput.current.click();
|
37
|
-
}} title={props.title}
|
38
|
-
disabled={props.disabled}
|
39
|
-
/>}
|
40
|
-
<input type="file" ref={hiddenFileInput} style={{ display: "none" }} multiple={isMulti}
|
41
|
-
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
|
-
}}
|
66
|
-
/>
|
67
|
-
</>;
|
1
|
+
import { ButtonProps } from "@fluentui/react-components";
|
2
|
+
import { isFunction, isNotEmptyArray, isNullOrEmptyString } from '@kwiz/common';
|
3
|
+
import * as React from "react";
|
4
|
+
import { ButtonEX, CompoundButtonEXSecondary } from "./button";
|
5
|
+
|
6
|
+
interface iProps {
|
7
|
+
showTitleWithIcon?: boolean;
|
8
|
+
title?: string;
|
9
|
+
/** Passing this will turn the button into a compound button */
|
10
|
+
secondaryContent?: string;
|
11
|
+
limitFileTypes?: string[];
|
12
|
+
allowMultiple?: boolean;
|
13
|
+
icon?: JSX.Element;
|
14
|
+
onChange?: (newFile: File | FileList) => void;
|
15
|
+
/** only works for single file, reads it as base64 */
|
16
|
+
asBase64?: (base64: string) => void;
|
17
|
+
buttonProps?: ButtonProps;
|
18
|
+
disabled?: boolean;
|
19
|
+
}
|
20
|
+
|
21
|
+
export const FileUpload = React.forwardRef<HTMLButtonElement, (iProps)>((props, ref) => {
|
22
|
+
const hiddenFileInput = React.useRef(null);
|
23
|
+
const isMulti = props.allowMultiple === true;
|
24
|
+
return <>
|
25
|
+
{isNullOrEmptyString(props.secondaryContent)
|
26
|
+
? <ButtonEX ref={ref} {...(props.buttonProps || {})} icon={props.icon} showTitleWithIcon={props.showTitleWithIcon} onClick={() => {
|
27
|
+
hiddenFileInput.current.value = "";
|
28
|
+
hiddenFileInput.current.click();
|
29
|
+
}} title={props.title}
|
30
|
+
disabled={props.disabled}
|
31
|
+
/>
|
32
|
+
: <CompoundButtonEXSecondary ref={ref} {...(props.buttonProps || {})} icon={props.icon}
|
33
|
+
secondaryContent={props.secondaryContent}
|
34
|
+
onClick={() => {
|
35
|
+
hiddenFileInput.current.value = "";
|
36
|
+
hiddenFileInput.current.click();
|
37
|
+
}} title={props.title}
|
38
|
+
disabled={props.disabled}
|
39
|
+
/>}
|
40
|
+
<input type="file" ref={hiddenFileInput} style={{ display: "none" }} multiple={isMulti}
|
41
|
+
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
|
+
}}
|
66
|
+
/>
|
67
|
+
</>;
|
68
68
|
});
|
@@ -1,35 +1,35 @@
|
|
1
|
-
import { makeStyles } from '@fluentui/react-components';
|
2
|
-
import { isNotEmptyArray } from '@kwiz/common';
|
3
|
-
import React from 'react';
|
4
|
-
import { KnownClassNames, mixins } from '../styles/styles';
|
5
|
-
import { ISectionProps, Section } from './section';
|
6
|
-
|
7
|
-
const useStyles = makeStyles({
|
8
|
-
horizontal: {
|
9
|
-
...mixins.flex,
|
10
|
-
flexDirection: 'row'
|
11
|
-
},
|
12
|
-
wrap: mixins.wrap,
|
13
|
-
nogap: mixins.nogap
|
14
|
-
})
|
15
|
-
|
16
|
-
interface IProps extends ISectionProps {
|
17
|
-
wrap?: boolean;
|
18
|
-
nogap?: boolean;
|
19
|
-
}
|
20
|
-
export const Horizontal: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
21
|
-
const cssNames = useStyles();
|
22
|
-
let css: string[] = [KnownClassNames.horizontal];
|
23
|
-
|
24
|
-
css.push(cssNames.horizontal);
|
25
|
-
if (props.wrap)
|
26
|
-
css.push(cssNames.wrap);
|
27
|
-
if (props.nogap)
|
28
|
-
css.push(cssNames.nogap);
|
29
|
-
|
30
|
-
if (isNotEmptyArray(props.css)) css.push(...props.css);
|
31
|
-
|
32
|
-
return (
|
33
|
-
<Section {...props} css={css} />
|
34
|
-
);
|
1
|
+
import { makeStyles } from '@fluentui/react-components';
|
2
|
+
import { isNotEmptyArray } from '@kwiz/common';
|
3
|
+
import React from 'react';
|
4
|
+
import { KnownClassNames, mixins } from '../styles/styles';
|
5
|
+
import { ISectionProps, Section } from './section';
|
6
|
+
|
7
|
+
const useStyles = makeStyles({
|
8
|
+
horizontal: {
|
9
|
+
...mixins.flex,
|
10
|
+
flexDirection: 'row'
|
11
|
+
},
|
12
|
+
wrap: mixins.wrap,
|
13
|
+
nogap: mixins.nogap
|
14
|
+
})
|
15
|
+
|
16
|
+
interface IProps extends ISectionProps {
|
17
|
+
wrap?: boolean;
|
18
|
+
nogap?: boolean;
|
19
|
+
}
|
20
|
+
export const Horizontal: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
21
|
+
const cssNames = useStyles();
|
22
|
+
let css: string[] = [KnownClassNames.horizontal];
|
23
|
+
|
24
|
+
css.push(cssNames.horizontal);
|
25
|
+
if (props.wrap)
|
26
|
+
css.push(cssNames.wrap);
|
27
|
+
if (props.nogap)
|
28
|
+
css.push(cssNames.nogap);
|
29
|
+
|
30
|
+
if (isNotEmptyArray(props.css)) css.push(...props.css);
|
31
|
+
|
32
|
+
return (
|
33
|
+
<Section {...props} css={css} />
|
34
|
+
);
|
35
35
|
}
|
package/src/controls/input.tsx
CHANGED
@@ -1,61 +1,61 @@
|
|
1
|
-
import { GriffelStyle, Input, InputProps, makeStyles, mergeClasses, Textarea, TextareaProps } from '@fluentui/react-components';
|
2
|
-
import { isFunction } from '@kwiz/common';
|
3
|
-
import React from 'react';
|
4
|
-
import { useKWIZFluentContext } from '../helpers/context';
|
5
|
-
|
6
|
-
|
7
|
-
interface IProps extends InputProps {
|
8
|
-
onOK?: () => void;
|
9
|
-
onCancel?: () => void;
|
10
|
-
}
|
11
|
-
export const InputEx: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
12
|
-
const ctx = useKWIZFluentContext();
|
13
|
-
return (
|
14
|
-
<Input appearance={ctx.inputAppearance} {...props}
|
15
|
-
onKeyDown={isFunction(props.onOK) || isFunction(props.onCancel)
|
16
|
-
? e => {
|
17
|
-
if (isFunction(props.onOK) && e.key === "Enter") props.onOK();
|
18
|
-
else if (isFunction(props.onCancel) && e.key === "Escape") props.onCancel();
|
19
|
-
}
|
20
|
-
: undefined
|
21
|
-
}
|
22
|
-
/>
|
23
|
-
);
|
24
|
-
}
|
25
|
-
|
26
|
-
const fullSize: GriffelStyle = {
|
27
|
-
width: '100% !important',
|
28
|
-
maxHeight: '100% !important'
|
29
|
-
};
|
30
|
-
const useStyles = makeStyles({
|
31
|
-
fullSizeTextArea: {
|
32
|
-
...fullSize,
|
33
|
-
['& > textarea']: fullSize
|
34
|
-
},
|
35
|
-
})
|
36
|
-
|
37
|
-
interface IPropsTextArea extends TextareaProps {
|
38
|
-
fullSize?: boolean;
|
39
|
-
growNoShrink?: boolean;
|
40
|
-
}
|
41
|
-
export const TextAreaEx: React.FunctionComponent<React.PropsWithChildren<IPropsTextArea>> = (props) => {
|
42
|
-
const cssNames = useStyles();
|
43
|
-
let css: string[] = [];
|
44
|
-
|
45
|
-
if (props.fullSize) css.push(cssNames.fullSizeTextArea);
|
46
|
-
const textAreaRef = React.useRef<HTMLTextAreaElement>(null);
|
47
|
-
const recalcHeight = React.useCallback(() => {
|
48
|
-
if (textAreaRef.current && props.growNoShrink) {
|
49
|
-
if (textAreaRef.current.scrollHeight > textAreaRef.current.clientHeight)
|
50
|
-
textAreaRef.current.style.minHeight = textAreaRef.current.scrollHeight + 'px';
|
51
|
-
}
|
52
|
-
}, [textAreaRef]);
|
53
|
-
|
54
|
-
let style: React.CSSProperties = { height: '100%', ...props.style };
|
55
|
-
return (
|
56
|
-
<Textarea ref={textAreaRef} className={mergeClasses(...css)} {...props} style={style} onChange={(e, d) => {
|
57
|
-
if (props.onChange) props.onChange(e, d);
|
58
|
-
recalcHeight();
|
59
|
-
}} />
|
60
|
-
);
|
1
|
+
import { GriffelStyle, Input, InputProps, makeStyles, mergeClasses, Textarea, TextareaProps } from '@fluentui/react-components';
|
2
|
+
import { isFunction } from '@kwiz/common';
|
3
|
+
import React from 'react';
|
4
|
+
import { useKWIZFluentContext } from '../helpers/context';
|
5
|
+
|
6
|
+
|
7
|
+
interface IProps extends InputProps {
|
8
|
+
onOK?: () => void;
|
9
|
+
onCancel?: () => void;
|
10
|
+
}
|
11
|
+
export const InputEx: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
12
|
+
const ctx = useKWIZFluentContext();
|
13
|
+
return (
|
14
|
+
<Input appearance={ctx.inputAppearance} {...props}
|
15
|
+
onKeyDown={isFunction(props.onOK) || isFunction(props.onCancel)
|
16
|
+
? e => {
|
17
|
+
if (isFunction(props.onOK) && e.key === "Enter") props.onOK();
|
18
|
+
else if (isFunction(props.onCancel) && e.key === "Escape") props.onCancel();
|
19
|
+
}
|
20
|
+
: undefined
|
21
|
+
}
|
22
|
+
/>
|
23
|
+
);
|
24
|
+
}
|
25
|
+
|
26
|
+
const fullSize: GriffelStyle = {
|
27
|
+
width: '100% !important',
|
28
|
+
maxHeight: '100% !important'
|
29
|
+
};
|
30
|
+
const useStyles = makeStyles({
|
31
|
+
fullSizeTextArea: {
|
32
|
+
...fullSize,
|
33
|
+
['& > textarea']: fullSize
|
34
|
+
},
|
35
|
+
})
|
36
|
+
|
37
|
+
interface IPropsTextArea extends TextareaProps {
|
38
|
+
fullSize?: boolean;
|
39
|
+
growNoShrink?: boolean;
|
40
|
+
}
|
41
|
+
export const TextAreaEx: React.FunctionComponent<React.PropsWithChildren<IPropsTextArea>> = (props) => {
|
42
|
+
const cssNames = useStyles();
|
43
|
+
let css: string[] = [];
|
44
|
+
|
45
|
+
if (props.fullSize) css.push(cssNames.fullSizeTextArea);
|
46
|
+
const textAreaRef = React.useRef<HTMLTextAreaElement>(null);
|
47
|
+
const recalcHeight = React.useCallback(() => {
|
48
|
+
if (textAreaRef.current && props.growNoShrink) {
|
49
|
+
if (textAreaRef.current.scrollHeight > textAreaRef.current.clientHeight)
|
50
|
+
textAreaRef.current.style.minHeight = textAreaRef.current.scrollHeight + 'px';
|
51
|
+
}
|
52
|
+
}, [textAreaRef]);
|
53
|
+
|
54
|
+
let style: React.CSSProperties = { height: '100%', ...props.style };
|
55
|
+
return (
|
56
|
+
<Textarea ref={textAreaRef} className={mergeClasses(...css)} {...props} style={style} onChange={(e, d) => {
|
57
|
+
if (props.onChange) props.onChange(e, d);
|
58
|
+
recalcHeight();
|
59
|
+
}} />
|
60
|
+
);
|
61
61
|
}
|
@@ -1,104 +1,104 @@
|
|
1
|
-
import {
|
2
|
-
Menu, MenuButton, MenuItem, MenuList, MenuPopover, MenuTrigger, Overflow, OverflowItem,
|
3
|
-
useIsOverflowItemVisible, useOverflowMenu
|
4
|
-
} from "@fluentui/react-components";
|
5
|
-
import { MoreHorizontalFilled } from "@fluentui/react-icons";
|
6
|
-
import { isNumber } from '@kwiz/common';
|
7
|
-
|
8
|
-
interface IProps<ItemType> {
|
9
|
-
/** you cannot have a menu with trigger in overflow items. put those in groupWrapper controls before/after rendering children. */
|
10
|
-
items: ItemType[];
|
11
|
-
getKey: (item: ItemType, index: number) => string;
|
12
|
-
getPriority?: (item: ItemType, index: number) => number;
|
13
|
-
renderItem: (item: ItemType, index: number, overflow?: boolean) => JSX.Element;
|
14
|
-
groupWrapper?: (children: React.ReactNode) => JSX.Element;
|
15
|
-
menuRef?: React.RefObject<HTMLButtonElement>;
|
16
|
-
menuWrapper?: (children: React.ReactNode) => JSX.Element;
|
17
|
-
menuTrigger?: (ref: React.RefObject<HTMLButtonElement>, overflowCount: number) => JSX.Element;
|
18
|
-
className?: string;
|
19
|
-
}
|
20
|
-
const OverflowMenu = <ItemType,>(props: IProps<ItemType>) => {
|
21
|
-
const { ref, isOverflowing, overflowCount } =
|
22
|
-
useOverflowMenu<HTMLButtonElement>();
|
23
|
-
|
24
|
-
if (!isOverflowing) {
|
25
|
-
return null;
|
26
|
-
}
|
27
|
-
|
28
|
-
let menu = <Menu>
|
29
|
-
<MenuTrigger disableButtonEnhancement>
|
30
|
-
{props.menuTrigger
|
31
|
-
? props.menuTrigger(props.menuRef || ref, overflowCount)
|
32
|
-
: <MenuButton
|
33
|
-
icon={<MoreHorizontalFilled/>}
|
34
|
-
ref={props.menuRef || ref}
|
35
|
-
aria-label="More items"
|
36
|
-
appearance="subtle"
|
37
|
-
/>}
|
38
|
-
</MenuTrigger>
|
39
|
-
<MenuPopover>
|
40
|
-
<MenuList>
|
41
|
-
{props.items.map((item, index) => (
|
42
|
-
<OverflowMenuItem key={props.getKey(item, index)} {...props} item={item} index={index} />
|
43
|
-
))}
|
44
|
-
</MenuList>
|
45
|
-
</MenuPopover>
|
46
|
-
</Menu>;
|
47
|
-
|
48
|
-
return (
|
49
|
-
props.menuWrapper
|
50
|
-
? props.menuWrapper(menu)
|
51
|
-
: menu
|
52
|
-
);
|
53
|
-
}
|
54
|
-
|
55
|
-
const OverflowMenuItem = <ItemType,>(props: IProps<ItemType> & { item: ItemType, index: number }) => {
|
56
|
-
const isVisible = useIsOverflowItemVisible(props.getKey(props.item, props.index));
|
57
|
-
|
58
|
-
if (isVisible) {
|
59
|
-
return null;
|
60
|
-
}
|
61
|
-
|
62
|
-
return (
|
63
|
-
<MenuItem key={props.getKey(props.item, props.index)}>
|
64
|
-
{props.renderItem(props.item, props.index, true)}
|
65
|
-
</MenuItem>
|
66
|
-
);
|
67
|
-
};
|
68
|
-
export const KWIZOverflow = <ItemType,>(props: IProps<ItemType>) => {
|
69
|
-
let content: JSX.Element[] = [];
|
70
|
-
let addMenu = () => {
|
71
|
-
if (menuIndex >= 0)
|
72
|
-
content.splice(menuIndex, 0, <OverflowMenu key="overflow_menu" {...props} />);
|
73
|
-
else
|
74
|
-
content.push(<OverflowMenu key="overflow_menu" {...props} />);
|
75
|
-
};
|
76
|
-
|
77
|
-
let menuIndex = -1;
|
78
|
-
|
79
|
-
props.items.forEach((item, index) => {
|
80
|
-
//add the menu before the first item with priority
|
81
|
-
let priority = props.getPriority ? props.getPriority(item, index) : undefined;
|
82
|
-
if (isNumber(priority) && priority > 0)
|
83
|
-
menuIndex = index;
|
84
|
-
|
85
|
-
content.push(<OverflowItem key={props.getKey(item, index)} id={props.getKey(item, index)}
|
86
|
-
priority={priority}>
|
87
|
-
{props.renderItem(item, index)}
|
88
|
-
</OverflowItem>);
|
89
|
-
});
|
90
|
-
|
91
|
-
addMenu();
|
92
|
-
|
93
|
-
return (
|
94
|
-
<Overflow minimumVisible={2} padding={60} key={`overflow_${props.items.length}`}>
|
95
|
-
<div style={{ overflow: "hidden" }} className={props.className}>
|
96
|
-
{
|
97
|
-
props.groupWrapper
|
98
|
-
? props.groupWrapper(content)
|
99
|
-
: content
|
100
|
-
}
|
101
|
-
</div>
|
102
|
-
</Overflow>
|
103
|
-
)
|
1
|
+
import {
|
2
|
+
Menu, MenuButton, MenuItem, MenuList, MenuPopover, MenuTrigger, Overflow, OverflowItem,
|
3
|
+
useIsOverflowItemVisible, useOverflowMenu
|
4
|
+
} from "@fluentui/react-components";
|
5
|
+
import { MoreHorizontalFilled } from "@fluentui/react-icons";
|
6
|
+
import { isNumber } from '@kwiz/common';
|
7
|
+
|
8
|
+
interface IProps<ItemType> {
|
9
|
+
/** you cannot have a menu with trigger in overflow items. put those in groupWrapper controls before/after rendering children. */
|
10
|
+
items: ItemType[];
|
11
|
+
getKey: (item: ItemType, index: number) => string;
|
12
|
+
getPriority?: (item: ItemType, index: number) => number;
|
13
|
+
renderItem: (item: ItemType, index: number, overflow?: boolean) => JSX.Element;
|
14
|
+
groupWrapper?: (children: React.ReactNode) => JSX.Element;
|
15
|
+
menuRef?: React.RefObject<HTMLButtonElement>;
|
16
|
+
menuWrapper?: (children: React.ReactNode) => JSX.Element;
|
17
|
+
menuTrigger?: (ref: React.RefObject<HTMLButtonElement>, overflowCount: number) => JSX.Element;
|
18
|
+
className?: string;
|
19
|
+
}
|
20
|
+
const OverflowMenu = <ItemType,>(props: IProps<ItemType>) => {
|
21
|
+
const { ref, isOverflowing, overflowCount } =
|
22
|
+
useOverflowMenu<HTMLButtonElement>();
|
23
|
+
|
24
|
+
if (!isOverflowing) {
|
25
|
+
return null;
|
26
|
+
}
|
27
|
+
|
28
|
+
let menu = <Menu>
|
29
|
+
<MenuTrigger disableButtonEnhancement>
|
30
|
+
{props.menuTrigger
|
31
|
+
? props.menuTrigger(props.menuRef || ref, overflowCount)
|
32
|
+
: <MenuButton
|
33
|
+
icon={<MoreHorizontalFilled/>}
|
34
|
+
ref={props.menuRef || ref}
|
35
|
+
aria-label="More items"
|
36
|
+
appearance="subtle"
|
37
|
+
/>}
|
38
|
+
</MenuTrigger>
|
39
|
+
<MenuPopover>
|
40
|
+
<MenuList>
|
41
|
+
{props.items.map((item, index) => (
|
42
|
+
<OverflowMenuItem key={props.getKey(item, index)} {...props} item={item} index={index} />
|
43
|
+
))}
|
44
|
+
</MenuList>
|
45
|
+
</MenuPopover>
|
46
|
+
</Menu>;
|
47
|
+
|
48
|
+
return (
|
49
|
+
props.menuWrapper
|
50
|
+
? props.menuWrapper(menu)
|
51
|
+
: menu
|
52
|
+
);
|
53
|
+
}
|
54
|
+
|
55
|
+
const OverflowMenuItem = <ItemType,>(props: IProps<ItemType> & { item: ItemType, index: number }) => {
|
56
|
+
const isVisible = useIsOverflowItemVisible(props.getKey(props.item, props.index));
|
57
|
+
|
58
|
+
if (isVisible) {
|
59
|
+
return null;
|
60
|
+
}
|
61
|
+
|
62
|
+
return (
|
63
|
+
<MenuItem key={props.getKey(props.item, props.index)}>
|
64
|
+
{props.renderItem(props.item, props.index, true)}
|
65
|
+
</MenuItem>
|
66
|
+
);
|
67
|
+
};
|
68
|
+
export const KWIZOverflow = <ItemType,>(props: IProps<ItemType>) => {
|
69
|
+
let content: JSX.Element[] = [];
|
70
|
+
let addMenu = () => {
|
71
|
+
if (menuIndex >= 0)
|
72
|
+
content.splice(menuIndex, 0, <OverflowMenu key="overflow_menu" {...props} />);
|
73
|
+
else
|
74
|
+
content.push(<OverflowMenu key="overflow_menu" {...props} />);
|
75
|
+
};
|
76
|
+
|
77
|
+
let menuIndex = -1;
|
78
|
+
|
79
|
+
props.items.forEach((item, index) => {
|
80
|
+
//add the menu before the first item with priority
|
81
|
+
let priority = props.getPriority ? props.getPriority(item, index) : undefined;
|
82
|
+
if (isNumber(priority) && priority > 0)
|
83
|
+
menuIndex = index;
|
84
|
+
|
85
|
+
content.push(<OverflowItem key={props.getKey(item, index)} id={props.getKey(item, index)}
|
86
|
+
priority={priority}>
|
87
|
+
{props.renderItem(item, index)}
|
88
|
+
</OverflowItem>);
|
89
|
+
});
|
90
|
+
|
91
|
+
addMenu();
|
92
|
+
|
93
|
+
return (
|
94
|
+
<Overflow minimumVisible={2} padding={60} key={`overflow_${props.items.length}`}>
|
95
|
+
<div style={{ overflow: "hidden" }} className={props.className}>
|
96
|
+
{
|
97
|
+
props.groupWrapper
|
98
|
+
? props.groupWrapper(content)
|
99
|
+
: content
|
100
|
+
}
|
101
|
+
</div>
|
102
|
+
</Overflow>
|
103
|
+
)
|
104
104
|
};
|