@kwiz/fluentui 1.0.16 → 1.0.19
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/.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
|
};
|