@kwiz/fluentui 1.0.15 → 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 -0
- 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 -102
- 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 -25
- 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/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 -13
- 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 -24
- package/dist/index.js +0 -24
- 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
package/src/controls/list.tsx
CHANGED
@@ -1,118 +1,118 @@
|
|
1
|
-
import { makeStyles, tokens } from '@fluentui/react-components';
|
2
|
-
import { LOGO_BLUE_SQUARE, LOGO_WHITE_SQUARE, isNullOrUndefined, isString } from '@kwiz/common';
|
3
|
-
import React from 'react';
|
4
|
-
import { KnownClassNames, mixins } from '../styles/styles';
|
5
|
-
import { Horizontal } from './horizontal';
|
6
|
-
import { Section } from './section';
|
7
|
-
import { Vertical } from './vertical';
|
8
|
-
|
9
|
-
const useStyles = makeStyles({
|
10
|
-
list: {
|
11
|
-
rowGap: 0
|
12
|
-
},
|
13
|
-
listItem: {
|
14
|
-
padding: tokens.spacingVerticalS,
|
15
|
-
':hover': {
|
16
|
-
backgroundColor: tokens.colorNeutralBackground1Hover
|
17
|
-
}
|
18
|
-
},
|
19
|
-
listItemSelected: {
|
20
|
-
backgroundColor: tokens.colorNeutralBackground1Selected
|
21
|
-
},
|
22
|
-
media: {
|
23
|
-
width: '32px',
|
24
|
-
fontSize: tokens.fontSizeBase600,
|
25
|
-
display: 'flex',
|
26
|
-
flexDirection: 'column',
|
27
|
-
justifyContent: 'center'
|
28
|
-
},
|
29
|
-
image: {
|
30
|
-
width: tokens.lineHeightBase600,
|
31
|
-
height: tokens.lineHeightBase600,
|
32
|
-
backgroundPosition: 'center center',
|
33
|
-
backgroundSize: 'cover',
|
34
|
-
borderRadius: tokens.borderRadiusCircular,
|
35
|
-
border: `1px solid ${tokens.colorNeutralStroke1}`
|
36
|
-
},
|
37
|
-
listItemBody: {
|
38
|
-
rowGap: 0,
|
39
|
-
width: 'calc(100% - 44px)'
|
40
|
-
},
|
41
|
-
listItemHeader: mixins.ellipsis,
|
42
|
-
listItemContent: {
|
43
|
-
...mixins.ellipsis,
|
44
|
-
fontSize: tokens.fontSizeBase200
|
45
|
-
},
|
46
|
-
listItemMedia: {
|
47
|
-
...mixins.ellipsis,
|
48
|
-
maxWidth: '20%',
|
49
|
-
'& svg': {
|
50
|
-
height: tokens.fontSizeBase300
|
51
|
-
},
|
52
|
-
'& button': {
|
53
|
-
padding: 0,
|
54
|
-
minWidth: 0,
|
55
|
-
minHeight: 0,
|
56
|
-
height: '14px'
|
57
|
-
}
|
58
|
-
},
|
59
|
-
listItemMediaNoTrim: {
|
60
|
-
overflow: 'visible',
|
61
|
-
maxWidth: 'fit-content'
|
62
|
-
},
|
63
|
-
listItemMultilineContent: {
|
64
|
-
whiteSpace: 'pre-line'
|
65
|
-
}
|
66
|
-
});
|
67
|
-
|
68
|
-
export interface iListItem {
|
69
|
-
key: string | number;
|
70
|
-
media?: JSX.Element | string;
|
71
|
-
header: string;
|
72
|
-
headerMedia?: JSX.Element | string;
|
73
|
-
content?: string | JSX.Element | (string | JSX.Element)[];
|
74
|
-
onClickOnMedia?: boolean;
|
75
|
-
onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
76
|
-
selected?: boolean;
|
77
|
-
}
|
78
|
-
interface IProps {
|
79
|
-
selectable?: boolean;
|
80
|
-
items: iListItem[];
|
81
|
-
showAllHeaderMedia?: boolean;
|
82
|
-
/** allow multiline content */
|
83
|
-
multiline?: boolean;
|
84
|
-
dark?: boolean;
|
85
|
-
}
|
86
|
-
|
87
|
-
export const ListEx = (props: IProps) => {
|
88
|
-
|
89
|
-
const cssNames = useStyles();
|
90
|
-
|
91
|
-
const listItemElm = (item: iListItem) => <Horizontal key={item.key} css={[cssNames.listItem, item.selected && cssNames.listItemSelected]} onClick={item.onClick}>
|
92
|
-
{item.media && <Section css={[cssNames.media]} onClick={(e) => {
|
93
|
-
if (!item.onClickOnMedia)
|
94
|
-
e.stopPropagation();//media may have its on onclick
|
95
|
-
}}>{
|
96
|
-
isString(item.media)
|
97
|
-
? <div className={cssNames.image} style={{ backgroundImage: `url('${encodeURI(item.media)}'), url('${props.dark ? LOGO_WHITE_SQUARE : LOGO_BLUE_SQUARE}')` }}></div>
|
98
|
-
: item.media
|
99
|
-
}</Section>}
|
100
|
-
<Vertical main css={[cssNames.listItemBody]}>
|
101
|
-
<Horizontal main>
|
102
|
-
<Section main css={[cssNames.listItemHeader]}>{item.header}</Section>
|
103
|
-
{item.headerMedia && <Section onClick={(e) => {
|
104
|
-
e.stopPropagation();//media may have its on onclick
|
105
|
-
}} css={[cssNames.listItemMedia, props.showAllHeaderMedia && cssNames.listItemMediaNoTrim]}>{item.headerMedia}</Section>}
|
106
|
-
</Horizontal>
|
107
|
-
{!isNullOrUndefined(item.content)
|
108
|
-
? (Array.isArray(item.content) ? item.content : [item.content]).map((c, idx) => isNullOrUndefined(c) ? undefined : <Section key={idx} css={[cssNames.listItemContent, props.multiline ? cssNames.listItemMultilineContent : undefined]}>{c}</Section>)
|
109
|
-
: undefined}
|
110
|
-
</Vertical>
|
111
|
-
</Horizontal>;
|
112
|
-
|
113
|
-
return (
|
114
|
-
<Vertical css={[cssNames.list, KnownClassNames.list]}>
|
115
|
-
{props.items.map(item => listItemElm(item))}
|
116
|
-
</Vertical>
|
117
|
-
);
|
1
|
+
import { makeStyles, tokens } from '@fluentui/react-components';
|
2
|
+
import { LOGO_BLUE_SQUARE, LOGO_WHITE_SQUARE, isNullOrUndefined, isString } from '@kwiz/common';
|
3
|
+
import React from 'react';
|
4
|
+
import { KnownClassNames, mixins } from '../styles/styles';
|
5
|
+
import { Horizontal } from './horizontal';
|
6
|
+
import { Section } from './section';
|
7
|
+
import { Vertical } from './vertical';
|
8
|
+
|
9
|
+
const useStyles = makeStyles({
|
10
|
+
list: {
|
11
|
+
rowGap: 0
|
12
|
+
},
|
13
|
+
listItem: {
|
14
|
+
padding: tokens.spacingVerticalS,
|
15
|
+
':hover': {
|
16
|
+
backgroundColor: tokens.colorNeutralBackground1Hover
|
17
|
+
}
|
18
|
+
},
|
19
|
+
listItemSelected: {
|
20
|
+
backgroundColor: tokens.colorNeutralBackground1Selected
|
21
|
+
},
|
22
|
+
media: {
|
23
|
+
width: '32px',
|
24
|
+
fontSize: tokens.fontSizeBase600,
|
25
|
+
display: 'flex',
|
26
|
+
flexDirection: 'column',
|
27
|
+
justifyContent: 'center'
|
28
|
+
},
|
29
|
+
image: {
|
30
|
+
width: tokens.lineHeightBase600,
|
31
|
+
height: tokens.lineHeightBase600,
|
32
|
+
backgroundPosition: 'center center',
|
33
|
+
backgroundSize: 'cover',
|
34
|
+
borderRadius: tokens.borderRadiusCircular,
|
35
|
+
border: `1px solid ${tokens.colorNeutralStroke1}`
|
36
|
+
},
|
37
|
+
listItemBody: {
|
38
|
+
rowGap: 0,
|
39
|
+
width: 'calc(100% - 44px)'
|
40
|
+
},
|
41
|
+
listItemHeader: mixins.ellipsis,
|
42
|
+
listItemContent: {
|
43
|
+
...mixins.ellipsis,
|
44
|
+
fontSize: tokens.fontSizeBase200
|
45
|
+
},
|
46
|
+
listItemMedia: {
|
47
|
+
...mixins.ellipsis,
|
48
|
+
maxWidth: '20%',
|
49
|
+
'& svg': {
|
50
|
+
height: tokens.fontSizeBase300
|
51
|
+
},
|
52
|
+
'& button': {
|
53
|
+
padding: 0,
|
54
|
+
minWidth: 0,
|
55
|
+
minHeight: 0,
|
56
|
+
height: '14px'
|
57
|
+
}
|
58
|
+
},
|
59
|
+
listItemMediaNoTrim: {
|
60
|
+
overflow: 'visible',
|
61
|
+
maxWidth: 'fit-content'
|
62
|
+
},
|
63
|
+
listItemMultilineContent: {
|
64
|
+
whiteSpace: 'pre-line'
|
65
|
+
}
|
66
|
+
});
|
67
|
+
|
68
|
+
export interface iListItem {
|
69
|
+
key: string | number;
|
70
|
+
media?: JSX.Element | string;
|
71
|
+
header: string;
|
72
|
+
headerMedia?: JSX.Element | string;
|
73
|
+
content?: string | JSX.Element | (string | JSX.Element)[];
|
74
|
+
onClickOnMedia?: boolean;
|
75
|
+
onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
76
|
+
selected?: boolean;
|
77
|
+
}
|
78
|
+
interface IProps {
|
79
|
+
selectable?: boolean;
|
80
|
+
items: iListItem[];
|
81
|
+
showAllHeaderMedia?: boolean;
|
82
|
+
/** allow multiline content */
|
83
|
+
multiline?: boolean;
|
84
|
+
dark?: boolean;
|
85
|
+
}
|
86
|
+
|
87
|
+
export const ListEx = (props: IProps) => {
|
88
|
+
|
89
|
+
const cssNames = useStyles();
|
90
|
+
|
91
|
+
const listItemElm = (item: iListItem) => <Horizontal key={item.key} css={[cssNames.listItem, item.selected && cssNames.listItemSelected]} onClick={item.onClick}>
|
92
|
+
{item.media && <Section css={[cssNames.media]} onClick={(e) => {
|
93
|
+
if (!item.onClickOnMedia)
|
94
|
+
e.stopPropagation();//media may have its on onclick
|
95
|
+
}}>{
|
96
|
+
isString(item.media)
|
97
|
+
? <div className={cssNames.image} style={{ backgroundImage: `url('${encodeURI(item.media)}'), url('${props.dark ? LOGO_WHITE_SQUARE : LOGO_BLUE_SQUARE}')` }}></div>
|
98
|
+
: item.media
|
99
|
+
}</Section>}
|
100
|
+
<Vertical main css={[cssNames.listItemBody]}>
|
101
|
+
<Horizontal main>
|
102
|
+
<Section main css={[cssNames.listItemHeader]}>{item.header}</Section>
|
103
|
+
{item.headerMedia && <Section onClick={(e) => {
|
104
|
+
e.stopPropagation();//media may have its on onclick
|
105
|
+
}} css={[cssNames.listItemMedia, props.showAllHeaderMedia && cssNames.listItemMediaNoTrim]}>{item.headerMedia}</Section>}
|
106
|
+
</Horizontal>
|
107
|
+
{!isNullOrUndefined(item.content)
|
108
|
+
? (Array.isArray(item.content) ? item.content : [item.content]).map((c, idx) => isNullOrUndefined(c) ? undefined : <Section key={idx} css={[cssNames.listItemContent, props.multiline ? cssNames.listItemMultilineContent : undefined]}>{c}</Section>)
|
109
|
+
: undefined}
|
110
|
+
</Vertical>
|
111
|
+
</Horizontal>;
|
112
|
+
|
113
|
+
return (
|
114
|
+
<Vertical css={[cssNames.list, KnownClassNames.list]}>
|
115
|
+
{props.items.map(item => listItemElm(item))}
|
116
|
+
</Vertical>
|
117
|
+
);
|
118
118
|
}
|
package/src/controls/loading.tsx
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
import { LOGO_ANIM_SMALL } from '@kwiz/common';
|
2
|
-
import { Centered } from './centered';
|
3
|
-
import React from 'react';
|
4
|
-
|
5
|
-
interface IProps {
|
6
|
-
}
|
7
|
-
export const Loading: React.FunctionComponent<IProps> = (props) => {
|
8
|
-
return (
|
9
|
-
<Centered><img src={LOGO_ANIM_SMALL} alt="loading" style={{ width: '15vw' }} /></Centered>
|
10
|
-
);
|
1
|
+
import { LOGO_ANIM_SMALL } from '@kwiz/common';
|
2
|
+
import { Centered } from './centered';
|
3
|
+
import React from 'react';
|
4
|
+
|
5
|
+
interface IProps {
|
6
|
+
}
|
7
|
+
export const Loading: React.FunctionComponent<IProps> = (props) => {
|
8
|
+
return (
|
9
|
+
<Centered><img src={LOGO_ANIM_SMALL} alt="loading" style={{ width: '15vw' }} /></Centered>
|
10
|
+
);
|
11
11
|
}
|
@@ -1,33 +1,33 @@
|
|
1
|
-
import { Field, ProgressBar } from '@fluentui/react-components';
|
2
|
-
import { isFunction } from '@kwiz/common';
|
3
|
-
import React from 'react';
|
4
|
-
import { IPrompterProps, Prompter } from './prompt';
|
5
|
-
|
6
|
-
interface IProps {
|
7
|
-
step?: number; max?: number;
|
8
|
-
/** do not wrap in a dialog */
|
9
|
-
contentOnly?: boolean;
|
10
|
-
cancelText?: string;
|
11
|
-
onCancel?: () => void;
|
12
|
-
label?: string;
|
13
|
-
}
|
14
|
-
export const PleaseWait: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
15
|
-
const field = <Field validationMessage={props.label || "please wait..."} validationState="none">
|
16
|
-
<ProgressBar value={props.step} max={props.max} />
|
17
|
-
</Field>;
|
18
|
-
return (props.contentOnly
|
19
|
-
? field
|
20
|
-
: <Prompter hideOk
|
21
|
-
hideCancel={!isFunction(props.onCancel)}
|
22
|
-
cancelButtonText={props.cancelText || 'cancel'}
|
23
|
-
onCancel={props.onCancel}>{field}</Prompter>
|
24
|
-
);
|
25
|
-
}
|
26
|
-
|
27
|
-
export const PleaseWaitPrompt = (props: { message: string; step?: number; max?: number; }): IPrompterProps => ({
|
28
|
-
//title: 'please wait...',
|
29
|
-
hideOk: true, hideCancel: true,
|
30
|
-
children: <Field validationMessage={props.message} validationState="none">
|
31
|
-
<ProgressBar value={props.step} max={props.max} />
|
32
|
-
</Field>
|
1
|
+
import { Field, ProgressBar } from '@fluentui/react-components';
|
2
|
+
import { isFunction } from '@kwiz/common';
|
3
|
+
import React from 'react';
|
4
|
+
import { IPrompterProps, Prompter } from './prompt';
|
5
|
+
|
6
|
+
interface IProps {
|
7
|
+
step?: number; max?: number;
|
8
|
+
/** do not wrap in a dialog */
|
9
|
+
contentOnly?: boolean;
|
10
|
+
cancelText?: string;
|
11
|
+
onCancel?: () => void;
|
12
|
+
label?: string;
|
13
|
+
}
|
14
|
+
export const PleaseWait: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
15
|
+
const field = <Field validationMessage={props.label || "please wait..."} validationState="none">
|
16
|
+
<ProgressBar value={props.step} max={props.max} />
|
17
|
+
</Field>;
|
18
|
+
return (props.contentOnly
|
19
|
+
? field
|
20
|
+
: <Prompter hideOk
|
21
|
+
hideCancel={!isFunction(props.onCancel)}
|
22
|
+
cancelButtonText={props.cancelText || 'cancel'}
|
23
|
+
onCancel={props.onCancel}>{field}</Prompter>
|
24
|
+
);
|
25
|
+
}
|
26
|
+
|
27
|
+
export const PleaseWaitPrompt = (props: { message: string; step?: number; max?: number; }): IPrompterProps => ({
|
28
|
+
//title: 'please wait...',
|
29
|
+
hideOk: true, hideCancel: true,
|
30
|
+
children: <Field validationMessage={props.message} validationState="none">
|
31
|
+
<ProgressBar value={props.step} max={props.max} />
|
32
|
+
</Field>
|
33
33
|
});
|
package/src/controls/prompt.tsx
CHANGED
@@ -1,97 +1,97 @@
|
|
1
|
-
import { Dialog, DialogActions, DialogBody, DialogContent, DialogModalType, DialogSurface, DialogTitle, DialogTrigger } from '@fluentui/react-components';
|
2
|
-
import { DismissRegular } from '@fluentui/react-icons';
|
3
|
-
import { isNotEmptyArray, isNullOrEmptyString } from '@kwiz/common';
|
4
|
-
import React from 'react';
|
5
|
-
import { useKWIZFluentContext } from '../helpers/context';
|
6
|
-
import { useKeyDown } from '../helpers/hooks';
|
7
|
-
import { ButtonEX, ButtonEXProps, ButtonEXSecondary } from './button';
|
8
|
-
|
9
|
-
export interface IPrompterProps {
|
10
|
-
hideOk?: boolean;
|
11
|
-
hideCancel?: boolean;
|
12
|
-
showCancelInTitle?: boolean;
|
13
|
-
/** return false to prevent closing the dialog. */
|
14
|
-
onOK?: () => Promise<void> | void;
|
15
|
-
onCancel?: () => void;
|
16
|
-
okButtonText?: string;
|
17
|
-
cancelButtonText?: string;
|
18
|
-
title?: string | JSX.Element;
|
19
|
-
okButtonProps?: Partial<ButtonEXProps>;
|
20
|
-
cancelButtonProps?: Partial<ButtonEXProps>;
|
21
|
-
children?: JSX.Element;
|
22
|
-
|
23
|
-
/** allow to epand the dialog to be wider */
|
24
|
-
maxWidth?: number | string;
|
25
|
-
|
26
|
-
/** additional button actions at the bottom */
|
27
|
-
actions?: JSX.Element[];
|
28
|
-
|
29
|
-
/** dialog title actions */
|
30
|
-
titleActions?: JSX.Element[];
|
31
|
-
/** specify a specific mount node for this dialog */
|
32
|
-
mountNode?: HTMLElement | null | {
|
33
|
-
element?: HTMLElement | null;
|
34
|
-
className?: string;
|
35
|
-
}
|
36
|
-
|
37
|
-
modalType?: DialogModalType;
|
38
|
-
/** do not fire ok/cancel on esc/enter press */
|
39
|
-
disableKeyboardActions?: boolean;
|
40
|
-
}
|
41
|
-
export const Prompter = React.forwardRef<HTMLDivElement, (IPrompterProps)>((props, ref) => {
|
42
|
-
const ctx = useKWIZFluentContext();
|
43
|
-
const disableKeyboardActions = React.useRef(props.disableKeyboardActions);
|
44
|
-
disableKeyboardActions.current = props.disableKeyboardActions;
|
45
|
-
|
46
|
-
let okProps: ButtonEXProps = {
|
47
|
-
...(props.okButtonProps as any || {}),
|
48
|
-
onClick: () => props.onOK(),
|
49
|
-
title: props.okButtonText || 'yes'
|
50
|
-
};
|
51
|
-
let cancelProps: ButtonEXProps = {
|
52
|
-
...(props.cancelButtonProps as any || {}),
|
53
|
-
onClick: () => props.onCancel(),
|
54
|
-
title: props.cancelButtonText || 'no'
|
55
|
-
};
|
56
|
-
|
57
|
-
useKeyDown({
|
58
|
-
onEnter: () => !disableKeyboardActions.current && props.onOK(),
|
59
|
-
onEscape: () => !disableKeyboardActions.current && props.onCancel(),
|
60
|
-
});
|
61
|
-
|
62
|
-
const actions: JSX.Element[] = [];
|
63
|
-
if (!props.hideOk) actions.push(<DialogTrigger key='ok' disableButtonEnhancement>
|
64
|
-
<ButtonEXSecondary {...okProps} />
|
65
|
-
</DialogTrigger>);
|
66
|
-
if (!props.hideCancel) actions.push(<DialogTrigger key='cancel' disableButtonEnhancement>
|
67
|
-
<ButtonEXSecondary {...cancelProps} />
|
68
|
-
</DialogTrigger>);
|
69
|
-
if (isNotEmptyArray(props.actions))
|
70
|
-
actions.push(...props.actions);
|
71
|
-
|
72
|
-
const titleActions: JSX.Element[] = props.titleActions ? [...props.titleActions] : [];
|
73
|
-
if (props.showCancelInTitle)
|
74
|
-
titleActions.push(<DialogTrigger key='cancel' disableButtonEnhancement>
|
75
|
-
<ButtonEX {...cancelProps} icon={<DismissRegular />} />
|
76
|
-
</DialogTrigger>);
|
77
|
-
|
78
|
-
|
79
|
-
return (
|
80
|
-
<Dialog open modalType={props.modalType}>
|
81
|
-
<DialogSurface mountNode={props.mountNode || ctx.mountNode}
|
82
|
-
style={!isNullOrEmptyString(props.maxWidth) ? { maxWidth: props.maxWidth } : undefined}>
|
83
|
-
<DialogBody>
|
84
|
-
{(!isNullOrEmptyString(props.title) || isNotEmptyArray(titleActions)) && <DialogTitle
|
85
|
-
action={titleActions}
|
86
|
-
>{props.title}</DialogTitle>}
|
87
|
-
<DialogContent ref={ref}>
|
88
|
-
{props.children}
|
89
|
-
</DialogContent>
|
90
|
-
{isNotEmptyArray(actions) && <DialogActions fluid={actions.length > 2}>
|
91
|
-
{actions}
|
92
|
-
</DialogActions>}
|
93
|
-
</DialogBody>
|
94
|
-
</DialogSurface>
|
95
|
-
</Dialog>
|
96
|
-
);
|
1
|
+
import { Dialog, DialogActions, DialogBody, DialogContent, DialogModalType, DialogSurface, DialogTitle, DialogTrigger } from '@fluentui/react-components';
|
2
|
+
import { DismissRegular } from '@fluentui/react-icons';
|
3
|
+
import { isNotEmptyArray, isNullOrEmptyString } from '@kwiz/common';
|
4
|
+
import React from 'react';
|
5
|
+
import { useKWIZFluentContext } from '../helpers/context';
|
6
|
+
import { useKeyDown } from '../helpers/hooks';
|
7
|
+
import { ButtonEX, ButtonEXProps, ButtonEXSecondary } from './button';
|
8
|
+
|
9
|
+
export interface IPrompterProps {
|
10
|
+
hideOk?: boolean;
|
11
|
+
hideCancel?: boolean;
|
12
|
+
showCancelInTitle?: boolean;
|
13
|
+
/** return false to prevent closing the dialog. */
|
14
|
+
onOK?: () => Promise<void> | void;
|
15
|
+
onCancel?: () => void;
|
16
|
+
okButtonText?: string;
|
17
|
+
cancelButtonText?: string;
|
18
|
+
title?: string | JSX.Element;
|
19
|
+
okButtonProps?: Partial<ButtonEXProps>;
|
20
|
+
cancelButtonProps?: Partial<ButtonEXProps>;
|
21
|
+
children?: JSX.Element;
|
22
|
+
|
23
|
+
/** allow to epand the dialog to be wider */
|
24
|
+
maxWidth?: number | string;
|
25
|
+
|
26
|
+
/** additional button actions at the bottom */
|
27
|
+
actions?: JSX.Element[];
|
28
|
+
|
29
|
+
/** dialog title actions */
|
30
|
+
titleActions?: JSX.Element[];
|
31
|
+
/** specify a specific mount node for this dialog */
|
32
|
+
mountNode?: HTMLElement | null | {
|
33
|
+
element?: HTMLElement | null;
|
34
|
+
className?: string;
|
35
|
+
}
|
36
|
+
|
37
|
+
modalType?: DialogModalType;
|
38
|
+
/** do not fire ok/cancel on esc/enter press */
|
39
|
+
disableKeyboardActions?: boolean;
|
40
|
+
}
|
41
|
+
export const Prompter = React.forwardRef<HTMLDivElement, (IPrompterProps)>((props, ref) => {
|
42
|
+
const ctx = useKWIZFluentContext();
|
43
|
+
const disableKeyboardActions = React.useRef(props.disableKeyboardActions);
|
44
|
+
disableKeyboardActions.current = props.disableKeyboardActions;
|
45
|
+
|
46
|
+
let okProps: ButtonEXProps = {
|
47
|
+
...(props.okButtonProps as any || {}),
|
48
|
+
onClick: () => props.onOK(),
|
49
|
+
title: props.okButtonText || 'yes'
|
50
|
+
};
|
51
|
+
let cancelProps: ButtonEXProps = {
|
52
|
+
...(props.cancelButtonProps as any || {}),
|
53
|
+
onClick: () => props.onCancel(),
|
54
|
+
title: props.cancelButtonText || 'no'
|
55
|
+
};
|
56
|
+
|
57
|
+
useKeyDown({
|
58
|
+
onEnter: () => !disableKeyboardActions.current && props.onOK(),
|
59
|
+
onEscape: () => !disableKeyboardActions.current && props.onCancel(),
|
60
|
+
});
|
61
|
+
|
62
|
+
const actions: JSX.Element[] = [];
|
63
|
+
if (!props.hideOk) actions.push(<DialogTrigger key='ok' disableButtonEnhancement>
|
64
|
+
<ButtonEXSecondary {...okProps} />
|
65
|
+
</DialogTrigger>);
|
66
|
+
if (!props.hideCancel) actions.push(<DialogTrigger key='cancel' disableButtonEnhancement>
|
67
|
+
<ButtonEXSecondary {...cancelProps} />
|
68
|
+
</DialogTrigger>);
|
69
|
+
if (isNotEmptyArray(props.actions))
|
70
|
+
actions.push(...props.actions);
|
71
|
+
|
72
|
+
const titleActions: JSX.Element[] = props.titleActions ? [...props.titleActions] : [];
|
73
|
+
if (props.showCancelInTitle)
|
74
|
+
titleActions.push(<DialogTrigger key='cancel' disableButtonEnhancement>
|
75
|
+
<ButtonEX {...cancelProps} icon={<DismissRegular />} />
|
76
|
+
</DialogTrigger>);
|
77
|
+
|
78
|
+
|
79
|
+
return (
|
80
|
+
<Dialog open modalType={props.modalType}>
|
81
|
+
<DialogSurface mountNode={props.mountNode || ctx.mountNode}
|
82
|
+
style={!isNullOrEmptyString(props.maxWidth) ? { maxWidth: props.maxWidth } : undefined}>
|
83
|
+
<DialogBody>
|
84
|
+
{(!isNullOrEmptyString(props.title) || isNotEmptyArray(titleActions)) && <DialogTitle
|
85
|
+
action={titleActions}
|
86
|
+
>{props.title}</DialogTitle>}
|
87
|
+
<DialogContent ref={ref}>
|
88
|
+
{props.children}
|
89
|
+
</DialogContent>
|
90
|
+
{isNotEmptyArray(actions) && <DialogActions fluid={actions.length > 2}>
|
91
|
+
{actions}
|
92
|
+
</DialogActions>}
|
93
|
+
</DialogBody>
|
94
|
+
</DialogSurface>
|
95
|
+
</Dialog>
|
96
|
+
);
|
97
97
|
});
|
package/src/controls/search.tsx
CHANGED
@@ -1,66 +1,66 @@
|
|
1
|
-
import { Input, InputProps, makeStyles } from '@fluentui/react-components';
|
2
|
-
import { DismissRegular, SearchRegular } from "@fluentui/react-icons";
|
3
|
-
import { debounce, isFunction, isNullOrEmptyString } from '@kwiz/common';
|
4
|
-
import React, { useState } from 'react';
|
5
|
-
import { GetLogger } from '../_modules/config';
|
6
|
-
import { useStateEX } from '../helpers/hooks';
|
7
|
-
import { mixins } from '../styles/styles';
|
8
|
-
const logger = GetLogger("Search");
|
9
|
-
|
10
|
-
const useStyles = makeStyles({
|
11
|
-
main: mixins.main,
|
12
|
-
clickable: mixins.clickable,
|
13
|
-
})
|
14
|
-
|
15
|
-
interface IProps extends InputProps {
|
16
|
-
main?: boolean;
|
17
|
-
delay?: number;
|
18
|
-
/** if changing the value in the caller - change this prop to reset */
|
19
|
-
resetValue?: string;
|
20
|
-
onChangeDeferred?: (newValue: string) => void;
|
21
|
-
onChangeSync?: (newValue: string) => void;
|
22
|
-
}
|
23
|
-
|
24
|
-
/** value is set on first load. to change the value after it was first set - change the compoenet's key. */
|
25
|
-
export const Search: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
26
|
-
const cssNames = useStyles();
|
27
|
-
|
28
|
-
const [resetKey, setResetKey] = useState(1);
|
29
|
-
|
30
|
-
let delay = props.delay || 1;
|
31
|
-
|
32
|
-
//cannot call debounce every render, since it won't be the same debounced instance...
|
33
|
-
var notifyParent = React.useMemo(() => debounce(v => {
|
34
|
-
logger.log(`Set: ${v}`);
|
35
|
-
props.onChangeDeferred(v);
|
36
|
-
}, delay * 1000), [delay]);
|
37
|
-
|
38
|
-
let [value, setValue] = useStateEX(props.value, {
|
39
|
-
onChange: newValue => {
|
40
|
-
if (isFunction(props.onChangeSync)) props.onChangeSync(newValue as string);
|
41
|
-
if (isFunction(props.onChangeDeferred)) notifyParent(newValue);
|
42
|
-
return newValue;
|
43
|
-
}
|
44
|
-
});
|
45
|
-
|
46
|
-
//once props change, reset this control value to match
|
47
|
-
React.useEffect(() => {
|
48
|
-
setValue(props.resetValue);
|
49
|
-
//todo: bug: setting value does not sync into the text box
|
50
|
-
setResetKey(resetKey + 1)
|
51
|
-
}, [props.resetValue]);
|
52
|
-
|
53
|
-
return (
|
54
|
-
<Input key={resetKey} {...props} value={value} onChange={(e, data) => setValue(data.value)}
|
55
|
-
className={props.main ? cssNames.main : undefined}
|
56
|
-
contentBefore={!isNullOrEmptyString(value) ? undefined : <SearchRegular />}
|
57
|
-
contentAfter={isNullOrEmptyString(value)
|
58
|
-
? undefined
|
59
|
-
: <DismissRegular className={cssNames.clickable} onClick={() => {
|
60
|
-
setValue("");
|
61
|
-
//todo: bug: setting value does not sync into the text box
|
62
|
-
setResetKey(resetKey + 1)
|
63
|
-
}} />
|
64
|
-
} />
|
65
|
-
);
|
1
|
+
import { Input, InputProps, makeStyles } from '@fluentui/react-components';
|
2
|
+
import { DismissRegular, SearchRegular } from "@fluentui/react-icons";
|
3
|
+
import { debounce, isFunction, isNullOrEmptyString } from '@kwiz/common';
|
4
|
+
import React, { useState } from 'react';
|
5
|
+
import { GetLogger } from '../_modules/config';
|
6
|
+
import { useStateEX } from '../helpers/hooks';
|
7
|
+
import { mixins } from '../styles/styles';
|
8
|
+
const logger = GetLogger("Search");
|
9
|
+
|
10
|
+
const useStyles = makeStyles({
|
11
|
+
main: mixins.main,
|
12
|
+
clickable: mixins.clickable,
|
13
|
+
})
|
14
|
+
|
15
|
+
interface IProps extends InputProps {
|
16
|
+
main?: boolean;
|
17
|
+
delay?: number;
|
18
|
+
/** if changing the value in the caller - change this prop to reset */
|
19
|
+
resetValue?: string;
|
20
|
+
onChangeDeferred?: (newValue: string) => void;
|
21
|
+
onChangeSync?: (newValue: string) => void;
|
22
|
+
}
|
23
|
+
|
24
|
+
/** value is set on first load. to change the value after it was first set - change the compoenet's key. */
|
25
|
+
export const Search: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
26
|
+
const cssNames = useStyles();
|
27
|
+
|
28
|
+
const [resetKey, setResetKey] = useState(1);
|
29
|
+
|
30
|
+
let delay = props.delay || 1;
|
31
|
+
|
32
|
+
//cannot call debounce every render, since it won't be the same debounced instance...
|
33
|
+
var notifyParent = React.useMemo(() => debounce(v => {
|
34
|
+
logger.log(`Set: ${v}`);
|
35
|
+
props.onChangeDeferred(v);
|
36
|
+
}, delay * 1000), [delay]);
|
37
|
+
|
38
|
+
let [value, setValue] = useStateEX(props.value, {
|
39
|
+
onChange: newValue => {
|
40
|
+
if (isFunction(props.onChangeSync)) props.onChangeSync(newValue as string);
|
41
|
+
if (isFunction(props.onChangeDeferred)) notifyParent(newValue);
|
42
|
+
return newValue;
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
//once props change, reset this control value to match
|
47
|
+
React.useEffect(() => {
|
48
|
+
setValue(props.resetValue);
|
49
|
+
//todo: bug: setting value does not sync into the text box
|
50
|
+
setResetKey(resetKey + 1)
|
51
|
+
}, [props.resetValue]);
|
52
|
+
|
53
|
+
return (
|
54
|
+
<Input key={resetKey} {...props} value={value} onChange={(e, data) => setValue(data.value)}
|
55
|
+
className={props.main ? cssNames.main : undefined}
|
56
|
+
contentBefore={!isNullOrEmptyString(value) ? undefined : <SearchRegular />}
|
57
|
+
contentAfter={isNullOrEmptyString(value)
|
58
|
+
? undefined
|
59
|
+
: <DismissRegular className={cssNames.clickable} onClick={() => {
|
60
|
+
setValue("");
|
61
|
+
//todo: bug: setting value does not sync into the text box
|
62
|
+
setResetKey(resetKey + 1)
|
63
|
+
}} />
|
64
|
+
} />
|
65
|
+
);
|
66
66
|
}
|