@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.
Files changed (134) hide show
  1. package/.github/workflows/npm-publish.yml +34 -0
  2. package/LICENSE +21 -21
  3. package/README.md +26 -26
  4. package/package.json +72 -72
  5. package/src/_modules/config.ts +9 -9
  6. package/src/_modules/constants.ts +3 -3
  7. package/src/controls/accordion.tsx +48 -48
  8. package/src/controls/button.tsx +169 -169
  9. package/src/controls/centered.tsx +22 -22
  10. package/src/controls/date.tsx +39 -39
  11. package/src/controls/dropdown.tsx +51 -51
  12. package/src/controls/error-boundary.tsx +41 -41
  13. package/src/controls/field-editor.tsx +40 -40
  14. package/src/controls/file-upload.tsx +67 -67
  15. package/src/controls/horizontal.tsx +34 -34
  16. package/src/controls/input.tsx +60 -60
  17. package/src/controls/kwizoverflow.tsx +103 -103
  18. package/src/controls/list.tsx +117 -117
  19. package/src/controls/loading.tsx +10 -10
  20. package/src/controls/please-wait.tsx +32 -32
  21. package/src/controls/prompt.tsx +96 -96
  22. package/src/controls/search.tsx +65 -65
  23. package/src/controls/section.tsx +51 -51
  24. package/src/controls/svg.tsx +120 -120
  25. package/src/controls/toolbar.tsx +48 -48
  26. package/src/controls/vertical-content.tsx +49 -49
  27. package/src/controls/vertical.tsx +34 -34
  28. package/src/helpers/context.ts +39 -39
  29. package/src/helpers/hooks.tsx +335 -335
  30. package/src/index.ts +26 -26
  31. package/src/styles/styles.ts +87 -87
  32. package/src/styles/theme.ts +90 -90
  33. package/dist/_modules/build.d.ts +0 -2
  34. package/dist/_modules/build.js +0 -3
  35. package/dist/_modules/build.js.map +0 -1
  36. package/dist/_modules/config.d.ts +0 -1
  37. package/dist/_modules/config.js +0 -9
  38. package/dist/_modules/config.js.map +0 -1
  39. package/dist/_modules/constants.d.ts +0 -2
  40. package/dist/_modules/constants.js +0 -3
  41. package/dist/_modules/constants.js.map +0 -1
  42. package/dist/_modules/exports-index.d.ts +0 -1
  43. package/dist/_modules/exports-index.js +0 -2
  44. package/dist/_modules/exports-index.js.map +0 -1
  45. package/dist/controls/accordion.d.ts +0 -13
  46. package/dist/controls/accordion.js +0 -27
  47. package/dist/controls/accordion.js.map +0 -1
  48. package/dist/controls/button.d.ts +0 -28
  49. package/dist/controls/button.js +0 -113
  50. package/dist/controls/button.js.map +0 -1
  51. package/dist/controls/centered.d.ts +0 -5
  52. package/dist/controls/centered.js +0 -14
  53. package/dist/controls/centered.js.map +0 -1
  54. package/dist/controls/date.d.ts +0 -8
  55. package/dist/controls/date.js +0 -32
  56. package/dist/controls/date.js.map +0 -1
  57. package/dist/controls/dropdown.d.ts +0 -29
  58. package/dist/controls/dropdown.js +0 -27
  59. package/dist/controls/dropdown.js.map +0 -1
  60. package/dist/controls/error-boundary.d.ts +0 -23
  61. package/dist/controls/error-boundary.js +0 -33
  62. package/dist/controls/error-boundary.js.map +0 -1
  63. package/dist/controls/exports-index.d.ts +0 -17
  64. package/dist/controls/exports-index.js +0 -18
  65. package/dist/controls/exports-index.js.map +0 -1
  66. package/dist/controls/field-editor.d.ts +0 -13
  67. package/dist/controls/field-editor.js +0 -15
  68. package/dist/controls/field-editor.js.map +0 -1
  69. package/dist/controls/file-upload.d.ts +0 -18
  70. package/dist/controls/file-upload.js +0 -41
  71. package/dist/controls/file-upload.js.map +0 -1
  72. package/dist/controls/horizontal.d.ts +0 -8
  73. package/dist/controls/horizontal.js +0 -23
  74. package/dist/controls/horizontal.js.map +0 -1
  75. package/dist/controls/input.d.ts +0 -13
  76. package/dist/controls/input.js +0 -43
  77. package/dist/controls/input.js.map +0 -1
  78. package/dist/controls/kwizoverflow.d.ts +0 -14
  79. package/dist/controls/kwizoverflow.js +0 -45
  80. package/dist/controls/kwizoverflow.js.map +0 -1
  81. package/dist/controls/list.d.ts +0 -21
  82. package/dist/controls/list.js +0 -72
  83. package/dist/controls/list.js.map +0 -1
  84. package/dist/controls/loading copy.d.ts +0 -5
  85. package/dist/controls/loading copy.js +0 -7
  86. package/dist/controls/loading copy.js.map +0 -1
  87. package/dist/controls/loading.d.ts +0 -5
  88. package/dist/controls/loading.js +0 -7
  89. package/dist/controls/loading.js.map +0 -1
  90. package/dist/controls/please-wait.d.ts +0 -18
  91. package/dist/controls/please-wait.js +0 -16
  92. package/dist/controls/please-wait.js.map +0 -1
  93. package/dist/controls/prompt.d.ts +0 -32
  94. package/dist/controls/prompt.js +0 -31
  95. package/dist/controls/prompt.js.map +0 -1
  96. package/dist/controls/search.d.ts +0 -13
  97. package/dist/controls/search.js +0 -47
  98. package/dist/controls/search.js.map +0 -1
  99. package/dist/controls/section.d.ts +0 -14
  100. package/dist/controls/section.js +0 -27
  101. package/dist/controls/section.js.map +0 -1
  102. package/dist/controls/svg.d.ts +0 -23
  103. package/dist/controls/svg.js +0 -45
  104. package/dist/controls/svg.js.map +0 -1
  105. package/dist/controls/toolbar.d.ts +0 -12
  106. package/dist/controls/toolbar.js +0 -23
  107. package/dist/controls/toolbar.js.map +0 -1
  108. package/dist/controls/vertical-content.d.ts +0 -6
  109. package/dist/controls/vertical-content.js +0 -37
  110. package/dist/controls/vertical-content.js.map +0 -1
  111. package/dist/controls/vertical.d.ts +0 -8
  112. package/dist/controls/vertical.js +0 -23
  113. package/dist/controls/vertical.js.map +0 -1
  114. package/dist/exports-index.d.ts +0 -3
  115. package/dist/exports-index.js +0 -4
  116. package/dist/exports-index.js.map +0 -1
  117. package/dist/helpers/context.d.ts +0 -26
  118. package/dist/helpers/context.js +0 -15
  119. package/dist/helpers/context.js.map +0 -1
  120. package/dist/helpers/hooks.d.ts +0 -62
  121. package/dist/helpers/hooks.js +0 -287
  122. package/dist/helpers/hooks.js.map +0 -1
  123. package/dist/index.d.ts +0 -25
  124. package/dist/index.js +0 -25
  125. package/dist/index.js.map +0 -1
  126. package/dist/styles/exports-index.d.ts +0 -2
  127. package/dist/styles/exports-index.js +0 -3
  128. package/dist/styles/exports-index.js.map +0 -1
  129. package/dist/styles/styles.d.ts +0 -19
  130. package/dist/styles/styles.js +0 -79
  131. package/dist/styles/styles.js.map +0 -1
  132. package/dist/styles/theme.d.ts +0 -6
  133. package/dist/styles/theme.js +0 -77
  134. package/dist/styles/theme.js.map +0 -1
@@ -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
  }
@@ -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
  });
@@ -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
  });
@@ -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
  }