@kwiz/fluentui 1.0.61 → 1.0.63
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/README.md +37 -11
- package/dist/controls/button.d.ts +11 -11
- package/dist/controls/button.js +2 -3
- package/dist/controls/button.js.map +1 -1
- package/dist/controls/centered.js +1 -8
- package/dist/controls/centered.js.map +1 -1
- package/dist/controls/date.js +1 -1
- package/dist/controls/date.js.map +1 -1
- package/dist/controls/diagram-picker.d.ts +2 -2
- package/dist/controls/divider.d.ts +2 -2
- package/dist/controls/dropdown.d.ts +4 -9
- package/dist/controls/dropdown.js +27 -28
- package/dist/controls/dropdown.js.map +1 -1
- package/dist/controls/file-upload.d.ts +1 -1
- package/dist/controls/horizontal.d.ts +2 -2
- package/dist/controls/index.d.ts +1 -0
- package/dist/controls/index.js +1 -0
- package/dist/controls/index.js.map +1 -1
- package/dist/controls/input.js +1 -1
- package/dist/controls/input.js.map +1 -1
- package/dist/controls/list.js +4 -1
- package/dist/controls/list.js.map +1 -1
- package/dist/controls/merge-text.d.ts +16 -0
- package/dist/controls/merge-text.js +81 -0
- package/dist/controls/merge-text.js.map +1 -0
- package/dist/controls/progress-bar.d.ts +2 -2
- package/dist/controls/prompt.d.ts +1 -1
- package/dist/controls/search.d.ts +3 -2
- package/dist/controls/search.js +20 -34
- package/dist/controls/search.js.map +1 -1
- package/dist/controls/section.d.ts +3 -2
- package/dist/controls/section.js +15 -5
- package/dist/controls/section.js.map +1 -1
- package/dist/controls/svg.d.ts +3 -0
- package/dist/controls/svg.js +5 -0
- package/dist/controls/svg.js.map +1 -1
- package/dist/controls/toolbar.js +2 -3
- package/dist/controls/toolbar.js.map +1 -1
- package/dist/controls/vertical.d.ts +4 -2
- package/dist/controls/vertical.js +6 -1
- package/dist/controls/vertical.js.map +1 -1
- package/dist/helpers/context-const.d.ts +2 -0
- package/dist/helpers/context-const.js.map +1 -1
- package/dist/helpers/context-export.d.ts +6 -1
- package/dist/helpers/context-export.js +44 -6
- package/dist/helpers/context-export.js.map +1 -1
- package/dist/helpers/forwardRef.d.ts +4 -0
- package/dist/helpers/forwardRef.js +2 -0
- package/dist/helpers/forwardRef.js.map +1 -0
- package/dist/helpers/hooks-events.d.ts +3 -3
- package/dist/helpers/hooks-events.js.map +1 -1
- package/dist/helpers/hooks.d.ts +1 -1
- package/dist/helpers/hooks.js +15 -6
- package/dist/helpers/hooks.js.map +1 -1
- package/dist/styles/styles.d.ts +5 -1
- package/dist/styles/styles.js +5 -18
- package/dist/styles/styles.js.map +1 -1
- package/package.json +3 -1
- package/src/controls/button.tsx +2 -3
- package/src/controls/centered.tsx +2 -10
- package/src/controls/date.tsx +1 -1
- package/src/controls/dropdown.tsx +37 -36
- package/src/controls/index.ts +2 -0
- package/src/controls/input.tsx +1 -1
- package/src/controls/list.tsx +4 -2
- package/src/controls/merge-text.tsx +126 -0
- package/src/controls/search.tsx +20 -33
- package/src/controls/section.tsx +17 -5
- package/src/controls/svg.tsx +8 -0
- package/src/controls/toolbar.tsx +2 -4
- package/src/controls/vertical.tsx +9 -1
- package/src/helpers/context-const.ts +2 -0
- package/src/helpers/context-export.tsx +52 -8
- package/src/helpers/forwardRef.ts +7 -0
- package/src/helpers/hooks-events.ts +2 -2
- package/src/helpers/hooks.tsx +16 -7
- package/src/styles/styles.ts +5 -18
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kwiz/fluentui",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.63",
|
4
4
|
"description": "KWIZ common controls for FluentUI",
|
5
5
|
"module": "dist/index.js",
|
6
6
|
"types": "dist/index.d.ts",
|
@@ -61,6 +61,8 @@
|
|
61
61
|
"@fluentui/react-datepicker-compat": "^0.4.53",
|
62
62
|
"@fluentui/react-timepicker-compat": "^0.2.42",
|
63
63
|
"@kwiz/common": "^1.0.103",
|
64
|
+
"@mismerge/core": "^1.2.1",
|
65
|
+
"@mismerge/react": "^1.0.1",
|
64
66
|
"esbuild": "^0.19.12",
|
65
67
|
"get-tsconfig": "^4.7.2",
|
66
68
|
"jodit": "^4.2.47",
|
package/src/controls/button.tsx
CHANGED
@@ -2,7 +2,7 @@ import { Button, ButtonProps, CompoundButton, compoundButtonClassNames, Compound
|
|
2
2
|
import { capitalizeFirstLetter, isFunction, isNullOrEmptyString, isNullOrUndefined, isString, PushNoDuplicate } from '@kwiz/common';
|
3
3
|
import React from 'react';
|
4
4
|
import { useKWIZFluentContext } from '../helpers/context-internal';
|
5
|
-
import { commonSizes,
|
5
|
+
import { commonSizes, KnownClassNames } from '../styles/styles';
|
6
6
|
|
7
7
|
interface IProps {
|
8
8
|
title: string;//required
|
@@ -72,11 +72,10 @@ export const ButtonEX = React.forwardRef<HTMLButtonElement, (ButtonEXProps)>((pr
|
|
72
72
|
let hasIcon = !isNullOrUndefined(icon);
|
73
73
|
let hasText = props.children || !hasIcon || (hasIcon && props.showTitleWithIcon === true);
|
74
74
|
|
75
|
-
const commonCssNames = useCommonStyles();
|
76
75
|
const cssNames = useStyles();
|
77
76
|
let css: string[] = [];
|
78
77
|
|
79
|
-
if (props.hideOnPrint) PushNoDuplicate(css,
|
78
|
+
if (props.hideOnPrint) PushNoDuplicate(css, KnownClassNames.printHide);
|
80
79
|
if (props.dontCenterText) PushNoDuplicate(css, cssNames.buttonNoCenter);
|
81
80
|
|
82
81
|
let btn = <Button ref={ref} appearance='subtle' {...props as any as ButtonProps} className={mergeClasses(...css, props.className)}
|
@@ -1,21 +1,13 @@
|
|
1
|
-
import { makeStyles } from '@fluentui/react-components';
|
2
1
|
import React from 'react';
|
3
2
|
import { Horizontal } from './horizontal';
|
4
3
|
import { Vertical } from './vertical';
|
5
4
|
|
6
|
-
const useStyles = makeStyles({
|
7
|
-
center: {
|
8
|
-
justifyContent: 'center'
|
9
|
-
},
|
10
|
-
})
|
11
|
-
|
12
5
|
interface IProps {
|
13
6
|
}
|
14
7
|
export const Centered: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
15
|
-
const cssNames = useStyles();
|
16
8
|
return (
|
17
|
-
<Vertical main
|
18
|
-
<Horizontal
|
9
|
+
<Vertical main vCentered>
|
10
|
+
<Horizontal hCentered>
|
19
11
|
{props.children}
|
20
12
|
</Horizontal>
|
21
13
|
</Vertical>
|
package/src/controls/date.tsx
CHANGED
@@ -40,7 +40,7 @@ export const DatePickerEx: React.FunctionComponent<React.PropsWithChildren<IProp
|
|
40
40
|
timeValue ? timeValue.getMinutes() : 0, 0, 0
|
41
41
|
);
|
42
42
|
props.onDateChange(newDate);
|
43
|
-
}, [timeValue]);
|
43
|
+
}, [timeValue, props.onDateChange]);
|
44
44
|
|
45
45
|
const changeTimeHandler = React.useCallback((newTimeValue: Date): void => {
|
46
46
|
//update our state
|
@@ -1,18 +1,20 @@
|
|
1
1
|
import { Dropdown, DropdownProps, makeStyles, mergeClasses, Option } from '@fluentui/react-components';
|
2
2
|
import { filterEmptyEntries, firstOrNull, isNullOrUndefined } from '@kwiz/common';
|
3
3
|
import React from 'react';
|
4
|
+
import { GetLogger } from '../_modules/config';
|
4
5
|
import { useKWIZFluentContext } from '../helpers/context-internal';
|
5
6
|
|
7
|
+
const logger = GetLogger("DropdownEX");
|
8
|
+
|
6
9
|
const useStyles = makeStyles({
|
7
10
|
root: {
|
8
11
|
minWidth: "auto"
|
9
12
|
},
|
10
13
|
});
|
11
14
|
|
12
|
-
|
13
15
|
type ForwardProps = Omit<DropdownProps, "onSelect" | "selectedOptions" | "clearable">;
|
14
16
|
|
15
|
-
interface IProps<
|
17
|
+
interface IProps<keyType, dataType> extends ForwardProps {
|
16
18
|
required?: boolean;
|
17
19
|
selected: keyType | keyType[];
|
18
20
|
items: {
|
@@ -27,40 +29,39 @@ interface IProps<dataType, keyType extends string = string> extends ForwardProps
|
|
27
29
|
options?: { key: keyType, value: string, data?: dataType }[]) => void;
|
28
30
|
}
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
*/
|
35
|
-
export function getDropdownEX<keyType extends string = string, dataType = never>() {
|
36
|
-
return React.forwardRef<HTMLButtonElement, (IProps<dataType, keyType>)>((props, ref) => {
|
37
|
-
const classes = useStyles();
|
38
|
-
const ctx = useKWIZFluentContext();
|
39
|
-
const selected: keyType[] = Array.isArray(props.selected) ? props.selected : isNullOrUndefined(props.selected) ? [] : [props.selected];
|
32
|
+
function $DropdownEX<keyType extends string = string, dataType = never>(props: IProps<keyType, dataType>, ref: React.ForwardedRef<HTMLButtonElement>) {
|
33
|
+
const classes = useStyles();
|
34
|
+
const ctx = useKWIZFluentContext();
|
35
|
+
const selected: keyType[] = Array.isArray(props.selected) ? props.selected : isNullOrUndefined(props.selected) ? [] : [props.selected];
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
37
|
+
//sometimes control will lose value when re-rendered
|
38
|
+
//use case: public forms when editing other fields after the dropdown was set
|
39
|
+
//re-set the text value manually to fix
|
40
|
+
let text = filterEmptyEntries((Array.isArray(props.selected) ? props.selected : [props.selected]).map(s => {
|
41
|
+
let v = firstOrNull(props.items, i => i.key === s);
|
42
|
+
return v ? v.value : ''
|
43
|
+
})).join(', ');
|
48
44
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
});
|
45
|
+
return (
|
46
|
+
<Dropdown {...{ ...props, onSelect: undefined }} className={mergeClasses(classes.root, props.className)} ref={ref} clearable={!props.required && !props.multiselect}
|
47
|
+
appearance={ctx.inputAppearance} mountNode={ctx.mountNode}
|
48
|
+
selectedOptions={selected} value={text} onOptionSelect={(e, data) => {
|
49
|
+
let o = firstOrNull(props.items, i => i.key === data.optionValue);
|
50
|
+
if (props.multiselect) {
|
51
|
+
let current = data.selectedOptions.map(s => firstOrNull(props.items, i => i.key === s));
|
52
|
+
props.onSelect(o, current);
|
53
|
+
}
|
54
|
+
else props.onSelect(o);
|
55
|
+
}}>
|
56
|
+
{props.items.map(i => <Option key={i.key} value={i.key} text={i.value}>{i.option ? i.option : i.value}</Option>)}
|
57
|
+
</Dropdown>
|
58
|
+
);
|
64
59
|
}
|
65
|
-
|
66
|
-
export const DropdownEX =
|
60
|
+
|
61
|
+
export const DropdownEX = React.forwardRef($DropdownEX);
|
62
|
+
|
63
|
+
/** @deprecated use normal DropdownEX it is now generic */
|
64
|
+
export function getDropdownEX<keyType extends string = string, dataType = never>() {
|
65
|
+
logger.warn('getDropdownEX is deprecated. use DropdownEX it now supports generic types');
|
66
|
+
return React.forwardRef($DropdownEX<keyType, dataType>);
|
67
|
+
}
|
package/src/controls/index.ts
CHANGED
@@ -19,6 +19,7 @@ export * from './kwizoverflow';
|
|
19
19
|
export * from './list';
|
20
20
|
export * from './loading';
|
21
21
|
export * from './menu';
|
22
|
+
export * from './merge-text';
|
22
23
|
export * from './please-wait';
|
23
24
|
export * from './progress-bar';
|
24
25
|
export * from './prompt';
|
@@ -29,3 +30,4 @@ export * from './svg';
|
|
29
30
|
export * from './toolbar';
|
30
31
|
export * from './vertical';
|
31
32
|
export * from './vertical-content';
|
33
|
+
|
package/src/controls/input.tsx
CHANGED
@@ -112,7 +112,7 @@ export const InputNumberEx: React.FunctionComponent<React.PropsWithChildren<INum
|
|
112
112
|
const isValid = props.required ? !isNullOrNaN(asNumber) : isNullOrUndefined(asNumber) || !isNaN(asNumber);
|
113
113
|
setIsValid(isValid);
|
114
114
|
props.onChange(isValid ? asNumber : null);
|
115
|
-
}, [props.allowDecimals]);
|
115
|
+
}, [props.allowDecimals, props.onChange, props.required]);
|
116
116
|
|
117
117
|
const passProps: IProps = { ...props, defaultValue: undefined, value: undefined, onChange: undefined };
|
118
118
|
|
package/src/controls/list.tsx
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import { makeStyles, tokens } from '@fluentui/react-components';
|
2
2
|
import { LOGO_BLUE_SQUARE, LOGO_WHITE_SQUARE, isNullOrUndefined, isString } from '@kwiz/common';
|
3
3
|
import React from 'react';
|
4
|
+
import { useKWIZFluentContext } from '../helpers/context-internal';
|
4
5
|
import { KnownClassNames, mixins } from '../styles/styles';
|
5
6
|
import { Horizontal } from './horizontal';
|
6
7
|
import { Section } from './section';
|
@@ -85,8 +86,9 @@ interface IProps {
|
|
85
86
|
}
|
86
87
|
|
87
88
|
export const ListEx = (props: IProps) => {
|
88
|
-
|
89
|
+
const ctx = useKWIZFluentContext();
|
89
90
|
const cssNames = useStyles();
|
91
|
+
const isDark = ctx.dark === true || props.dark === true;
|
90
92
|
|
91
93
|
const listItemElm = (item: iListItem) => <Horizontal key={item.key} css={[cssNames.listItem, item.selected && cssNames.listItemSelected]} onClick={item.onClick}>
|
92
94
|
{item.media && <Section css={[cssNames.media]} onClick={(e) => {
|
@@ -94,7 +96,7 @@ export const ListEx = (props: IProps) => {
|
|
94
96
|
e.stopPropagation();//media may have its on onclick
|
95
97
|
}}>{
|
96
98
|
isString(item.media)
|
97
|
-
? <div className={cssNames.image} style={{ backgroundImage: `url('${encodeURI(item.media)}'), url('${
|
99
|
+
? <div className={cssNames.image} style={{ backgroundImage: `url('${encodeURI(item.media)}'), url('${isDark ? LOGO_WHITE_SQUARE : LOGO_BLUE_SQUARE}')` }}></div>
|
98
100
|
: item.media
|
99
101
|
}</Section>}
|
100
102
|
<Vertical main css={[cssNames.listItemBody]}>
|
@@ -0,0 +1,126 @@
|
|
1
|
+
import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle, Field, Label, makeStyles, Radio, tokens } from '@fluentui/react-components';
|
2
|
+
import { DismissRegular, SaveRegular } from '@fluentui/react-icons';
|
3
|
+
import { isNullOrUndefined, waitFor } from '@kwiz/common';
|
4
|
+
import { DefaultDarkColors, DefaultLightColors, MisMerge2 } from '@mismerge/react';
|
5
|
+
import * as React from 'react';
|
6
|
+
|
7
|
+
import '@mismerge/core/dark.css';
|
8
|
+
import '@mismerge/core/styles.css';
|
9
|
+
import { useStateEX, useWindowSize } from '../helpers';
|
10
|
+
import { useKWIZFluentContext } from '../helpers/context-internal';
|
11
|
+
import { ButtonEX, ButtonEXPrimarySubtle } from './button';
|
12
|
+
import { Horizontal } from './horizontal';
|
13
|
+
import { Section } from './section';
|
14
|
+
import { Vertical } from './vertical';
|
15
|
+
|
16
|
+
const useStyles = makeStyles({
|
17
|
+
root: {
|
18
|
+
// position: 'fixed',
|
19
|
+
// top: 0,
|
20
|
+
// left: 0,
|
21
|
+
// right: 0,
|
22
|
+
// bottom: 0,
|
23
|
+
// backgroundColor: tokens.colorNeutralBackground1,
|
24
|
+
// zIndex: 10,
|
25
|
+
"& .mismerge": {
|
26
|
+
// height: "100%",
|
27
|
+
"--background": tokens.colorNeutralBackground1,
|
28
|
+
//line number background
|
29
|
+
"--primary-100": tokens.colorNeutralBackground2,
|
30
|
+
//selection background
|
31
|
+
"--selection": tokens.colorNeutralBackground1Selected,
|
32
|
+
//scrollbar hover
|
33
|
+
"--primary-300": tokens.colorNeutralBackground1Hover,
|
34
|
+
//border / scroll
|
35
|
+
"--primary-200": tokens.colorNeutralStroke1,
|
36
|
+
//line number color
|
37
|
+
"--primary-400": tokens.colorNeutralForeground2,
|
38
|
+
//button hover color
|
39
|
+
"--primary-500": tokens.colorNeutralForeground1Hover,
|
40
|
+
//main text color
|
41
|
+
"--primary-600": tokens.colorNeutralForeground1,
|
42
|
+
"& TEXTAREA": {
|
43
|
+
lineHeight: "20px"
|
44
|
+
}
|
45
|
+
}
|
46
|
+
},
|
47
|
+
menu: {
|
48
|
+
justifyContent: "space-between"
|
49
|
+
}
|
50
|
+
});
|
51
|
+
|
52
|
+
interface IProps {
|
53
|
+
title: string;
|
54
|
+
description?: string;
|
55
|
+
lhsTitle: string;
|
56
|
+
lhsValue: string;
|
57
|
+
rhsTitle: string;
|
58
|
+
rhsValue: string;
|
59
|
+
dark?: boolean;
|
60
|
+
save: (merged: string) => void;
|
61
|
+
cancel: () => void;
|
62
|
+
}
|
63
|
+
export const MergeText: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
64
|
+
const classes = useStyles();
|
65
|
+
const ctx = useKWIZFluentContext();
|
66
|
+
|
67
|
+
let size = useWindowSize();
|
68
|
+
let wrapper = React.useRef<HTMLDivElement>();
|
69
|
+
let [lhs, setLhs] = useStateEX(props.lhsValue || "", {
|
70
|
+
skipUpdateIfSame: true, onChange: (v, changed) => {
|
71
|
+
if (changed) setKeep("left"); return v;
|
72
|
+
}
|
73
|
+
});
|
74
|
+
let [rhs, setRhs] = useStateEX(props.rhsValue || "", {
|
75
|
+
skipUpdateIfSame: true, onChange: (v, changed) => {
|
76
|
+
if (changed) setKeep("right"); return v;
|
77
|
+
}
|
78
|
+
});
|
79
|
+
let [keep, setKeep] = useStateEX<"cancel" | "left" | "right">("cancel");
|
80
|
+
|
81
|
+
React.useEffect(() => {
|
82
|
+
if (wrapper.current) {
|
83
|
+
waitFor(() => !isNullOrUndefined(wrapper.current.querySelector(".mismerge"))).then(() => {
|
84
|
+
let mismerge = wrapper.current.querySelector(".mismerge") as HTMLDivElement;
|
85
|
+
if (mismerge)
|
86
|
+
mismerge.style.height = `${mismerge.offsetParent.clientHeight - mismerge.offsetTop - 10}px`;
|
87
|
+
});
|
88
|
+
}
|
89
|
+
}, [wrapper.current, size.height]);
|
90
|
+
|
91
|
+
return <Drawer type='overlay' open size='full' className={classes.root} mountNode={ctx.mountNode}>
|
92
|
+
<DrawerHeader>
|
93
|
+
<DrawerHeaderTitle action={<ButtonEX icon={<DismissRegular />} title="Close" onClick={props.cancel} />}>
|
94
|
+
{props.title}
|
95
|
+
</DrawerHeaderTitle>
|
96
|
+
</DrawerHeader>
|
97
|
+
<DrawerBody>
|
98
|
+
<Vertical>
|
99
|
+
{props.description && <Label>{props.description}</Label>}
|
100
|
+
<Field label="Which version would you like to keep?"
|
101
|
+
hint="Merge the changes to either side and save. Close this panel to keep editing the page without saving">
|
102
|
+
<Horizontal css={[classes.menu]}>
|
103
|
+
<Horizontal nogap>
|
104
|
+
<Radio value="left" label={props.lhsTitle} checked={keep === "left"} onClick={() => setKeep("left")} />
|
105
|
+
<ButtonEXPrimarySubtle showTitleWithIcon dontCenterText icon={<SaveRegular />} disabled={keep !== "left"} title={`Save ${props.lhsTitle.toLowerCase()}`} onClick={() => props.save(lhs)} />
|
106
|
+
</Horizontal>
|
107
|
+
<Horizontal nogap>
|
108
|
+
<Radio value="right" label={props.rhsTitle} checked={keep === "right"} onClick={() => setKeep("right")} />
|
109
|
+
<ButtonEXPrimarySubtle showTitleWithIcon dontCenterText icon={<SaveRegular />} disabled={keep !== "right"} title={`Save ${props.rhsTitle.toLowerCase()}`} onClick={() => props.save(rhs)} />
|
110
|
+
</Horizontal>
|
111
|
+
</Horizontal>
|
112
|
+
</Field>
|
113
|
+
<Section main ref={wrapper}>
|
114
|
+
<MisMerge2
|
115
|
+
lhs={lhs}
|
116
|
+
rhs={rhs}
|
117
|
+
lhsEditable rhsEditable
|
118
|
+
onLhsChange={v => setLhs(v)}
|
119
|
+
onRhsChange={v => setRhs(v)}
|
120
|
+
colors={props.dark ? DefaultDarkColors : DefaultLightColors}
|
121
|
+
/>
|
122
|
+
</Section>
|
123
|
+
</Vertical>
|
124
|
+
</DrawerBody>
|
125
|
+
</Drawer>;
|
126
|
+
}
|
package/src/controls/search.tsx
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
import { Input, InputProps, makeStyles, mergeClasses } from '@fluentui/react-components';
|
2
2
|
import { DismissRegular, SearchRegular } from "@fluentui/react-icons";
|
3
|
-
import { debounce,
|
4
|
-
import React, {
|
3
|
+
import { debounce, isNullOrEmptyString } from '@kwiz/common';
|
4
|
+
import React, { useRef } from 'react';
|
5
5
|
import { GetLogger } from '../_modules/config';
|
6
|
-
import { useStateEX } from '../helpers';
|
7
6
|
import { mixins } from '../styles/styles';
|
8
7
|
const logger = GetLogger("Search");
|
9
8
|
|
@@ -11,64 +10,52 @@ const useStyles = makeStyles({
|
|
11
10
|
main: mixins.main,
|
12
11
|
clickable: mixins.clickable,
|
13
12
|
root: {
|
14
|
-
paddingLeft: 0
|
15
13
|
},
|
16
14
|
searchIcon: {
|
17
|
-
position: "absolute",
|
18
|
-
left: '5px',
|
19
|
-
top: '5px'
|
20
15
|
},
|
21
16
|
})
|
22
17
|
|
23
|
-
interface IProps extends InputProps {
|
18
|
+
interface IProps extends Omit<InputProps, "onChange"> {
|
24
19
|
main?: boolean;
|
20
|
+
/** number of seconds to debounce the deferred event */
|
25
21
|
delay?: number;
|
26
22
|
/** if changing the value in the caller - change this prop to reset */
|
27
23
|
resetValue?: string;
|
28
24
|
onChangeDeferred?: (newValue: string) => void;
|
29
|
-
|
25
|
+
onChange?: (newValue: string) => void;
|
30
26
|
}
|
31
27
|
|
32
28
|
/** value is set on first load. to change the value after it was first set - change the compoenet's key. */
|
33
29
|
export const Search: React.FunctionComponent<React.PropsWithChildren<IProps>> = (props) => {
|
34
30
|
const cssNames = useStyles();
|
35
31
|
|
36
|
-
const [resetKey, setResetKey] = useState(1);
|
37
|
-
|
38
32
|
let delay = props.delay || 1;
|
39
33
|
|
34
|
+
let refonChangeDeferred = useRef(props.onChangeDeferred);
|
35
|
+
//keep updating the ref
|
36
|
+
React.useEffect(() => { refonChangeDeferred.current = props.onChangeDeferred; }, [props.onChangeDeferred]);
|
37
|
+
|
40
38
|
//cannot call debounce every render, since it won't be the same debounced instance...
|
41
39
|
var notifyParent = React.useMemo(() => debounce(v => {
|
42
40
|
logger.log(`Set: ${v}`);
|
43
|
-
|
41
|
+
//Call the latest ref - we don't want to call an old version of this function
|
42
|
+
refonChangeDeferred.current?.(v);
|
44
43
|
}, delay * 1000), [delay]);
|
45
44
|
|
46
|
-
|
47
|
-
onChange: newValue => {
|
48
|
-
if (isFunction(props.onChangeSync)) props.onChangeSync(newValue as string);
|
49
|
-
if (isFunction(props.onChangeDeferred)) notifyParent(newValue);
|
50
|
-
return newValue;
|
51
|
-
}
|
52
|
-
});
|
53
|
-
|
54
|
-
//once props change, reset this control value to match
|
55
|
-
React.useEffect(() => {
|
56
|
-
if (!isUndefined(props.resetValue))
|
57
|
-
setValue(props.resetValue);
|
58
|
-
//todo: bug: setting value does not sync into the text box
|
59
|
-
setResetKey(resetKey + 1)
|
60
|
-
}, [props.resetValue]);
|
45
|
+
const currentValue = props.value || "";
|
61
46
|
|
62
47
|
return (
|
63
|
-
<Input
|
48
|
+
<Input {...props} value={currentValue} onChange={(e, data) => {
|
49
|
+
props.onChange?.(data.value);
|
50
|
+
notifyParent(data.value);
|
51
|
+
}}
|
64
52
|
className={mergeClasses(cssNames.root, props.main && cssNames.main)}
|
65
|
-
contentBefore={!isNullOrEmptyString(
|
66
|
-
contentAfter={isNullOrEmptyString(
|
53
|
+
contentBefore={!isNullOrEmptyString(currentValue) ? undefined : <SearchRegular className={cssNames.searchIcon} />}
|
54
|
+
contentAfter={isNullOrEmptyString(currentValue)
|
67
55
|
? undefined
|
68
56
|
: <DismissRegular className={cssNames.clickable} onClick={() => {
|
69
|
-
|
70
|
-
|
71
|
-
setResetKey(resetKey + 1)
|
57
|
+
props.onChange?.("");
|
58
|
+
notifyParent("");
|
72
59
|
}} />
|
73
60
|
} />
|
74
61
|
);
|
package/src/controls/section.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { makeStyles, mergeClasses, Portal, tokens } from '@fluentui/react-components';
|
2
|
-
import { isFunction, isNotEmptyArray } from '@kwiz/common';
|
2
|
+
import { isFunction, isNotEmptyArray, isNotEmptyString } from '@kwiz/common';
|
3
3
|
import React from 'react';
|
4
4
|
import { useKWIZFluentContext } from '../helpers/context-internal';
|
5
5
|
import { KnownClassNames, mixins, useCommonStyles } from '../styles/styles';
|
@@ -15,7 +15,10 @@ const useStyles = makeStyles({
|
|
15
15
|
right: {
|
16
16
|
...mixins.float,
|
17
17
|
float: "right",
|
18
|
-
|
18
|
+
marginLeft: tokens.spacingHorizontalXXL
|
19
|
+
},
|
20
|
+
selfCentered: {
|
21
|
+
alignSelf: "center"
|
19
22
|
}
|
20
23
|
});
|
21
24
|
|
@@ -31,6 +34,7 @@ export interface ISectionProps {
|
|
31
34
|
right?: boolean;
|
32
35
|
/** true - will add css position fixed. portal will also wrap it in a portal. */
|
33
36
|
fullscreen?: boolean | "portal";
|
37
|
+
centerSelf?: boolean;
|
34
38
|
}
|
35
39
|
|
36
40
|
export const Section = React.forwardRef<HTMLDivElement, React.PropsWithChildren<ISectionProps>>((props, ref) => {
|
@@ -39,13 +43,21 @@ export const Section = React.forwardRef<HTMLDivElement, React.PropsWithChildren<
|
|
39
43
|
const cssNames = useStyles();
|
40
44
|
let css: string[] = [KnownClassNames.section];
|
41
45
|
if (props.main) css.push(cssNames.main);
|
46
|
+
if (props.centerSelf) css.push(cssNames.selfCentered);
|
42
47
|
if (isFunction(props.onClick))
|
43
48
|
css.push(cssNames.clickable);
|
44
49
|
|
45
|
-
if (props.left)
|
46
|
-
|
50
|
+
if (props.left) {
|
51
|
+
css.push(cssNames.left);
|
52
|
+
css.push(KnownClassNames.left);
|
53
|
+
}
|
54
|
+
else if (props.right) {
|
55
|
+
css.push(cssNames.right);
|
56
|
+
css.push(KnownClassNames.right);
|
57
|
+
}
|
47
58
|
|
48
|
-
|
59
|
+
//a css class might have space and multiuple classes in it
|
60
|
+
if (isNotEmptyArray(props.css)) props.css.filter(c => isNotEmptyString(c)).forEach(c => css.push(...c.split(" ")));
|
49
61
|
if (props.fullscreen) css.push(commonStyles.fullscreen);
|
50
62
|
const control = <div ref={ref} {...(props.rootProps || {})} title={props.title} style={props.style}
|
51
63
|
className={mergeClasses(...css)}
|
package/src/controls/svg.tsx
CHANGED
@@ -121,6 +121,14 @@ export const GetSVGSplitIcon = (props: { size: number }) => {
|
|
121
121
|
</svg>`;
|
122
122
|
}
|
123
123
|
|
124
|
+
export function GetSVGCopyIcon(props: { size: number }) {
|
125
|
+
return (
|
126
|
+
`<svg fill="var(--colorNeutralForeground1)" width="${props.size}px" height="${props.size}px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
127
|
+
<path d="M8 2a2 2 0 0 0-2 2v10c0 1.1.9 2 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8ZM7 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V4ZM4 6a2 2 0 0 1 1-1.73V14.5A2.5 2.5 0 0 0 7.5 17h6.23A2 2 0 0 1 12 18H7.5A3.5 3.5 0 0 1 4 14.5V6Z"></path>
|
128
|
+
</svg>`
|
129
|
+
)
|
130
|
+
}
|
131
|
+
|
124
132
|
export function IconToSVG(icon: JSX.Element) {
|
125
133
|
const iconDiv = document.createElement('div');
|
126
134
|
const root = createRoot(iconDiv);
|
package/src/controls/toolbar.tsx
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { Toolbar, ToolbarDivider, ToolbarGroup } from '@fluentui/react-components';
|
2
2
|
import React from 'react';
|
3
|
-
import {
|
3
|
+
import { KnownClassNames } from '../styles/styles';
|
4
4
|
import { KWIZOverflow } from './kwizoverflow';
|
5
5
|
|
6
6
|
interface IProps {
|
@@ -10,8 +10,6 @@ interface IProps {
|
|
10
10
|
sideButtons?: JSX.Element;
|
11
11
|
}
|
12
12
|
export const ToolbarEX: React.FunctionComponent<IProps> = (props) => {
|
13
|
-
const commonCssNames = useCommonStyles();
|
14
|
-
|
15
13
|
let elements: { id: string, priority?: number, elm: JSX.Element, overflowElement?: JSX.Element }[] = [];
|
16
14
|
props.buttonGroups.forEach((group, groupIndex) => {
|
17
15
|
group.forEach((button, buttonIndex) => {
|
@@ -32,7 +30,7 @@ export const ToolbarEX: React.FunctionComponent<IProps> = (props) => {
|
|
32
30
|
});
|
33
31
|
|
34
32
|
return (
|
35
|
-
<KWIZOverflow className={
|
33
|
+
<KWIZOverflow className={KnownClassNames.printHide}
|
36
34
|
items={elements}
|
37
35
|
getKey={e => e.id}
|
38
36
|
renderItem={(e, i, overflow) => overflow && e.overflowElement || e.elm}
|
@@ -10,12 +10,18 @@ const useStyles = makeStyles({
|
|
10
10
|
flexDirection: 'column'
|
11
11
|
},
|
12
12
|
wrap: mixins.wrap,
|
13
|
-
nogap: mixins.nogap
|
13
|
+
nogap: mixins.nogap,
|
14
|
+
vCentered: {
|
15
|
+
justifyContent: "center"
|
16
|
+
},
|
17
|
+
|
14
18
|
})
|
15
19
|
|
16
20
|
interface IProps extends ISectionProps {
|
17
21
|
wrap?: boolean;
|
18
22
|
nogap?: boolean;
|
23
|
+
/** vertical centered */
|
24
|
+
vCentered?: boolean;
|
19
25
|
}
|
20
26
|
export const Vertical = React.forwardRef<HTMLDivElement, React.PropsWithChildren<IProps>>((props, ref) => {
|
21
27
|
const cssNames = useStyles();
|
@@ -26,6 +32,8 @@ export const Vertical = React.forwardRef<HTMLDivElement, React.PropsWithChildren
|
|
26
32
|
css.push(cssNames.wrap);
|
27
33
|
if (props.nogap)
|
28
34
|
css.push(cssNames.nogap);
|
35
|
+
if (props.vCentered)
|
36
|
+
css.push(cssNames.vCentered);
|
29
37
|
|
30
38
|
if (isNotEmptyArray(props.css)) css.push(...props.css);
|
31
39
|
|