@kwiz/fluentui 1.0.73 → 1.0.75
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 +24 -24
- package/LICENSE +21 -21
- package/README.md +53 -53
- package/dist/@types/forwardRef.d.ts +0 -0
- package/dist/@types/forwardRef.js +1 -0
- package/dist/@types/forwardRef.js.map +1 -0
- package/dist/controls/error-boundary copy.d.ts +23 -0
- package/dist/controls/error-boundary copy.js +33 -0
- package/dist/controls/error-boundary copy.js.map +1 -0
- package/dist/controls/menu.js +2 -2
- package/dist/controls/menu.js.map +1 -1
- package/dist/controls/search.js +19 -11
- package/dist/controls/search.js.map +1 -1
- package/dist/controls/svg.js +21 -21
- package/dist/controls/svg.js.map +1 -1
- package/dist/helpers/common.d.ts +4 -0
- package/dist/helpers/common.js +2 -0
- package/dist/helpers/common.js.map +1 -0
- package/dist/helpers/context.d.ts +26 -0
- package/dist/helpers/context.js +15 -0
- package/dist/helpers/context.js.map +1 -0
- package/dist/helpers/drag-drop/exports.d.ts +12 -0
- package/dist/helpers/drag-drop/exports.js +3 -0
- package/dist/helpers/drag-drop/exports.js.map +1 -0
- package/dist/helpers/exports.d.ts +7 -0
- package/dist/helpers/exports.js +8 -0
- package/dist/helpers/exports.js.map +1 -0
- package/dist/helpers/use-editable-control.d.ts +1 -1
- package/dist/helpers/use-editable-control.js.map +1 -1
- package/package.json +85 -84
- package/src/_modules/config.ts +9 -9
- package/src/_modules/constants.ts +3 -3
- package/src/controls/ColorPickerDialog.tsx +83 -83
- package/src/controls/accordion.tsx +62 -62
- package/src/controls/button.tsx +180 -180
- package/src/controls/canvas/CustomEventTargetBase.ts +32 -32
- package/src/controls/canvas/DrawPad.tsx +296 -296
- package/src/controls/canvas/DrawPadManager.ts +694 -694
- package/src/controls/canvas/bezier.ts +109 -109
- package/src/controls/canvas/point.ts +44 -44
- package/src/controls/card-list.tsx +31 -31
- package/src/controls/card.tsx +77 -77
- package/src/controls/centered.tsx +14 -14
- package/src/controls/date.tsx +87 -87
- package/src/controls/diagram-picker.tsx +96 -96
- package/src/controls/divider.tsx +15 -15
- package/src/controls/dropdown.tsx +66 -66
- package/src/controls/error-boundary.tsx +41 -41
- package/src/controls/field-editor.tsx +42 -42
- package/src/controls/file-upload.tsx +155 -155
- package/src/controls/horizontal.tsx +48 -48
- package/src/controls/html-editor/editor.tsx +182 -182
- package/src/controls/index.ts +33 -33
- package/src/controls/input.tsx +160 -160
- package/src/controls/kwizoverflow.tsx +106 -106
- package/src/controls/list.tsx +119 -119
- package/src/controls/loading.tsx +10 -10
- package/src/controls/menu.tsx +173 -173
- package/src/controls/merge-text.tsx +126 -126
- package/src/controls/please-wait.tsx +32 -32
- package/src/controls/progress-bar.tsx +109 -109
- package/src/controls/prompt.tsx +121 -121
- package/src/controls/qrcode.tsx +36 -36
- package/src/controls/search.tsx +71 -61
- package/src/controls/section.tsx +133 -133
- package/src/controls/svg.tsx +138 -138
- package/src/controls/toolbar.tsx +46 -46
- package/src/controls/vertical-content.tsx +49 -49
- package/src/controls/vertical.tsx +42 -42
- package/src/helpers/block-nav.tsx +88 -88
- package/src/helpers/context-const.ts +29 -29
- package/src/helpers/context-export.tsx +77 -77
- package/src/helpers/context-internal.ts +13 -13
- package/src/helpers/drag-drop/drag-drop-container.tsx +53 -53
- package/src/helpers/drag-drop/drag-drop-context-internal.tsx +9 -9
- package/src/helpers/drag-drop/drag-drop-context.tsx +61 -61
- package/src/helpers/drag-drop/drag-drop.types.ts +21 -21
- package/src/helpers/drag-drop/index.ts +12 -12
- package/src/helpers/drag-drop/readme.md +75 -75
- package/src/helpers/drag-drop/use-draggable.ts +47 -47
- package/src/helpers/drag-drop/use-droppable.ts +38 -38
- package/src/helpers/forwardRef.ts +7 -7
- package/src/helpers/hooks-events.ts +149 -149
- package/src/helpers/hooks.tsx +141 -141
- package/src/helpers/index.ts +8 -8
- package/src/helpers/use-alerts.tsx +74 -74
- package/src/helpers/use-editable-control.tsx +37 -37
- package/src/helpers/use-toast.tsx +29 -29
- package/src/index.ts +2 -2
- package/src/styles/index.ts +1 -1
- package/src/styles/styles.ts +104 -104
- package/src/styles/theme.ts +90 -90
package/src/controls/prompt.tsx
CHANGED
@@ -1,122 +1,122 @@
|
|
1
|
-
import { Dialog, DialogActions, DialogBody, DialogContent, DialogModalType, DialogSurface, DialogTitle, DialogTrigger, useId } from '@fluentui/react-components';
|
2
|
-
import { DismissRegular } from '@fluentui/react-icons';
|
3
|
-
import { isNotEmptyArray, isNullOrEmptyString, noops, PushNoDuplicate, RemoveItemFromArr, stopEvent } from '@kwiz/common';
|
4
|
-
import React from 'react';
|
5
|
-
import { useKWIZFluentContext } from '../helpers/context-internal';
|
6
|
-
import { useKeyDown } from '../helpers/hooks-events';
|
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
|
-
/** OK */
|
17
|
-
okButtonText?: string;
|
18
|
-
/** Cancel */
|
19
|
-
cancelButtonText?: string;
|
20
|
-
title?: string | JSX.Element;
|
21
|
-
okButtonProps?: Partial<ButtonEXProps>;
|
22
|
-
cancelButtonProps?: Partial<ButtonEXProps>;
|
23
|
-
children?: JSX.Element;
|
24
|
-
|
25
|
-
/** allow to epand the dialog to be wider */
|
26
|
-
maxWidth?: number | string;
|
27
|
-
|
28
|
-
/** additional button actions at the bottom */
|
29
|
-
actions?: JSX.Element[];
|
30
|
-
|
31
|
-
/** dialog title actions */
|
32
|
-
titleActions?: JSX.Element[];
|
33
|
-
/** specify a specific mount node for this dialog */
|
34
|
-
mountNode?: HTMLElement | null | {
|
35
|
-
element?: HTMLElement | null;
|
36
|
-
className?: string;
|
37
|
-
}
|
38
|
-
|
39
|
-
modalType?: DialogModalType;
|
40
|
-
/** do not fire ok/cancel on esc/enter press */
|
41
|
-
disableKeyboardActions?: boolean;
|
42
|
-
}
|
43
|
-
const dialogsOrder: string[] = [];
|
44
|
-
export const Prompter = React.forwardRef<HTMLDivElement, (IPrompterProps)>((props, ref) => {
|
45
|
-
const ctx = useKWIZFluentContext();
|
46
|
-
const disableKeyboardActions = React.useRef(props.disableKeyboardActions);
|
47
|
-
disableKeyboardActions.current = props.disableKeyboardActions;
|
48
|
-
|
49
|
-
const myId = useId();
|
50
|
-
React.useEffect(() => {
|
51
|
-
PushNoDuplicate(dialogsOrder, myId);
|
52
|
-
//cleanup
|
53
|
-
return () => RemoveItemFromArr(dialogsOrder, myId);
|
54
|
-
}, [myId]);
|
55
|
-
|
56
|
-
const onOK = props.onOK || noops;
|
57
|
-
const onCancel = props.onCancel || noops;
|
58
|
-
|
59
|
-
let okProps: ButtonEXProps = {
|
60
|
-
...(props.okButtonProps as any || {}),
|
61
|
-
onClick: () => onOK(),
|
62
|
-
title: props.okButtonText || 'OK'
|
63
|
-
};
|
64
|
-
let cancelProps: ButtonEXProps = {
|
65
|
-
...(props.cancelButtonProps as any || {}),
|
66
|
-
onClick: () => onCancel(),
|
67
|
-
title: props.cancelButtonText || 'Cancel'
|
68
|
-
};
|
69
|
-
|
70
|
-
useKeyDown({
|
71
|
-
onEnter: (e) => {
|
72
|
-
const topMost = dialogsOrder.indexOf(myId) === dialogsOrder.length - 1;
|
73
|
-
if (topMost && !disableKeyboardActions.current) {
|
74
|
-
stopEvent(e);
|
75
|
-
onOK();
|
76
|
-
}
|
77
|
-
},
|
78
|
-
onEscape: (e) => {
|
79
|
-
const topMost = dialogsOrder.indexOf(myId) === dialogsOrder.length - 1;
|
80
|
-
if (topMost && !disableKeyboardActions.current) {
|
81
|
-
stopEvent(e);
|
82
|
-
onCancel();
|
83
|
-
}
|
84
|
-
}
|
85
|
-
});
|
86
|
-
|
87
|
-
const actions: JSX.Element[] = [];
|
88
|
-
if (!props.hideOk) actions.push(<DialogTrigger key='ok' disableButtonEnhancement>
|
89
|
-
<ButtonEXSecondary {...okProps} />
|
90
|
-
</DialogTrigger>);
|
91
|
-
if (!props.hideCancel) actions.push(<DialogTrigger key='cancel' disableButtonEnhancement>
|
92
|
-
<ButtonEXSecondary {...cancelProps} />
|
93
|
-
</DialogTrigger>);
|
94
|
-
if (isNotEmptyArray(props.actions))
|
95
|
-
actions.push(...props.actions);
|
96
|
-
|
97
|
-
const titleActions: JSX.Element[] = props.titleActions ? [...props.titleActions] : [];
|
98
|
-
if (props.showCancelInTitle)
|
99
|
-
titleActions.push(<DialogTrigger key='cancel' disableButtonEnhancement>
|
100
|
-
<ButtonEX {...cancelProps} icon={<DismissRegular />} />
|
101
|
-
</DialogTrigger>);
|
102
|
-
|
103
|
-
|
104
|
-
return (
|
105
|
-
<Dialog open modalType={props.modalType}>
|
106
|
-
<DialogSurface mountNode={props.mountNode || ctx.mountNode}
|
107
|
-
style={!isNullOrEmptyString(props.maxWidth) ? { maxWidth: props.maxWidth } : undefined}>
|
108
|
-
<DialogBody>
|
109
|
-
{(!isNullOrEmptyString(props.title) || isNotEmptyArray(titleActions)) && <DialogTitle
|
110
|
-
action={titleActions}
|
111
|
-
>{props.title}</DialogTitle>}
|
112
|
-
<DialogContent ref={ref}>
|
113
|
-
{props.children}
|
114
|
-
</DialogContent>
|
115
|
-
{isNotEmptyArray(actions) && <DialogActions fluid={actions.length > 2}>
|
116
|
-
{actions}
|
117
|
-
</DialogActions>}
|
118
|
-
</DialogBody>
|
119
|
-
</DialogSurface>
|
120
|
-
</Dialog>
|
121
|
-
);
|
1
|
+
import { Dialog, DialogActions, DialogBody, DialogContent, DialogModalType, DialogSurface, DialogTitle, DialogTrigger, useId } from '@fluentui/react-components';
|
2
|
+
import { DismissRegular } from '@fluentui/react-icons';
|
3
|
+
import { isNotEmptyArray, isNullOrEmptyString, noops, PushNoDuplicate, RemoveItemFromArr, stopEvent } from '@kwiz/common';
|
4
|
+
import React from 'react';
|
5
|
+
import { useKWIZFluentContext } from '../helpers/context-internal';
|
6
|
+
import { useKeyDown } from '../helpers/hooks-events';
|
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
|
+
/** OK */
|
17
|
+
okButtonText?: string;
|
18
|
+
/** Cancel */
|
19
|
+
cancelButtonText?: string;
|
20
|
+
title?: string | JSX.Element;
|
21
|
+
okButtonProps?: Partial<ButtonEXProps>;
|
22
|
+
cancelButtonProps?: Partial<ButtonEXProps>;
|
23
|
+
children?: JSX.Element;
|
24
|
+
|
25
|
+
/** allow to epand the dialog to be wider */
|
26
|
+
maxWidth?: number | string;
|
27
|
+
|
28
|
+
/** additional button actions at the bottom */
|
29
|
+
actions?: JSX.Element[];
|
30
|
+
|
31
|
+
/** dialog title actions */
|
32
|
+
titleActions?: JSX.Element[];
|
33
|
+
/** specify a specific mount node for this dialog */
|
34
|
+
mountNode?: HTMLElement | null | {
|
35
|
+
element?: HTMLElement | null;
|
36
|
+
className?: string;
|
37
|
+
}
|
38
|
+
|
39
|
+
modalType?: DialogModalType;
|
40
|
+
/** do not fire ok/cancel on esc/enter press */
|
41
|
+
disableKeyboardActions?: boolean;
|
42
|
+
}
|
43
|
+
const dialogsOrder: string[] = [];
|
44
|
+
export const Prompter = React.forwardRef<HTMLDivElement, (IPrompterProps)>((props, ref) => {
|
45
|
+
const ctx = useKWIZFluentContext();
|
46
|
+
const disableKeyboardActions = React.useRef(props.disableKeyboardActions);
|
47
|
+
disableKeyboardActions.current = props.disableKeyboardActions;
|
48
|
+
|
49
|
+
const myId = useId();
|
50
|
+
React.useEffect(() => {
|
51
|
+
PushNoDuplicate(dialogsOrder, myId);
|
52
|
+
//cleanup
|
53
|
+
return () => RemoveItemFromArr(dialogsOrder, myId);
|
54
|
+
}, [myId]);
|
55
|
+
|
56
|
+
const onOK = props.onOK || noops;
|
57
|
+
const onCancel = props.onCancel || noops;
|
58
|
+
|
59
|
+
let okProps: ButtonEXProps = {
|
60
|
+
...(props.okButtonProps as any || {}),
|
61
|
+
onClick: () => onOK(),
|
62
|
+
title: props.okButtonText || 'OK'
|
63
|
+
};
|
64
|
+
let cancelProps: ButtonEXProps = {
|
65
|
+
...(props.cancelButtonProps as any || {}),
|
66
|
+
onClick: () => onCancel(),
|
67
|
+
title: props.cancelButtonText || 'Cancel'
|
68
|
+
};
|
69
|
+
|
70
|
+
useKeyDown({
|
71
|
+
onEnter: (e) => {
|
72
|
+
const topMost = dialogsOrder.indexOf(myId) === dialogsOrder.length - 1;
|
73
|
+
if (topMost && !disableKeyboardActions.current) {
|
74
|
+
stopEvent(e);
|
75
|
+
onOK();
|
76
|
+
}
|
77
|
+
},
|
78
|
+
onEscape: (e) => {
|
79
|
+
const topMost = dialogsOrder.indexOf(myId) === dialogsOrder.length - 1;
|
80
|
+
if (topMost && !disableKeyboardActions.current) {
|
81
|
+
stopEvent(e);
|
82
|
+
onCancel();
|
83
|
+
}
|
84
|
+
}
|
85
|
+
});
|
86
|
+
|
87
|
+
const actions: JSX.Element[] = [];
|
88
|
+
if (!props.hideOk) actions.push(<DialogTrigger key='ok' disableButtonEnhancement>
|
89
|
+
<ButtonEXSecondary {...okProps} />
|
90
|
+
</DialogTrigger>);
|
91
|
+
if (!props.hideCancel) actions.push(<DialogTrigger key='cancel' disableButtonEnhancement>
|
92
|
+
<ButtonEXSecondary {...cancelProps} />
|
93
|
+
</DialogTrigger>);
|
94
|
+
if (isNotEmptyArray(props.actions))
|
95
|
+
actions.push(...props.actions);
|
96
|
+
|
97
|
+
const titleActions: JSX.Element[] = props.titleActions ? [...props.titleActions] : [];
|
98
|
+
if (props.showCancelInTitle)
|
99
|
+
titleActions.push(<DialogTrigger key='cancel' disableButtonEnhancement>
|
100
|
+
<ButtonEX {...cancelProps} icon={<DismissRegular />} />
|
101
|
+
</DialogTrigger>);
|
102
|
+
|
103
|
+
|
104
|
+
return (
|
105
|
+
<Dialog open modalType={props.modalType}>
|
106
|
+
<DialogSurface mountNode={props.mountNode || ctx.mountNode}
|
107
|
+
style={!isNullOrEmptyString(props.maxWidth) ? { maxWidth: props.maxWidth } : undefined}>
|
108
|
+
<DialogBody>
|
109
|
+
{(!isNullOrEmptyString(props.title) || isNotEmptyArray(titleActions)) && <DialogTitle
|
110
|
+
action={titleActions}
|
111
|
+
>{props.title}</DialogTitle>}
|
112
|
+
<DialogContent ref={ref}>
|
113
|
+
{props.children}
|
114
|
+
</DialogContent>
|
115
|
+
{isNotEmptyArray(actions) && <DialogActions fluid={actions.length > 2}>
|
116
|
+
{actions}
|
117
|
+
</DialogActions>}
|
118
|
+
</DialogBody>
|
119
|
+
</DialogSurface>
|
120
|
+
</Dialog>
|
121
|
+
);
|
122
122
|
});
|
package/src/controls/qrcode.tsx
CHANGED
@@ -1,37 +1,37 @@
|
|
1
|
-
import { makeStyles } from '@fluentui/react-components';
|
2
|
-
import { colorToHex } from '@kwiz/common';
|
3
|
-
import QRCode from 'qrcode';
|
4
|
-
import React, { useEffect, useRef } from 'react';
|
5
|
-
|
6
|
-
const useStyles = makeStyles({
|
7
|
-
center: {
|
8
|
-
justifyContent: 'center'
|
9
|
-
},
|
10
|
-
})
|
11
|
-
|
12
|
-
interface IProps {
|
13
|
-
value: string;
|
14
|
-
color?: string;
|
15
|
-
width?: number;
|
16
|
-
backgroundColor?: string;
|
17
|
-
foregroundColor?: string;
|
18
|
-
}
|
19
|
-
export const QRCodeEX: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
20
|
-
const container = useRef<HTMLCanvasElement>();
|
21
|
-
useEffect(() => {
|
22
|
-
if (container.current) {
|
23
|
-
let dark = props.foregroundColor ? colorToHex(props.foregroundColor) : "#000000ff";
|
24
|
-
let light = props.backgroundColor ? colorToHex(props.backgroundColor) : "#ffffffff";
|
25
|
-
QRCode.toCanvas(container.current, props.value, {
|
26
|
-
color: {
|
27
|
-
dark,
|
28
|
-
light
|
29
|
-
},
|
30
|
-
width: props.width
|
31
|
-
});
|
32
|
-
}
|
33
|
-
}, [container]);
|
34
|
-
return (
|
35
|
-
<canvas ref={container} />
|
36
|
-
);
|
1
|
+
import { makeStyles } from '@fluentui/react-components';
|
2
|
+
import { colorToHex } from '@kwiz/common';
|
3
|
+
import QRCode from 'qrcode';
|
4
|
+
import React, { useEffect, useRef } from 'react';
|
5
|
+
|
6
|
+
const useStyles = makeStyles({
|
7
|
+
center: {
|
8
|
+
justifyContent: 'center'
|
9
|
+
},
|
10
|
+
})
|
11
|
+
|
12
|
+
interface IProps {
|
13
|
+
value: string;
|
14
|
+
color?: string;
|
15
|
+
width?: number;
|
16
|
+
backgroundColor?: string;
|
17
|
+
foregroundColor?: string;
|
18
|
+
}
|
19
|
+
export const QRCodeEX: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
20
|
+
const container = useRef<HTMLCanvasElement>();
|
21
|
+
useEffect(() => {
|
22
|
+
if (container.current) {
|
23
|
+
let dark = props.foregroundColor ? colorToHex(props.foregroundColor) : "#000000ff";
|
24
|
+
let light = props.backgroundColor ? colorToHex(props.backgroundColor) : "#ffffffff";
|
25
|
+
QRCode.toCanvas(container.current, props.value, {
|
26
|
+
color: {
|
27
|
+
dark,
|
28
|
+
light
|
29
|
+
},
|
30
|
+
width: props.width
|
31
|
+
});
|
32
|
+
}
|
33
|
+
}, [container]);
|
34
|
+
return (
|
35
|
+
<canvas ref={container} />
|
36
|
+
);
|
37
37
|
}
|
package/src/controls/search.tsx
CHANGED
@@ -1,62 +1,72 @@
|
|
1
|
-
import { Input, InputProps, makeStyles, mergeClasses } from '@fluentui/react-components';
|
2
|
-
import { DismissRegular, SearchRegular } from "@fluentui/react-icons";
|
3
|
-
import { debounce, isNullOrEmptyString } from '@kwiz/common';
|
4
|
-
import React, { useRef } from 'react';
|
5
|
-
import { GetLogger } from '../_modules/config';
|
6
|
-
import {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
}
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
props.
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
1
|
+
import { Input, InputProps, makeStyles, mergeClasses } from '@fluentui/react-components';
|
2
|
+
import { DismissRegular, SearchRegular } from "@fluentui/react-icons";
|
3
|
+
import { debounce, isNullOrEmptyString, isNullOrUndefined } from '@kwiz/common';
|
4
|
+
import React, { useEffect, useRef } from 'react';
|
5
|
+
import { GetLogger } from '../_modules/config';
|
6
|
+
import { useEffectOnlyOnMount, useStateEX } from '../helpers';
|
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
|
+
root: {
|
14
|
+
},
|
15
|
+
searchIcon: {
|
16
|
+
},
|
17
|
+
})
|
18
|
+
|
19
|
+
interface IProps extends Omit<InputProps, "onChange"> {
|
20
|
+
main?: boolean;
|
21
|
+
/** number of seconds to debounce the deferred event */
|
22
|
+
delay?: number;
|
23
|
+
/** if changing the value in the caller - change this prop to reset */
|
24
|
+
resetValue?: string;
|
25
|
+
onChangeDeferred?: (newValue: string) => void;
|
26
|
+
onChange?: (newValue: string) => void;
|
27
|
+
}
|
28
|
+
|
29
|
+
/** value is set on first load. to change the value after it was first set - change the compoenet's key. */
|
30
|
+
export const Search: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
31
|
+
const cssNames = useStyles();
|
32
|
+
|
33
|
+
let delay = props.delay || 1;
|
34
|
+
|
35
|
+
let refonChangeDeferred = useRef(props.onChangeDeferred);
|
36
|
+
//keep updating the ref
|
37
|
+
React.useEffect(() => { refonChangeDeferred.current = props.onChangeDeferred; }, [props.onChangeDeferred]);
|
38
|
+
|
39
|
+
//cannot call debounce every render, since it won't be the same debounced instance...
|
40
|
+
var notifyParent = React.useCallback(debounce(v => {
|
41
|
+
logger.log(`Set: ${v}`);
|
42
|
+
//Call the latest ref - we don't want to call an old version of this function
|
43
|
+
refonChangeDeferred.current?.(v);
|
44
|
+
}, delay * 1000), [delay]);
|
45
|
+
|
46
|
+
const [currentValue, setCurrentValue] = useStateEX(props.value || props.defaultValue || "", { skipUpdateIfSame: true });
|
47
|
+
useEffect(() => {
|
48
|
+
if (!isNullOrUndefined(props.value))
|
49
|
+
setCurrentValue(props.value);
|
50
|
+
}, [props.value]);
|
51
|
+
|
52
|
+
var changeValue = React.useCallback((newValue: string) => {
|
53
|
+
newValue = newValue || "";//no null or undefined here
|
54
|
+
setCurrentValue(newValue);//keep our state updated in sync
|
55
|
+
props.onChange?.(newValue);//if parent is using search as managed control, keep it up to date in sync
|
56
|
+
notifyParent(newValue);//trigger a search async
|
57
|
+
}, useEffectOnlyOnMount);
|
58
|
+
|
59
|
+
return (
|
60
|
+
<Input {...props} autoFocus defaultValue={undefined} value={currentValue} onChange={(e, data) => {
|
61
|
+
changeValue(data.value);
|
62
|
+
}}
|
63
|
+
className={mergeClasses(cssNames.root, props.main && cssNames.main)}
|
64
|
+
contentBefore={!isNullOrEmptyString(currentValue) ? undefined : <SearchRegular className={cssNames.searchIcon} />}
|
65
|
+
contentAfter={isNullOrEmptyString(currentValue)
|
66
|
+
? undefined
|
67
|
+
: <DismissRegular className={cssNames.clickable} onClick={() => {
|
68
|
+
changeValue("");
|
69
|
+
}} />
|
70
|
+
} />
|
71
|
+
);
|
62
72
|
}
|