@monolith-forensics/monolith-ui 1.9.3-dev.4 → 2.1.0
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/dist/Button/Button.js +11 -4
- package/dist/DropDownMenu/DropDownMenu.js +12 -2
- package/dist/DropDownMenu/components/MenuComponent.js +7 -1
- package/dist/DropDownMenu/components/MenuItem.js +4 -2
- package/dist/DropDownMenu/components/MenuItemList.d.ts +1 -0
- package/dist/DropDownMenu/components/MenuItemList.js +17 -7
- package/dist/DropDownMenu/components/SearchInput.js +2 -1
- package/dist/DropDownMenu/components/StyledContent.js +3 -2
- package/dist/DropDownMenu/constants.d.ts +4 -0
- package/dist/DropDownMenu/constants.js +4 -0
- package/dist/QueryFilter/DefaultOperators.d.ts +76 -0
- package/dist/QueryFilter/DefaultOperators.js +21 -0
- package/dist/QueryFilter/types.d.ts +66 -0
- package/dist/QueryFilter/types.js +1 -0
- package/dist/RichTextEditor/Enums/Controls.d.ts +1 -0
- package/dist/RichTextEditor/Enums/Controls.js +1 -0
- package/dist/RichTextEditor/Enums/Extensions.d.ts +1 -0
- package/dist/RichTextEditor/Enums/Extensions.js +1 -0
- package/dist/RichTextEditor/Enums/Fonts.d.ts +2 -1
- package/dist/RichTextEditor/Enums/Fonts.js +2 -1
- package/dist/RichTextEditor/Enums/SlashCommands.d.ts +1 -0
- package/dist/RichTextEditor/Enums/SlashCommands.js +1 -0
- package/dist/RichTextEditor/Extensions/BubbleMenuExtension.d.ts +7 -0
- package/dist/RichTextEditor/Extensions/BubbleMenuExtension.js +157 -0
- package/dist/RichTextEditor/Extensions/getSlashCommand.js +10 -1
- package/dist/RichTextEditor/Extensions/getTiptapExtensions.js +15 -0
- package/dist/RichTextEditor/RichTextEditor.js +55 -27
- package/dist/RichTextEditor/Toolbar/Controls.d.ts +13 -0
- package/dist/RichTextEditor/Toolbar/Controls.js +142 -3
- package/dist/RichTextEditor/Toolbar/Labels.d.ts +1 -0
- package/dist/RichTextEditor/Toolbar/Labels.js +1 -0
- package/dist/RichTextEditor/Toolbar/Toolbar.js +28 -2
- package/dist/Table/Utils/resizeHandler.d.ts +3 -0
- package/dist/Table/Utils/resizeHandler.js +84 -0
- package/package.json +4 -1
package/dist/Button/Button.js
CHANGED
|
@@ -46,14 +46,16 @@ const StyledButton = styled.button `
|
|
|
46
46
|
return `0px ${getControlSizeTokens(size).buttonPaddingX}px`;
|
|
47
47
|
}};
|
|
48
48
|
|
|
49
|
-
color: ${({ theme, variant, color }) => {
|
|
49
|
+
color: ${({ theme, variant, color, selected }) => {
|
|
50
50
|
var _a, _b;
|
|
51
|
-
if (variant === "default")
|
|
52
|
-
return theme.palette.text.primary;
|
|
53
51
|
if (variant === "contained")
|
|
54
52
|
return "white";
|
|
55
53
|
if (variant === "filled")
|
|
56
54
|
return "white";
|
|
55
|
+
if (selected)
|
|
56
|
+
return theme.palette.primary.main;
|
|
57
|
+
if (variant === "default")
|
|
58
|
+
return theme.palette.text.primary;
|
|
57
59
|
if (color) {
|
|
58
60
|
return (((_b = (_a = theme === null || theme === void 0 ? void 0 : theme.button) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b[color]) ||
|
|
59
61
|
colors[color] ||
|
|
@@ -69,6 +71,9 @@ const StyledButton = styled.button `
|
|
|
69
71
|
resolvedColor =
|
|
70
72
|
((_b = (_a = theme === null || theme === void 0 ? void 0 : theme.button) === null || _a === void 0 ? void 0 : _a.background) === null || _b === void 0 ? void 0 : _b[color]) || colors[color];
|
|
71
73
|
}
|
|
74
|
+
if (selected && variant !== "contained" && variant !== "filled") {
|
|
75
|
+
return theme.palette.primary.main + "20";
|
|
76
|
+
}
|
|
72
77
|
switch (variant) {
|
|
73
78
|
case "default":
|
|
74
79
|
return theme.button.background.default;
|
|
@@ -121,7 +126,9 @@ const StyledButton = styled.button `
|
|
|
121
126
|
|
|
122
127
|
cursor: pointer;
|
|
123
128
|
|
|
124
|
-
transition:
|
|
129
|
+
transition:
|
|
130
|
+
background-color 0.2s,
|
|
131
|
+
border 0.2s;
|
|
125
132
|
|
|
126
133
|
.inner-span {
|
|
127
134
|
display: flex;
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { Menu, MenuItemList, StyledInnerItemContainer } from "./components";
|
|
4
|
+
import { DEFAULT_DROPDOWN_MAX_HEIGHT } from "./constants";
|
|
5
|
+
const getNumericCssLength = (value) => {
|
|
6
|
+
if (typeof value === "number")
|
|
7
|
+
return value;
|
|
8
|
+
if (typeof value !== "string")
|
|
9
|
+
return undefined;
|
|
10
|
+
const pixelMatch = value.trim().match(/^(\d+(?:\.\d+)?)px$/);
|
|
11
|
+
return pixelMatch ? Number(pixelMatch[1]) : undefined;
|
|
12
|
+
};
|
|
4
13
|
export const DropDownMenu = ({ data, children, defaultValue, value, variant, arrow, size, searchable, grouped, onAddNew, loading, onScroll, onScrollToTop, onScrollToBottom, onSearch, manualSearch, multiselect, enableSelectAll, enableSelectedOptionStyling, renderOption, dynamicOptionHeight, onItemSelect, onChange, buttonProps, TooltipContent, dropDownProps, query, disabled, }) => {
|
|
5
|
-
var _a;
|
|
14
|
+
var _a, _b, _c, _d, _e, _f;
|
|
6
15
|
const isObjectArray = (_a = Object.keys((data === null || data === void 0 ? void 0 : data[0]) || {})) === null || _a === void 0 ? void 0 : _a.includes("label");
|
|
16
|
+
const maxDropdownHeight = (_f = (_e = (_c = getNumericCssLength((_b = dropDownProps === null || dropDownProps === void 0 ? void 0 : dropDownProps.style) === null || _b === void 0 ? void 0 : _b.height)) !== null && _c !== void 0 ? _c : getNumericCssLength((_d = dropDownProps === null || dropDownProps === void 0 ? void 0 : dropDownProps.style) === null || _d === void 0 ? void 0 : _d.maxHeight)) !== null && _e !== void 0 ? _e : getNumericCssLength(dropDownProps === null || dropDownProps === void 0 ? void 0 : dropDownProps.maxDropdownHeight)) !== null && _f !== void 0 ? _f : DEFAULT_DROPDOWN_MAX_HEIGHT;
|
|
7
17
|
const [internalSelected, setInternalSelected] = useState(defaultValue || []);
|
|
8
18
|
const isControlled = value !== undefined;
|
|
9
19
|
const selected = isControlled ? value || [] : internalSelected;
|
|
@@ -35,5 +45,5 @@ export const DropDownMenu = ({ data, children, defaultValue, value, variant, arr
|
|
|
35
45
|
const handleScrollToBottom = (e) => {
|
|
36
46
|
onScrollToBottom === null || onScrollToBottom === void 0 ? void 0 : onScrollToBottom(e);
|
|
37
47
|
};
|
|
38
|
-
return (_jsx(Menu, { label: children, disabled: disabled, arrow: arrow, buttonSize: size, variant: variant, multiselect: multiselect, buttonProps: buttonProps, onMenuClose: handleMenuClose, dropDownProps: dropDownProps, children: _jsxs(StyledInnerItemContainer, { children: [loading && _jsx("div", { children: "Loading..." }), !loading && (_jsx(MenuItemList, { menuItems: data, searchable: searchable, grouped: grouped, onAddNew: onAddNew, onSearch: onSearch, manualSearch: manualSearch, dynamicOptionHeight: dynamicOptionHeight, selected: selected, TooltipContent: TooltipContent, multiselect: multiselect, enableSelectAll: enableSelectAll, enableSelectedOptionStyling: enableSelectedOptionStyling, size: size, handleAddItem: handleAddItem, handleRemoveItem: handleRemoveItem, handleSetSelected: handleSetSelected, onItemSelect: onItemSelect, renderOption: renderOption, onScroll: onScroll, onScrollToTop: onScrollToTop, onScrollToBottom: handleScrollToBottom, query: query }))] }) }));
|
|
48
|
+
return (_jsx(Menu, { label: children, disabled: disabled, arrow: arrow, buttonSize: size, variant: variant, multiselect: multiselect, buttonProps: buttonProps, onMenuClose: handleMenuClose, dropDownProps: dropDownProps, children: _jsxs(StyledInnerItemContainer, { children: [loading && _jsx("div", { children: "Loading..." }), !loading && (_jsx(MenuItemList, { menuItems: data, searchable: searchable, grouped: grouped, onAddNew: onAddNew, onSearch: onSearch, manualSearch: manualSearch, dynamicOptionHeight: dynamicOptionHeight, maxDropdownHeight: maxDropdownHeight, selected: selected, TooltipContent: TooltipContent, multiselect: multiselect, enableSelectAll: enableSelectAll, enableSelectedOptionStyling: enableSelectedOptionStyling, size: size, handleAddItem: handleAddItem, handleRemoveItem: handleRemoveItem, handleSetSelected: handleSetSelected, onItemSelect: onItemSelect, renderOption: renderOption, onScroll: onScroll, onScrollToTop: onScrollToTop, onScrollToBottom: handleScrollToBottom, query: query }))] }) }));
|
|
39
49
|
};
|
|
@@ -18,8 +18,14 @@ import { MenuContext } from "./MenuContext";
|
|
|
18
18
|
import { StyledFloatContainer } from "./StyledFloatContainer";
|
|
19
19
|
import { StyledContent } from "./StyledContent";
|
|
20
20
|
import { MenuItem } from "./MenuItem";
|
|
21
|
+
import { DEFAULT_DROPDOWN_MAX_HEIGHT } from "../constants";
|
|
21
22
|
export const MenuComponent = forwardRef((_a, forwardedRef) => {
|
|
22
23
|
var { children, label, arrow, size, buttonSize, variant, buttonProps, buttonRender, multiselect, onMenuClose, dropDownProps, disabled } = _a, props = __rest(_a, ["children", "label", "arrow", "size", "buttonSize", "variant", "buttonProps", "buttonRender", "multiselect", "onMenuClose", "dropDownProps", "disabled"]);
|
|
24
|
+
const _b = dropDownProps || {}, { style: dropDownStyle } = _b, contentProps = __rest(_b, ["style"]);
|
|
25
|
+
const contentStyle = Object.assign({ height: "fit-content", maxHeight: (dropDownStyle === null || dropDownStyle === void 0 ? void 0 : dropDownStyle.maxHeight) ||
|
|
26
|
+
(dropDownStyle === null || dropDownStyle === void 0 ? void 0 : dropDownStyle.height) ||
|
|
27
|
+
(dropDownProps === null || dropDownProps === void 0 ? void 0 : dropDownProps.maxDropdownHeight) ||
|
|
28
|
+
DEFAULT_DROPDOWN_MAX_HEIGHT }, dropDownStyle);
|
|
23
29
|
const [isOpen, setIsOpen] = useState(false);
|
|
24
30
|
const [hasFocusInside, setHasFocusInside] = useState(false);
|
|
25
31
|
const [activeIndex, setActiveIndex] = useState(null);
|
|
@@ -119,5 +125,5 @@ export const MenuComponent = forwardRef((_a, forwardedRef) => {
|
|
|
119
125
|
getItemProps,
|
|
120
126
|
setHasFocusInside,
|
|
121
127
|
isOpen,
|
|
122
|
-
}, children: _jsx(FloatingList, { elementsRef: elementsRef, labelsRef: labelsRef, children: isOpen && (_jsx(FloatingPortal, { children: _jsx(FloatingFocusManager, { context: context, modal: false, initialFocus: isNested ? -1 : 0, returnFocus: !isNested, children: _jsx(StyledFloatContainer, Object.assign({ ref: refs.setFloating, className: "Menu", style: floatingStyles }, getFloatingProps(), { children: _jsx(StyledContent, Object.assign({ className: "mfFloatingContent" },
|
|
128
|
+
}, children: _jsx(FloatingList, { elementsRef: elementsRef, labelsRef: labelsRef, children: isOpen && (_jsx(FloatingPortal, { children: _jsx(FloatingFocusManager, { context: context, modal: false, initialFocus: isNested ? -1 : 0, returnFocus: !isNested, children: _jsx(StyledFloatContainer, Object.assign({ ref: refs.setFloating, className: "Menu", style: floatingStyles }, getFloatingProps(), { children: _jsx(StyledContent, Object.assign({ className: "mfFloatingContent", style: contentStyle }, contentProps, { children: children })) })) }) })) }) })] }));
|
|
123
129
|
});
|
|
@@ -26,7 +26,7 @@ export const MenuItem = styled(forwardRef((_a, forwardedRef) => {
|
|
|
26
26
|
return (_jsx(Tooltip, { content: TooltipContent ? _jsx(TooltipContent, { data: itemData }) : null, side: "left", children: _jsx(Button, Object.assign({}, props, { ref: useMergeRefs([
|
|
27
27
|
item.ref,
|
|
28
28
|
forwardedRef,
|
|
29
|
-
]), type: "button", role: "menuitem", tabIndex: isActive ? 0 : -1, disabled: disabled, justify: "start", color: props.color }, menu.getItemProps({
|
|
29
|
+
]), type: "button", role: "menuitem", tabIndex: isActive ? 0 : -1, disabled: disabled, justify: "start", color: props.color, selected: false }, menu.getItemProps({
|
|
30
30
|
onClick(event) {
|
|
31
31
|
var _a;
|
|
32
32
|
(_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, event);
|
|
@@ -49,7 +49,9 @@ export const MenuItem = styled(forwardRef((_a, forwardedRef) => {
|
|
|
49
49
|
min-height: ${({ size = "sm" }) => `${getControlSizeTokens(size).menuRowHeight}px`};
|
|
50
50
|
width: 100%;
|
|
51
51
|
min-width: 100%;
|
|
52
|
-
height: ${({ size = "sm", $dynamicHeight }) => $dynamicHeight
|
|
52
|
+
height: ${({ size = "sm", $dynamicHeight }) => $dynamicHeight
|
|
53
|
+
? "auto"
|
|
54
|
+
: `${getControlSizeTokens(size).menuRowHeight}px`};
|
|
53
55
|
box-sizing: border-box;
|
|
54
56
|
position: relative;
|
|
55
57
|
user-select: none;
|
|
@@ -22,6 +22,7 @@ import { useInfiniteQuery } from "@tanstack/react-query";
|
|
|
22
22
|
import { useDebouncedCallback } from "use-debounce";
|
|
23
23
|
import { SearchInput } from "./SearchInput";
|
|
24
24
|
import Loader from "../../Loader";
|
|
25
|
+
import { DEFAULT_DROPDOWN_MAX_HEIGHT, DROPDOWN_CONTENT_VERTICAL_PADDING, SEARCH_INPUT_MARGIN_BOTTOM, } from "../constants";
|
|
25
26
|
const getItemKey = (item) => item && typeof item === "object" && "value" in item ? item.value : item;
|
|
26
27
|
const filterMenuItems = (menuItems, searchValue) => {
|
|
27
28
|
return menuItems.filter((item) => {
|
|
@@ -128,7 +129,7 @@ const MeasuredRow = ({ children, index, setItemSize, style }) => {
|
|
|
128
129
|
}, [children, index, setItemSize]);
|
|
129
130
|
return (_jsx("div", { style: Object.assign(Object.assign({}, style), { overflow: "visible" }), children: _jsx("div", { ref: rowRef, children: children }) }));
|
|
130
131
|
};
|
|
131
|
-
export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dynamicOptionHeight, selected, TooltipContent, multiselect, enableSelectAll, enableSelectedOptionStyling, grouped, onAddNew, size, handleAddItem, handleRemoveItem, handleSetSelected, onItemSelect, renderOption, onScroll, onScrollToTop, onScrollToBottom, query, }) => {
|
|
132
|
+
export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dynamicOptionHeight, selected, TooltipContent, multiselect, enableSelectAll, enableSelectedOptionStyling, grouped, onAddNew, size, handleAddItem, handleRemoveItem, handleSetSelected, onItemSelect, renderOption, onScroll, onScrollToTop, onScrollToBottom, maxDropdownHeight = DEFAULT_DROPDOWN_MAX_HEIGHT, query, }) => {
|
|
132
133
|
const [searchValue, setSearchValue] = useState("");
|
|
133
134
|
const _a = query !== null && query !== void 0 ? query : {}, { queryKey, queryFn, getNextPageParam, initialPageParam } = _a, rest = __rest(_a, ["queryKey", "queryFn", "getNextPageParam", "initialPageParam"]);
|
|
134
135
|
const targetElm = useRef(null);
|
|
@@ -253,16 +254,25 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
253
254
|
const getDynamicItemSize = (index) => {
|
|
254
255
|
var _a;
|
|
255
256
|
return itemSizeMap.current[index] ||
|
|
256
|
-
(((_a = displayItems[index]) === null || _a === void 0 ? void 0 : _a._isGroupHeader)
|
|
257
|
+
(((_a = displayItems[index]) === null || _a === void 0 ? void 0 : _a._isGroupHeader)
|
|
258
|
+
? itemHeight
|
|
259
|
+
: estimatedDynamicItemHeight);
|
|
257
260
|
};
|
|
258
261
|
const estimatedHeight = dynamicListEnabled
|
|
259
262
|
? displayItems.reduce((total, _, index) => total + getDynamicItemSize(index), 0)
|
|
260
263
|
: itemCount * itemHeight;
|
|
261
|
-
const
|
|
262
|
-
?
|
|
263
|
-
:
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
const searchHeight = searchable
|
|
265
|
+
? sizeTokens.height + SEARCH_INPUT_MARGIN_BOTTOM
|
|
266
|
+
: 0;
|
|
267
|
+
const selectAllHeight = multiselect && enableSelectAll && selectableItems.length > 0
|
|
268
|
+
? itemHeight
|
|
269
|
+
: 0;
|
|
270
|
+
const maxListHeight = Math.max(itemHeight, maxDropdownHeight -
|
|
271
|
+
DROPDOWN_CONTENT_VERTICAL_PADDING -
|
|
272
|
+
searchHeight -
|
|
273
|
+
selectAllHeight);
|
|
274
|
+
const availableHeight = viewPortDimensions.height || maxListHeight;
|
|
275
|
+
const height = Math.min(estimatedHeight, availableHeight, maxListHeight);
|
|
266
276
|
const width = "100%";
|
|
267
277
|
useLayoutEffect(() => {
|
|
268
278
|
const target = targetElm.current;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef } from "react";
|
|
3
3
|
import Input from "../../Input";
|
|
4
|
-
|
|
4
|
+
import { SEARCH_INPUT_MARGIN_BOTTOM } from "../constants";
|
|
5
|
+
export const SearchInput = forwardRef((props, ref) => (_jsx(Input, Object.assign({ ref: ref, style: { marginBottom: SEARCH_INPUT_MARGIN_BOTTOM } }, props))));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import styled from "styled-components";
|
|
2
|
+
import { DEFAULT_DROPDOWN_MAX_HEIGHT, DROPDOWN_CONTENT_PADDING, } from "../constants";
|
|
2
3
|
export const StyledContent = styled.div `
|
|
3
4
|
position: relative;
|
|
4
5
|
display: flex;
|
|
@@ -11,7 +12,7 @@ export const StyledContent = styled.div `
|
|
|
11
12
|
max-width: 400px;
|
|
12
13
|
max-height: ${({ maxDropdownHeight }) => Number.isInteger(maxDropdownHeight)
|
|
13
14
|
? `${maxDropdownHeight}px`
|
|
14
|
-
: maxDropdownHeight ||
|
|
15
|
+
: maxDropdownHeight || `${DEFAULT_DROPDOWN_MAX_HEIGHT}px`};
|
|
15
16
|
|
|
16
17
|
background-color: ${(props) => props.theme.palette.background.default};
|
|
17
18
|
background-color: ${({ theme, variant }) => {
|
|
@@ -30,7 +31,7 @@ export const StyledContent = styled.div `
|
|
|
30
31
|
border-radius: 5px;
|
|
31
32
|
border: 1px solid ${(props) => props.theme.palette.divider};
|
|
32
33
|
outline: none;
|
|
33
|
-
padding:
|
|
34
|
+
padding: ${DROPDOWN_CONTENT_PADDING}px;
|
|
34
35
|
animation-duration: 400ms;
|
|
35
36
|
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
36
37
|
will-change: transform, opacity;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Operator } from "./types";
|
|
2
|
+
export declare const Operators: {
|
|
3
|
+
Equals: {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
};
|
|
7
|
+
NotEquals: {
|
|
8
|
+
value: string;
|
|
9
|
+
label: string;
|
|
10
|
+
};
|
|
11
|
+
LessThan: {
|
|
12
|
+
value: string;
|
|
13
|
+
label: string;
|
|
14
|
+
};
|
|
15
|
+
GreaterThan: {
|
|
16
|
+
value: string;
|
|
17
|
+
label: string;
|
|
18
|
+
};
|
|
19
|
+
LessThanOrEqual: {
|
|
20
|
+
value: string;
|
|
21
|
+
label: string;
|
|
22
|
+
};
|
|
23
|
+
GreaterThanOrEqual: {
|
|
24
|
+
value: string;
|
|
25
|
+
label: string;
|
|
26
|
+
};
|
|
27
|
+
Contains: {
|
|
28
|
+
value: string;
|
|
29
|
+
label: string;
|
|
30
|
+
};
|
|
31
|
+
BeginsWith: {
|
|
32
|
+
value: string;
|
|
33
|
+
label: string;
|
|
34
|
+
};
|
|
35
|
+
EndsWith: {
|
|
36
|
+
value: string;
|
|
37
|
+
label: string;
|
|
38
|
+
};
|
|
39
|
+
DoesNotContain: {
|
|
40
|
+
value: string;
|
|
41
|
+
label: string;
|
|
42
|
+
};
|
|
43
|
+
DoesNotBeginWith: {
|
|
44
|
+
value: string;
|
|
45
|
+
label: string;
|
|
46
|
+
};
|
|
47
|
+
DoesNotEndWith: {
|
|
48
|
+
value: string;
|
|
49
|
+
label: string;
|
|
50
|
+
};
|
|
51
|
+
IsEmpty: {
|
|
52
|
+
value: string;
|
|
53
|
+
label: string;
|
|
54
|
+
};
|
|
55
|
+
IsNotEmpty: {
|
|
56
|
+
value: string;
|
|
57
|
+
label: string;
|
|
58
|
+
};
|
|
59
|
+
In: {
|
|
60
|
+
value: string;
|
|
61
|
+
label: string;
|
|
62
|
+
};
|
|
63
|
+
NIn: {
|
|
64
|
+
value: string;
|
|
65
|
+
label: string;
|
|
66
|
+
};
|
|
67
|
+
Between: {
|
|
68
|
+
value: string;
|
|
69
|
+
label: string;
|
|
70
|
+
};
|
|
71
|
+
NotBetween: {
|
|
72
|
+
value: string;
|
|
73
|
+
label: string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
export declare const DefaultOperators: Operator[];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const Operators = {
|
|
2
|
+
Equals: { value: "=", label: "is" },
|
|
3
|
+
NotEquals: { value: "!=", label: "is not" },
|
|
4
|
+
LessThan: { value: "<", label: "less than" },
|
|
5
|
+
GreaterThan: { value: ">", label: "greater than" },
|
|
6
|
+
LessThanOrEqual: { value: "<=", label: "less than or equal" },
|
|
7
|
+
GreaterThanOrEqual: { value: ">=", label: "greater than or equal" },
|
|
8
|
+
Contains: { value: "contains", label: "contains" },
|
|
9
|
+
BeginsWith: { value: "beginsWith", label: "begins with" },
|
|
10
|
+
EndsWith: { value: "endsWith", label: "ends with" },
|
|
11
|
+
DoesNotContain: { value: "doesNotContain", label: "does not contain" },
|
|
12
|
+
DoesNotBeginWith: { value: "doesNotBeginWith", label: "does not begin with" },
|
|
13
|
+
DoesNotEndWith: { value: "doesNotEndWith", label: "does not end with" },
|
|
14
|
+
IsEmpty: { value: "isEmpty", label: "is empty" },
|
|
15
|
+
IsNotEmpty: { value: "isNotEmpty", label: "is not empty" },
|
|
16
|
+
In: { value: "in", label: "is any of" },
|
|
17
|
+
NIn: { value: "nin", label: "is none of" },
|
|
18
|
+
Between: { value: "between", label: "between" },
|
|
19
|
+
NotBetween: { value: "notBetween", label: "not between" },
|
|
20
|
+
};
|
|
21
|
+
export const DefaultOperators = Object.values(Operators);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { DropDownItem, DropDownMenuProps } from "../DropDownMenu";
|
|
2
|
+
export interface UseQueryFilterProps {
|
|
3
|
+
defaultFilter?: Query | null;
|
|
4
|
+
/**
|
|
5
|
+
* Filter definitions for the available fields. Pass `undefined` while the
|
|
6
|
+
* definitions are still loading (e.g. async fetch in flight) — any rules
|
|
7
|
+
* already in state will render nothing until definitions resolve. An empty
|
|
8
|
+
* array means "loaded, no definitions": every rule will render as an
|
|
9
|
+
* orphan chip and `onUnknownField` will fire for each.
|
|
10
|
+
*/
|
|
11
|
+
filterDefinitions: FilterDefinition[] | undefined;
|
|
12
|
+
showCombinator?: boolean;
|
|
13
|
+
onFilterChange?: (filter: any) => void;
|
|
14
|
+
onUnknownField?: (rule: Rule) => void;
|
|
15
|
+
}
|
|
16
|
+
export type QueryFilterType = {
|
|
17
|
+
filter: Query;
|
|
18
|
+
filterDefinitions: FilterDefinition[] | undefined;
|
|
19
|
+
showCombinator?: boolean;
|
|
20
|
+
addRule: (rule: Rule) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Remove a rule by `id` (preferred) or by passing the `Rule` object. The
|
|
23
|
+
* object form falls back to reference equality when `rule.id` is missing,
|
|
24
|
+
* so chips for un-normalized orphan rules can still delete themselves.
|
|
25
|
+
*/
|
|
26
|
+
removeRule: (target: string | Rule) => void;
|
|
27
|
+
updateRule: (rule: Rule) => void;
|
|
28
|
+
updateRootCombinator: (combinator: Combinator) => void;
|
|
29
|
+
onUnknownField?: (rule: Rule) => void;
|
|
30
|
+
};
|
|
31
|
+
export type UseQueryFilter = (args: UseQueryFilterProps) => QueryFilterType;
|
|
32
|
+
export type Combinator = "and" | "or";
|
|
33
|
+
export type Operator = {
|
|
34
|
+
label: string;
|
|
35
|
+
value: string;
|
|
36
|
+
};
|
|
37
|
+
export type InputType = "text" | "number" | "date" | "datetime" | "multiselect";
|
|
38
|
+
export interface FilterDefinition {
|
|
39
|
+
dataField: string;
|
|
40
|
+
label: string;
|
|
41
|
+
pluralLabel?: string;
|
|
42
|
+
operators?: Operator[];
|
|
43
|
+
inputType?: InputType;
|
|
44
|
+
resolution?: "day" | "second" | "millisecond";
|
|
45
|
+
isoString?: boolean;
|
|
46
|
+
placeholder?: string;
|
|
47
|
+
selectOptions?: DropDownItem[];
|
|
48
|
+
dropDownOptions?: {
|
|
49
|
+
style?: React.CSSProperties;
|
|
50
|
+
};
|
|
51
|
+
query?: DropDownMenuProps["query"];
|
|
52
|
+
}
|
|
53
|
+
export interface Rule {
|
|
54
|
+
id?: string;
|
|
55
|
+
dataField: string;
|
|
56
|
+
value?: string[];
|
|
57
|
+
options?: DropDownItem[];
|
|
58
|
+
operator: Operator;
|
|
59
|
+
label: string;
|
|
60
|
+
}
|
|
61
|
+
export interface RuleGroup {
|
|
62
|
+
rules: Rule[];
|
|
63
|
+
combinator: Combinator;
|
|
64
|
+
}
|
|
65
|
+
export interface Query extends RuleGroup {
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -16,6 +16,7 @@ export declare enum Controls {
|
|
|
16
16
|
HEADING_4 = "heading_4",
|
|
17
17
|
BULLET_LIST = "bulletList",
|
|
18
18
|
ORDERED_LIST = "orderedList",
|
|
19
|
+
TASK_LIST = "taskList",
|
|
19
20
|
TEXT_ALIGN_LEFT = "textAlignLeft",
|
|
20
21
|
TEXT_ALIGN_CENTER = "textAlignCenter",
|
|
21
22
|
TEXT_ALIGN_RIGHT = "textAlignRight",
|
|
@@ -17,6 +17,7 @@ export var Controls;
|
|
|
17
17
|
Controls["HEADING_4"] = "heading_4";
|
|
18
18
|
Controls["BULLET_LIST"] = "bulletList";
|
|
19
19
|
Controls["ORDERED_LIST"] = "orderedList";
|
|
20
|
+
Controls["TASK_LIST"] = "taskList";
|
|
20
21
|
Controls["TEXT_ALIGN_LEFT"] = "textAlignLeft";
|
|
21
22
|
Controls["TEXT_ALIGN_CENTER"] = "textAlignCenter";
|
|
22
23
|
Controls["TEXT_ALIGN_RIGHT"] = "textAlignRight";
|
|
@@ -15,6 +15,7 @@ export var Extensions;
|
|
|
15
15
|
Extensions["Strike"] = "strike";
|
|
16
16
|
Extensions["BulletList"] = "bulletList";
|
|
17
17
|
Extensions["OrderedList"] = "orderedList";
|
|
18
|
+
Extensions["TaskList"] = "taskList";
|
|
18
19
|
Extensions["AlignLeft"] = "alignLeft";
|
|
19
20
|
Extensions["AlignCenter"] = "alignCenter";
|
|
20
21
|
Extensions["AlignRight"] = "alignRight";
|
|
@@ -6,6 +6,7 @@ var Fonts;
|
|
|
6
6
|
Fonts["TIMES_NEW_ROMAN"] = "Times New Roman";
|
|
7
7
|
Fonts["SEGOE_UI"] = "Segoe UI";
|
|
8
8
|
Fonts["ROBOTO"] = "Roboto";
|
|
9
|
-
Fonts["
|
|
9
|
+
Fonts["VERDANA"] = "Verdana";
|
|
10
|
+
Fonts["CAMBRIA"] = "Cambria";
|
|
10
11
|
})(Fonts || (Fonts = {}));
|
|
11
12
|
export default Fonts;
|
|
@@ -7,6 +7,7 @@ export var SlashCommands;
|
|
|
7
7
|
SlashCommands["Heading4"] = "Heading 4";
|
|
8
8
|
SlashCommands["BulletList"] = "Bullet List";
|
|
9
9
|
SlashCommands["NumberedList"] = "Numbered List";
|
|
10
|
+
SlashCommands["TaskList"] = "Task List";
|
|
10
11
|
SlashCommands["Code"] = "Code";
|
|
11
12
|
SlashCommands["CodeBlock"] = "Code Block";
|
|
12
13
|
SlashCommands["HorizontalRule"] = "Horizontal Rule";
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { Extension, isNodeSelection, isTextSelection, posToDOMRect, } from "@tiptap/core";
|
|
2
|
+
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
3
|
+
import { ReactRenderer } from "@tiptap/react";
|
|
4
|
+
import BubbleMenuComponent from "../Components/BubbleMenu";
|
|
5
|
+
class Menu {
|
|
6
|
+
constructor({ view, editor, customMenuItems, }) {
|
|
7
|
+
this.mousedownHandler = (event) => {
|
|
8
|
+
this.preventShow = true;
|
|
9
|
+
};
|
|
10
|
+
this.mouseUpHandler = (event) => {
|
|
11
|
+
this.preventShow = false;
|
|
12
|
+
this.update(this.editor.view);
|
|
13
|
+
};
|
|
14
|
+
this.focusHandler = () => {
|
|
15
|
+
// this.editor.commands.setTextSelection({ from: 0, to: 0 });
|
|
16
|
+
// we use `setTimeout` to make sure `selection` is already updated
|
|
17
|
+
setTimeout(() => this.update(this.editor.view));
|
|
18
|
+
};
|
|
19
|
+
this.blurHandler = ({ event }) => {
|
|
20
|
+
var _a;
|
|
21
|
+
if (this.preventShow) {
|
|
22
|
+
this.preventShow = false;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if ((event === null || event === void 0 ? void 0 : event.relatedTarget) &&
|
|
26
|
+
((_a = this.floating) === null || _a === void 0 ? void 0 : _a.contains(event === null || event === void 0 ? void 0 : event.relatedTarget))) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// clear text selection
|
|
30
|
+
// this.editor.commands.setTextSelection({ from: 0, to: 0 });
|
|
31
|
+
this.hide();
|
|
32
|
+
};
|
|
33
|
+
this.editor = editor;
|
|
34
|
+
this.view = view;
|
|
35
|
+
this.rect = null;
|
|
36
|
+
this.preventShow = false;
|
|
37
|
+
this.floating = null;
|
|
38
|
+
this.isOpen = false;
|
|
39
|
+
// create and mount react component
|
|
40
|
+
if (!this.component) {
|
|
41
|
+
this.component = new ReactRenderer(BubbleMenuComponent, {
|
|
42
|
+
props: {
|
|
43
|
+
editor: this.editor,
|
|
44
|
+
open: false,
|
|
45
|
+
onOpen: (ref) => {
|
|
46
|
+
this.floating = ref;
|
|
47
|
+
},
|
|
48
|
+
customMenuItems,
|
|
49
|
+
},
|
|
50
|
+
editor: this.editor,
|
|
51
|
+
});
|
|
52
|
+
document.body.appendChild(this.component.element);
|
|
53
|
+
}
|
|
54
|
+
// don't show the bubble during selection of text
|
|
55
|
+
this.view.dom.addEventListener("mousedown", this.mousedownHandler, {
|
|
56
|
+
capture: true,
|
|
57
|
+
});
|
|
58
|
+
this.view.dom.addEventListener("mouseup", this.mouseUpHandler);
|
|
59
|
+
this.editor.on("blur", this.blurHandler);
|
|
60
|
+
this.editor.on("focus", this.focusHandler);
|
|
61
|
+
}
|
|
62
|
+
update(view, oldState) {
|
|
63
|
+
var _a;
|
|
64
|
+
const { state, composing } = view;
|
|
65
|
+
const { doc, selection } = state;
|
|
66
|
+
const { empty, ranges } = selection;
|
|
67
|
+
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
|
68
|
+
const to = Math.max(...ranges.map((range) => range.$to.pos));
|
|
69
|
+
const selectionChanged = !(oldState === null || oldState === void 0 ? void 0 : oldState.selection.eq(view.state.selection));
|
|
70
|
+
const docChanged = !(oldState === null || oldState === void 0 ? void 0 : oldState.doc.eq(view.state.doc));
|
|
71
|
+
const isSame = !selectionChanged && !docChanged;
|
|
72
|
+
if (composing || isSame) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Sometime check for `empty` is not enough.
|
|
76
|
+
// Doubleclick an empty paragraph returns a node size of 2.
|
|
77
|
+
// So we check also for an empty text size.
|
|
78
|
+
const isEmptyTextBlock = !doc.textBetween(from, to).length && isTextSelection(state.selection);
|
|
79
|
+
// When clicking on a element inside the bubble menu the editor "blur" event
|
|
80
|
+
// is called and the bubble menu item is focussed. In this case we should
|
|
81
|
+
// consider the menu as part of the editor and keep showing the menu
|
|
82
|
+
const isChildOfMenu = (_a = this === null || this === void 0 ? void 0 : this.floating) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);
|
|
83
|
+
const hasEditorFocus = view.hasFocus() || isChildOfMenu;
|
|
84
|
+
if (!hasEditorFocus ||
|
|
85
|
+
empty ||
|
|
86
|
+
isEmptyTextBlock ||
|
|
87
|
+
!this.editor.isEditable ||
|
|
88
|
+
this.preventShow) {
|
|
89
|
+
this.hide();
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// only set position when it is not already open
|
|
93
|
+
// otherwise the menu will jump around when the selection changes or text formatting is applied
|
|
94
|
+
if (!this.isOpen) {
|
|
95
|
+
if (isNodeSelection(state.selection)) {
|
|
96
|
+
let node = view.nodeDOM(from);
|
|
97
|
+
const nodeViewWrapper = node.dataset.nodeViewWrapper
|
|
98
|
+
? node
|
|
99
|
+
: node.querySelector("[data-node-view-wrapper]");
|
|
100
|
+
if (nodeViewWrapper) {
|
|
101
|
+
node = nodeViewWrapper.firstChild;
|
|
102
|
+
}
|
|
103
|
+
if (node) {
|
|
104
|
+
this.rect = node.getBoundingClientRect();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this.rect = posToDOMRect(view, from, to);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
this.show();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
show() {
|
|
115
|
+
if (this.component) {
|
|
116
|
+
this.component.updateProps({ open: true, rect: this.rect });
|
|
117
|
+
this.isOpen = true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
hide() {
|
|
121
|
+
if (this.component) {
|
|
122
|
+
this.component.updateProps({ open: false, rect: null });
|
|
123
|
+
this.isOpen = false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
destroy() {
|
|
127
|
+
if (this.component) {
|
|
128
|
+
this.view.dom.removeEventListener("mousedown", this.mousedownHandler);
|
|
129
|
+
this.view.dom.removeEventListener("mouseup", this.mouseUpHandler);
|
|
130
|
+
this.component.destroy();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const BubbleMenu = Extension.create({
|
|
135
|
+
name: "bubbleMenu",
|
|
136
|
+
addOptions() {
|
|
137
|
+
return {
|
|
138
|
+
bubbleMenuOptions: {},
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
addProseMirrorPlugins() {
|
|
142
|
+
return [
|
|
143
|
+
new Plugin({
|
|
144
|
+
key: new PluginKey("bubbleMenu"),
|
|
145
|
+
view: (view) => {
|
|
146
|
+
var _a;
|
|
147
|
+
return new Menu({
|
|
148
|
+
view,
|
|
149
|
+
editor: this.editor,
|
|
150
|
+
customMenuItems: ((_a = this === null || this === void 0 ? void 0 : this.options) === null || _a === void 0 ? void 0 : _a.customMenuItems) || [],
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
}),
|
|
154
|
+
];
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
export default BubbleMenu;
|
|
@@ -11,7 +11,7 @@ import { Extension } from "@tiptap/core";
|
|
|
11
11
|
import Suggestion from "@tiptap/suggestion";
|
|
12
12
|
import { ReactRenderer } from "@tiptap/react";
|
|
13
13
|
import tippy from "tippy.js";
|
|
14
|
-
import { Heading1, Heading2, Heading3, Heading4, List, ListOrdered, Text, TextQuote, Image as ImageIcon, Calendar, CodeIcon, ClockIcon, SeparatorHorizontalIcon, SquareCodeIcon, Table2Icon, } from "lucide-react";
|
|
14
|
+
import { Heading1, Heading2, Heading3, Heading4, List, ListOrdered, Text, TextQuote, Image as ImageIcon, Calendar, CodeIcon, ClockIcon, ListChecksIcon, SeparatorHorizontalIcon, SquareCodeIcon, Table2Icon, } from "lucide-react";
|
|
15
15
|
import { startImageUpload, } from "../Plugins/UploadImagesPlugin.js";
|
|
16
16
|
import { PluginKey } from "@tiptap/pm/state";
|
|
17
17
|
import SlashCommandList from "./SlashCommandList";
|
|
@@ -116,6 +116,15 @@ const getCommandItems = (values, options) => {
|
|
|
116
116
|
editor.chain().focus().deleteRange(range).toggleOrderedList().run();
|
|
117
117
|
},
|
|
118
118
|
},
|
|
119
|
+
{
|
|
120
|
+
title: SlashCommands.TaskList,
|
|
121
|
+
description: "Create a checklist with tasks.",
|
|
122
|
+
searchTerms: ["todo", "checklist", "checkbox"],
|
|
123
|
+
icon: ListChecksIcon,
|
|
124
|
+
command: ({ editor, range }) => {
|
|
125
|
+
editor.chain().focus().deleteRange(range).toggleTaskList().run();
|
|
126
|
+
},
|
|
127
|
+
},
|
|
119
128
|
{
|
|
120
129
|
title: SlashCommands.Code,
|
|
121
130
|
description: "Start typing inline code.",
|
|
@@ -4,6 +4,8 @@ import { CodeBlockLowlight } from "@tiptap/extension-code-block-lowlight";
|
|
|
4
4
|
import HorizontalRule from "@tiptap/extension-horizontal-rule";
|
|
5
5
|
import TextAlign from "@tiptap/extension-text-align";
|
|
6
6
|
import { Table, TableCell, TableHeader, TableRow, } from "@tiptap/extension-table";
|
|
7
|
+
import TaskList from "@tiptap/extension-task-list";
|
|
8
|
+
import TaskItem from "@tiptap/extension-task-item";
|
|
7
9
|
import { Focus, Placeholder } from "@tiptap/extensions";
|
|
8
10
|
import { Color } from "@tiptap/extension-color";
|
|
9
11
|
import { Highlight } from "@tiptap/extension-highlight";
|
|
@@ -89,6 +91,7 @@ export const MINIMAL_EXTENSIONS = [
|
|
|
89
91
|
export const FULL_EXTENSIONS = [
|
|
90
92
|
...BASIC_EXTENSIONS,
|
|
91
93
|
Extensions.CodeBlock,
|
|
94
|
+
Extensions.TaskList,
|
|
92
95
|
Extensions.Table,
|
|
93
96
|
Extensions.TableCell,
|
|
94
97
|
Extensions.TableHeader,
|
|
@@ -269,6 +272,16 @@ const getTipTapExtensions = ({ disabledExtensions = [], extensions = [], slashCo
|
|
|
269
272
|
name: Extensions.TableCell,
|
|
270
273
|
extension: TableCell,
|
|
271
274
|
},
|
|
275
|
+
{
|
|
276
|
+
name: Extensions.TaskList,
|
|
277
|
+
extension: TaskList,
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: "taskItem",
|
|
281
|
+
extension: TaskItem.configure({
|
|
282
|
+
nested: true,
|
|
283
|
+
}),
|
|
284
|
+
},
|
|
272
285
|
{
|
|
273
286
|
name: Extensions.Image,
|
|
274
287
|
extension: CustomImage.configure({
|
|
@@ -314,6 +327,8 @@ const getTipTapExtensions = ({ disabledExtensions = [], extensions = [], slashCo
|
|
|
314
327
|
.filter((ext) => {
|
|
315
328
|
if (ext.name === "starterKit")
|
|
316
329
|
return true;
|
|
330
|
+
if (ext.name === "taskItem")
|
|
331
|
+
return isEnabled(Extensions.TaskList);
|
|
317
332
|
return isEnabled(ext.name);
|
|
318
333
|
})
|
|
319
334
|
.map((ext) => ext.extension);
|
|
@@ -26,6 +26,7 @@ import Fonts from "./Enums/Fonts";
|
|
|
26
26
|
import RichTextEditorContext from "./Contexts/RichTextEditorContext";
|
|
27
27
|
import { getLinkAttributesAtPosition, getLinkRangeAtPosition, openLink, } from "./Utils/linkUtils";
|
|
28
28
|
import { TABLE_CELL_MIN_WIDTH } from "./Utils/tableUtils";
|
|
29
|
+
import { getControlSizeTokens } from "../core";
|
|
29
30
|
const codeBlockFallbacks = {
|
|
30
31
|
light: {
|
|
31
32
|
background: "#f6f8fa",
|
|
@@ -74,6 +75,7 @@ const codeBlockFallbacks = {
|
|
|
74
75
|
},
|
|
75
76
|
},
|
|
76
77
|
};
|
|
78
|
+
const TASK_CHECKBOX_SIZE = getControlSizeTokens("sm").checkboxIconSize;
|
|
77
79
|
const getCodeBlockTheme = (theme) => {
|
|
78
80
|
if (theme.palette.codeBlock)
|
|
79
81
|
return theme.palette.codeBlock;
|
|
@@ -322,6 +324,10 @@ const StyledContent = styled.div `
|
|
|
322
324
|
font-family: Roboto, sans-serif;
|
|
323
325
|
}
|
|
324
326
|
|
|
327
|
+
.editor-content[data-font="Cambria"] {
|
|
328
|
+
font-family: Cambria, Georgia, "Times New Roman", serif;
|
|
329
|
+
}
|
|
330
|
+
|
|
325
331
|
.ProseMirror {
|
|
326
332
|
font-size: 14px;
|
|
327
333
|
font-weight: 400;
|
|
@@ -758,59 +764,77 @@ const StyledContent = styled.div `
|
|
|
758
764
|
|
|
759
765
|
ul[data-type="taskList"] {
|
|
760
766
|
list-style: none;
|
|
767
|
+
margin: 0.25rem 0;
|
|
761
768
|
padding: 0;
|
|
762
769
|
|
|
763
770
|
li {
|
|
764
771
|
display: flex;
|
|
765
|
-
align-items:
|
|
772
|
+
align-items: flex-start;
|
|
766
773
|
margin: 0.25rem 0;
|
|
767
774
|
|
|
768
775
|
> label {
|
|
776
|
+
display: inline-flex;
|
|
777
|
+
align-items: center;
|
|
778
|
+
justify-content: center;
|
|
769
779
|
flex: 0 0 auto;
|
|
780
|
+
height: 1.5rem;
|
|
770
781
|
margin-right: 0.5rem;
|
|
771
782
|
user-select: none;
|
|
772
783
|
}
|
|
773
784
|
|
|
774
785
|
> div {
|
|
775
786
|
flex: 1 1 auto;
|
|
787
|
+
min-width: 0;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
> div > ul[data-type="taskList"] {
|
|
791
|
+
margin: 0.25rem 0 0;
|
|
776
792
|
}
|
|
777
793
|
}
|
|
778
794
|
|
|
779
795
|
input[type="checkbox"] {
|
|
780
|
-
cursor: pointer;
|
|
781
|
-
margin: 0;
|
|
782
796
|
-webkit-appearance: none;
|
|
783
797
|
appearance: none;
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
798
|
+
position: relative;
|
|
799
|
+
display: inline-flex;
|
|
800
|
+
align-items: center;
|
|
801
|
+
justify-content: center;
|
|
802
|
+
box-sizing: border-box;
|
|
803
|
+
width: ${TASK_CHECKBOX_SIZE}px;
|
|
804
|
+
height: ${TASK_CHECKBOX_SIZE}px;
|
|
805
|
+
margin: 0;
|
|
806
|
+
border: 1px solid ${({ theme }) => theme.palette.text.secondary};
|
|
807
|
+
border-radius: 2px;
|
|
808
|
+
background-color: transparent;
|
|
809
|
+
cursor: pointer;
|
|
810
|
+
|
|
811
|
+
&::after {
|
|
812
|
+
content: "";
|
|
813
|
+
position: absolute;
|
|
814
|
+
left: 50%;
|
|
815
|
+
top: 45%;
|
|
816
|
+
width: 32%;
|
|
817
|
+
height: 56%;
|
|
818
|
+
border: solid
|
|
819
|
+
${({ theme }) => (theme.name === "DARK" ? "#000000" : "#ffffff")};
|
|
820
|
+
border-width: 0 2px 2px 0;
|
|
821
|
+
opacity: 0;
|
|
822
|
+
transform: translate(-50%, -50%) rotate(45deg);
|
|
823
|
+
transform-origin: center;
|
|
794
824
|
}
|
|
795
825
|
|
|
796
|
-
&:
|
|
797
|
-
background-color: ${({ theme }) => theme.
|
|
826
|
+
&:checked {
|
|
827
|
+
background-color: ${({ theme }) => theme.name === "DARK" ? "#cdcdcd" : "#646464"};
|
|
828
|
+
border-color: ${({ theme }) => theme.name === "DARK" ? "#cdcdcd" : "#646464"};
|
|
798
829
|
}
|
|
799
830
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
width: 0.75em;
|
|
803
|
-
height: 0.75em;
|
|
804
|
-
transform: scale(0);
|
|
805
|
-
transition: 120ms transform ease-in-out;
|
|
806
|
-
box-shadow: inset 1em 1em;
|
|
807
|
-
transform-origin: center;
|
|
808
|
-
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
|
|
809
|
-
color: ${({ theme }) => theme.palette.text.primary};
|
|
831
|
+
&:checked::after {
|
|
832
|
+
opacity: 1;
|
|
810
833
|
}
|
|
811
834
|
|
|
812
|
-
&:
|
|
813
|
-
|
|
835
|
+
&:focus-visible {
|
|
836
|
+
outline: 2px solid ${({ theme }) => theme.palette.primary.main}40;
|
|
837
|
+
outline-offset: 2px;
|
|
814
838
|
}
|
|
815
839
|
}
|
|
816
840
|
}
|
|
@@ -856,6 +880,9 @@ export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = ""
|
|
|
856
880
|
if (command === SlashCommands.Table) {
|
|
857
881
|
return resolvedExtensionSet.has(Extensions.Table);
|
|
858
882
|
}
|
|
883
|
+
if (command === SlashCommands.TaskList) {
|
|
884
|
+
return resolvedExtensionSet.has(Extensions.TaskList);
|
|
885
|
+
}
|
|
859
886
|
return true;
|
|
860
887
|
}), [resolvedExtensionSet, slashCommands]);
|
|
861
888
|
const resolvedToolbarOptions = useMemo(() => {
|
|
@@ -872,6 +899,7 @@ export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = ""
|
|
|
872
899
|
[Controls.HORIZONTAL_RULE]: Extensions.HorizontalRule,
|
|
873
900
|
[Controls.BULLET_LIST]: Extensions.BulletList,
|
|
874
901
|
[Controls.ORDERED_LIST]: Extensions.OrderedList,
|
|
902
|
+
[Controls.TASK_LIST]: Extensions.TaskList,
|
|
875
903
|
[Controls.COLOR]: Extensions.Color,
|
|
876
904
|
[Controls.HIGHLIGHT]: Extensions.Highlight,
|
|
877
905
|
[Controls.LINK]: Extensions.Link,
|
|
@@ -2,6 +2,9 @@ import { Editor } from "@tiptap/react";
|
|
|
2
2
|
interface ControlProps {
|
|
3
3
|
editor: Editor | null;
|
|
4
4
|
}
|
|
5
|
+
export type HeadingLevel = 1 | 2 | 3 | 4;
|
|
6
|
+
export type TextAlignment = "left" | "center" | "right" | "justify";
|
|
7
|
+
export type ListType = "bullet" | "ordered" | "task";
|
|
5
8
|
export declare const UndoControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
9
|
export declare const RedoControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
10
|
export declare const FontControl: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -20,10 +23,20 @@ export declare const Heading1Control: ({ editor }: ControlProps) => import("reac
|
|
|
20
23
|
export declare const Heading2Control: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
24
|
export declare const Heading3Control: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
25
|
export declare const Heading4Control: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export declare const HeadingControl: ({ editor, levels, }: ControlProps & {
|
|
27
|
+
levels?: HeadingLevel[];
|
|
28
|
+
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
23
29
|
export declare const BulletListControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
24
30
|
export declare const OrderedListControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare const TaskListControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
export declare const ListControl: ({ editor, listTypes, }: ControlProps & {
|
|
33
|
+
listTypes?: ListType[];
|
|
34
|
+
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
25
35
|
export declare const AlignLeftControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
26
36
|
export declare const AlignRightControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
27
37
|
export declare const AlignCenterControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
28
38
|
export declare const AlignJustifiedControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
export declare const AlignmentControl: ({ editor, alignments, }: ControlProps & {
|
|
40
|
+
alignments?: TextAlignment[];
|
|
41
|
+
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
29
42
|
export {};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { IconBold, IconItalic, IconUnderline, IconStrikethrough, IconH1, IconH2, IconH3, IconH4, IconList, IconListNumbers, IconAlignLeft, IconAlignRight, IconAlignCenter, IconAlignJustified, IconCornerUpLeft, IconCornerUpRight, IconBlockquote, IconSeparatorHorizontal, } from "@tabler/icons-react";
|
|
3
|
-
import { CodeIcon, HighlighterIcon, PaletteIcon, RemoveFormattingIcon, SquircleIcon, TypeIcon, } from "lucide-react";
|
|
4
|
-
import { SquareCodeIcon } from "lucide-react";
|
|
2
|
+
import { IconBold, IconItalic, IconUnderline, IconStrikethrough, IconH1, IconH2, IconH3, IconH4, IconHeading, IconList, IconListNumbers, IconAlignLeft, IconAlignRight, IconAlignCenter, IconAlignJustified, IconCornerUpLeft, IconCornerUpRight, IconBlockquote, IconSeparatorHorizontal, } from "@tabler/icons-react";
|
|
3
|
+
import { CodeIcon, HighlighterIcon, ListChecksIcon, PaletteIcon, RemoveFormattingIcon, SquareCodeIcon, SquircleIcon, TypeIcon, } from "lucide-react";
|
|
5
4
|
import { Control } from "./Control";
|
|
6
5
|
import { hasInlineCode, toggleInlineCode } from "../Utils/codeUtils";
|
|
7
6
|
import { hasSyntaxHighlightedCodeBlock, toggleCodeBlock, } from "../Utils/codeBlockUtils";
|
|
@@ -12,6 +11,38 @@ import RichTextEditorContext from "../Contexts/RichTextEditorContext";
|
|
|
12
11
|
import Fonts from "../Enums/Fonts";
|
|
13
12
|
import TextColors from "../Enums/TextColors";
|
|
14
13
|
import HighlightColors from "../Enums/HighlightColors";
|
|
14
|
+
const headingControlOptions = [
|
|
15
|
+
{ level: 1, label: "Heading 1", icon: IconH1 },
|
|
16
|
+
{ level: 2, label: "Heading 2", icon: IconH2 },
|
|
17
|
+
{ level: 3, label: "Heading 3", icon: IconH3 },
|
|
18
|
+
{ level: 4, label: "Heading 4", icon: IconH4 },
|
|
19
|
+
];
|
|
20
|
+
const alignmentControlOptions = [
|
|
21
|
+
{ value: "left", label: "Align text: left", icon: IconAlignLeft },
|
|
22
|
+
{ value: "center", label: "Align text: center", icon: IconAlignCenter },
|
|
23
|
+
{ value: "right", label: "Align text: right", icon: IconAlignRight },
|
|
24
|
+
{ value: "justify", label: "Align text: justify", icon: IconAlignJustified },
|
|
25
|
+
];
|
|
26
|
+
const listControlOptions = [
|
|
27
|
+
{
|
|
28
|
+
value: "bullet",
|
|
29
|
+
label: "Bullet list",
|
|
30
|
+
nodeName: "bulletList",
|
|
31
|
+
icon: IconList,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
value: "ordered",
|
|
35
|
+
label: "Ordered list",
|
|
36
|
+
nodeName: "orderedList",
|
|
37
|
+
icon: IconListNumbers,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
value: "task",
|
|
41
|
+
label: "Task list",
|
|
42
|
+
nodeName: "taskList",
|
|
43
|
+
icon: ListChecksIcon,
|
|
44
|
+
},
|
|
45
|
+
];
|
|
15
46
|
export const UndoControl = ({ editor }) => {
|
|
16
47
|
return (_jsx(Control, { editor: editor, label: "undoControlLabel", operation: {
|
|
17
48
|
name: "undo",
|
|
@@ -204,6 +235,37 @@ export const Heading4Control = ({ editor }) => {
|
|
|
204
235
|
attributes: { level: 4 },
|
|
205
236
|
}, icon: IconH4 }));
|
|
206
237
|
};
|
|
238
|
+
export const HeadingControl = ({ editor, levels = [1, 2, 3, 4], }) => {
|
|
239
|
+
const options = headingControlOptions.filter((option) => levels.includes(option.level));
|
|
240
|
+
const currentHeading = headingControlOptions.find((option) => editor === null || editor === void 0 ? void 0 : editor.isActive("heading", { level: option.level }));
|
|
241
|
+
const selectedHeading = options.find((option) => option.level === (currentHeading === null || currentHeading === void 0 ? void 0 : currentHeading.level));
|
|
242
|
+
const ButtonIcon = (currentHeading === null || currentHeading === void 0 ? void 0 : currentHeading.icon) || IconHeading;
|
|
243
|
+
if (!options.length)
|
|
244
|
+
return null;
|
|
245
|
+
return (_jsx(DropDownMenu, { data: options.map((option) => ({
|
|
246
|
+
label: option.label,
|
|
247
|
+
value: option.level,
|
|
248
|
+
onClick: () => {
|
|
249
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleHeading({ level: option.level }).run();
|
|
250
|
+
},
|
|
251
|
+
})), value: selectedHeading
|
|
252
|
+
? [{ label: selectedHeading.label, value: selectedHeading.level }]
|
|
253
|
+
: [], enableSelectedOptionStyling: true, renderOption: (item) => {
|
|
254
|
+
const option = options.find((option) => option.level === item.value);
|
|
255
|
+
const Icon = (option === null || option === void 0 ? void 0 : option.icon) || IconH1;
|
|
256
|
+
return (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [_jsx(Icon, { size: 14 }), item.label] }));
|
|
257
|
+
}, size: "xs", variant: "outlined", buttonProps: {
|
|
258
|
+
title: (currentHeading === null || currentHeading === void 0 ? void 0 : currentHeading.label) || "Heading",
|
|
259
|
+
"aria-label": "Heading",
|
|
260
|
+
disabled: !editor,
|
|
261
|
+
selected: Boolean(currentHeading),
|
|
262
|
+
style: { padding: "1px 6px" },
|
|
263
|
+
}, dropDownProps: {
|
|
264
|
+
style: {
|
|
265
|
+
width: 150,
|
|
266
|
+
},
|
|
267
|
+
}, children: _jsx(ButtonIcon, { size: 14 }) }));
|
|
268
|
+
};
|
|
207
269
|
export const BulletListControl = ({ editor }) => {
|
|
208
270
|
return (_jsx(Control, { editor: editor, label: "bulletListControlLabel", isActive: {
|
|
209
271
|
name: "bulletList",
|
|
@@ -218,6 +280,51 @@ export const OrderedListControl = ({ editor }) => {
|
|
|
218
280
|
name: "toggleOrderedList",
|
|
219
281
|
}, icon: IconListNumbers }));
|
|
220
282
|
};
|
|
283
|
+
export const TaskListControl = ({ editor }) => {
|
|
284
|
+
return (_jsx(Control, { editor: editor, label: "taskListControlLabel", isActive: {
|
|
285
|
+
name: "taskList",
|
|
286
|
+
}, operation: {
|
|
287
|
+
name: "toggleTaskList",
|
|
288
|
+
}, icon: ListChecksIcon }));
|
|
289
|
+
};
|
|
290
|
+
export const ListControl = ({ editor, listTypes = ["bullet", "ordered", "task"], }) => {
|
|
291
|
+
const options = listControlOptions.filter((option) => listTypes.includes(option.value));
|
|
292
|
+
const currentList = listControlOptions.find((option) => editor === null || editor === void 0 ? void 0 : editor.isActive(option.nodeName));
|
|
293
|
+
const selectedList = options.find((option) => option.value === (currentList === null || currentList === void 0 ? void 0 : currentList.value));
|
|
294
|
+
const fallbackList = options[0] || listControlOptions[0];
|
|
295
|
+
const ButtonIcon = (currentList === null || currentList === void 0 ? void 0 : currentList.icon) || fallbackList.icon;
|
|
296
|
+
if (!options.length)
|
|
297
|
+
return null;
|
|
298
|
+
return (_jsx(DropDownMenu, { data: options.map((option) => ({
|
|
299
|
+
label: option.label,
|
|
300
|
+
value: option.value,
|
|
301
|
+
onClick: () => {
|
|
302
|
+
const chain = editor === null || editor === void 0 ? void 0 : editor.chain().focus();
|
|
303
|
+
if (option.value === "bullet")
|
|
304
|
+
chain === null || chain === void 0 ? void 0 : chain.toggleBulletList().run();
|
|
305
|
+
if (option.value === "ordered")
|
|
306
|
+
chain === null || chain === void 0 ? void 0 : chain.toggleOrderedList().run();
|
|
307
|
+
if (option.value === "task")
|
|
308
|
+
chain === null || chain === void 0 ? void 0 : chain.toggleTaskList().run();
|
|
309
|
+
},
|
|
310
|
+
})), value: selectedList
|
|
311
|
+
? [{ label: selectedList.label, value: selectedList.value }]
|
|
312
|
+
: [], enableSelectedOptionStyling: true, renderOption: (item) => {
|
|
313
|
+
const option = options.find((option) => option.value === item.value);
|
|
314
|
+
const Icon = (option === null || option === void 0 ? void 0 : option.icon) || IconList;
|
|
315
|
+
return (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [_jsx(Icon, { size: 14 }), item.label] }));
|
|
316
|
+
}, size: "xs", variant: "outlined", buttonProps: {
|
|
317
|
+
title: (currentList === null || currentList === void 0 ? void 0 : currentList.label) || "List",
|
|
318
|
+
"aria-label": "List",
|
|
319
|
+
disabled: !editor,
|
|
320
|
+
selected: Boolean(currentList),
|
|
321
|
+
style: { padding: "1px 6px" },
|
|
322
|
+
}, dropDownProps: {
|
|
323
|
+
style: {
|
|
324
|
+
width: 150,
|
|
325
|
+
},
|
|
326
|
+
}, children: _jsx(ButtonIcon, { size: 14 }) }));
|
|
327
|
+
};
|
|
221
328
|
export const AlignLeftControl = ({ editor }) => {
|
|
222
329
|
return (_jsx(Control, { editor: editor, label: "alignLeftControlLabel", isActive: {
|
|
223
330
|
name: { textAlign: "left" },
|
|
@@ -247,3 +354,35 @@ export const AlignJustifiedControl = ({ editor }) => {
|
|
|
247
354
|
name: { textAlign: "justify" },
|
|
248
355
|
}, operation: { name: "setTextAlign", attributes: "justify" }, icon: IconAlignJustified }));
|
|
249
356
|
};
|
|
357
|
+
export const AlignmentControl = ({ editor, alignments = ["left", "center", "right", "justify"], }) => {
|
|
358
|
+
const options = alignmentControlOptions.filter((option) => alignments.includes(option.value));
|
|
359
|
+
const activeAlignment = alignmentControlOptions.find((option) => editor === null || editor === void 0 ? void 0 : editor.isActive({ textAlign: option.value }));
|
|
360
|
+
const currentAlignment = activeAlignment || alignmentControlOptions[0];
|
|
361
|
+
const selectedAlignment = options.find((option) => option.value === currentAlignment.value);
|
|
362
|
+
const ButtonIcon = currentAlignment.icon;
|
|
363
|
+
if (!options.length)
|
|
364
|
+
return null;
|
|
365
|
+
return (_jsx(DropDownMenu, { data: options.map((option) => ({
|
|
366
|
+
label: option.label,
|
|
367
|
+
value: option.value,
|
|
368
|
+
onClick: () => {
|
|
369
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().setTextAlign(option.value).run();
|
|
370
|
+
},
|
|
371
|
+
})), value: selectedAlignment
|
|
372
|
+
? [{ label: selectedAlignment.label, value: selectedAlignment.value }]
|
|
373
|
+
: [], enableSelectedOptionStyling: true, renderOption: (item) => {
|
|
374
|
+
const option = options.find((option) => option.value === item.value);
|
|
375
|
+
const Icon = (option === null || option === void 0 ? void 0 : option.icon) || IconAlignLeft;
|
|
376
|
+
return (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [_jsx(Icon, { size: 14 }), item.label] }));
|
|
377
|
+
}, size: "xs", variant: "outlined", buttonProps: {
|
|
378
|
+
title: currentAlignment.label,
|
|
379
|
+
"aria-label": "Text alignment",
|
|
380
|
+
disabled: !editor,
|
|
381
|
+
selected: Boolean(activeAlignment),
|
|
382
|
+
style: { padding: "1px 6px" },
|
|
383
|
+
}, dropDownProps: {
|
|
384
|
+
style: {
|
|
385
|
+
width: 170,
|
|
386
|
+
},
|
|
387
|
+
}, children: _jsx(ButtonIcon, { size: 14 }) }));
|
|
388
|
+
};
|
|
@@ -12,6 +12,7 @@ const Labels = {
|
|
|
12
12
|
unlinkControlLabel: "Remove link",
|
|
13
13
|
bulletListControlLabel: "Bullet list",
|
|
14
14
|
orderedListControlLabel: "Ordered list",
|
|
15
|
+
taskListControlLabel: "Task list",
|
|
15
16
|
h1ControlLabel: "Heading 1",
|
|
16
17
|
h2ControlLabel: "Heading 2",
|
|
17
18
|
h3ControlLabel: "Heading 3",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import styled from "styled-components";
|
|
3
3
|
import ControlsGroup from "./ControlsGroup";
|
|
4
|
-
import { UndoControl, RedoControl, FontControl, TextColorControl, HighlightControl, BoldControl, ItalicControl, UnderlineControl, StrikeThroughControl, ClearFormattingControl, CodeControl, CodeBlockControl, BlockquoteControl, HorizontalRuleControl,
|
|
4
|
+
import { UndoControl, RedoControl, FontControl, TextColorControl, HighlightControl, BoldControl, ItalicControl, UnderlineControl, StrikeThroughControl, ClearFormattingControl, CodeControl, CodeBlockControl, BlockquoteControl, HorizontalRuleControl, HeadingControl, ListControl, AlignmentControl, } from "./Controls";
|
|
5
5
|
import { Controls } from "../Enums";
|
|
6
6
|
import { DropDownMenu } from "../../DropDownMenu";
|
|
7
7
|
import { useState } from "react";
|
|
@@ -10,6 +10,23 @@ import { Popover } from "../../Popover";
|
|
|
10
10
|
import LinkEditor from "../Components/LinkEditor";
|
|
11
11
|
import { TableToolsPopover } from "../Components/TableTools";
|
|
12
12
|
import { LinkIcon } from "lucide-react";
|
|
13
|
+
const headingControlLevels = [
|
|
14
|
+
{ control: Controls.HEADING_1, level: 1 },
|
|
15
|
+
{ control: Controls.HEADING_2, level: 2 },
|
|
16
|
+
{ control: Controls.HEADING_3, level: 3 },
|
|
17
|
+
{ control: Controls.HEADING_4, level: 4 },
|
|
18
|
+
];
|
|
19
|
+
const alignmentControls = [
|
|
20
|
+
{ control: Controls.TEXT_ALIGN_LEFT, alignment: "left" },
|
|
21
|
+
{ control: Controls.TEXT_ALIGN_CENTER, alignment: "center" },
|
|
22
|
+
{ control: Controls.TEXT_ALIGN_RIGHT, alignment: "right" },
|
|
23
|
+
{ control: Controls.TEXT_ALIGN_JUSTIFIED, alignment: "justify" },
|
|
24
|
+
];
|
|
25
|
+
const listControls = [
|
|
26
|
+
{ control: Controls.BULLET_LIST, listType: "bullet" },
|
|
27
|
+
{ control: Controls.ORDERED_LIST, listType: "ordered" },
|
|
28
|
+
{ control: Controls.TASK_LIST, listType: "task" },
|
|
29
|
+
];
|
|
13
30
|
const ToolbarContainer = styled.div `
|
|
14
31
|
display: flex;
|
|
15
32
|
flex-direction: row;
|
|
@@ -32,6 +49,15 @@ export const Toolbar = ({ editor, toolbarOptions }) => {
|
|
|
32
49
|
var _a;
|
|
33
50
|
const { controls } = toolbarOptions || {};
|
|
34
51
|
const [linkPopoverOpen, setLinkPopoverOpen] = useState(false);
|
|
52
|
+
const headingLevels = headingControlLevels
|
|
53
|
+
.filter(({ control }) => controls === null || controls === void 0 ? void 0 : controls.includes(control))
|
|
54
|
+
.map(({ level }) => level);
|
|
55
|
+
const alignments = alignmentControls
|
|
56
|
+
.filter(({ control }) => controls === null || controls === void 0 ? void 0 : controls.includes(control))
|
|
57
|
+
.map(({ alignment }) => alignment);
|
|
58
|
+
const listTypes = listControls
|
|
59
|
+
.filter(({ control }) => controls === null || controls === void 0 ? void 0 : controls.includes(control))
|
|
60
|
+
.map(({ listType }) => listType);
|
|
35
61
|
const customItems = controls === null || controls === void 0 ? void 0 : controls.filter((control) => typeof control !== "string" &&
|
|
36
62
|
(control.type === "menu" || control.type === "button"));
|
|
37
63
|
return (_jsxs(ToolbarContainer, { children: [(_a = customItems === null || customItems === void 0 ? void 0 : customItems.map) === null || _a === void 0 ? void 0 : _a.call(customItems, (item, index) => {
|
|
@@ -46,5 +72,5 @@ export const Toolbar = ({ editor, toolbarOptions }) => {
|
|
|
46
72
|
},
|
|
47
73
|
} }, item.options, { size: "xs", children: (_b = item === null || item === void 0 ? void 0 : item.options) === null || _b === void 0 ? void 0 : _b.label }), index));
|
|
48
74
|
}
|
|
49
|
-
}), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.UNDO)) && _jsx(UndoControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.REDO)) && _jsx(RedoControl, { editor: editor })] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.FONT)) && _jsx(FontControl, {}), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.COLOR)) && (_jsx(TextColorControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HIGHLIGHT)) && (_jsx(HighlightControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.BOLD)) && _jsx(BoldControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.ITALIC)) && (_jsx(ItalicControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.UNDERLINE)) && (_jsx(UnderlineControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.STRIKE)) && (_jsx(StrikeThroughControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [
|
|
75
|
+
}), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.UNDO)) && _jsx(UndoControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.REDO)) && _jsx(RedoControl, { editor: editor })] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.FONT)) && _jsx(FontControl, {}), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.COLOR)) && (_jsx(TextColorControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HIGHLIGHT)) && (_jsx(HighlightControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.BOLD)) && _jsx(BoldControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.ITALIC)) && (_jsx(ItalicControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.UNDERLINE)) && (_jsx(UnderlineControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.STRIKE)) && (_jsx(StrikeThroughControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [headingLevels.length > 0 && (_jsx(HeadingControl, { editor: editor, levels: headingLevels })), alignments.length > 0 && (_jsx(AlignmentControl, { editor: editor, alignments: alignments })), listTypes.length > 0 && (_jsx(ListControl, { editor: editor, listTypes: listTypes })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.BLOCKQUOTE)) && (_jsx(BlockquoteControl, { editor: editor }))] }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.LINK)) && (_jsxs(Popover, { opened: linkPopoverOpen, onChange: setLinkPopoverOpen, position: "bottom", width: 330, trapFocus: true, children: [_jsx(Popover.Target, { children: _jsx(Button, { size: "xs", variant: "outlined", title: "Link", "aria-label": "Link", selected: linkPopoverOpen || Boolean(editor === null || editor === void 0 ? void 0 : editor.isActive("link")), disabled: !editor, style: { padding: "1px 6px" }, children: _jsx(LinkIcon, { size: 14 }) }) }), _jsx(Popover.Dropdown, { children: editor && (_jsx(LinkEditor, { editor: editor, autoFocus: linkPopoverOpen, onClose: () => setLinkPopoverOpen(false) })) })] })), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.CODE)) && _jsx(CodeControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.CODE_BLOCK)) && (_jsx(CodeBlockControl, { editor: editor }))] }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TABLE)) && (_jsx(TableToolsPopover, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HORIZONTAL_RULE)) && (_jsx(HorizontalRuleControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.CLEAR_FORMATTING)) && (_jsx(ClearFormattingControl, { editor: editor }))] }));
|
|
50
76
|
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import TableDefaults from "../TableDefaults";
|
|
2
|
+
const enableResizeClass = (dataField) => {
|
|
3
|
+
if (dataField === undefined) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
document.querySelectorAll(`.resizer.col-${dataField}`).forEach((resizer) => {
|
|
7
|
+
resizer.classList.add("isResizing");
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
const disableResizeClass = (dataField) => {
|
|
11
|
+
if (dataField === undefined) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
document.querySelectorAll(`.resizer.col-${dataField}`).forEach((resizer) => {
|
|
15
|
+
resizer.classList.remove("isResizing");
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
const resizeHandler = ({ event, columnId, columnProps, onResize, onResizeFinished, }) => {
|
|
19
|
+
let col = event.target
|
|
20
|
+
.parentElement;
|
|
21
|
+
let newColumns = [];
|
|
22
|
+
let x = 0;
|
|
23
|
+
let w = 0;
|
|
24
|
+
const mouseMoveHandler = function (e) {
|
|
25
|
+
const selectedColumn = document.querySelectorAll(`.column-${columnId}`);
|
|
26
|
+
const columnHeaders = document.querySelectorAll(`.mfui-th.column-${columnId}`);
|
|
27
|
+
const dx = e.clientX - x;
|
|
28
|
+
let newWidth = w + dx;
|
|
29
|
+
// Calculate what the minimum width should be
|
|
30
|
+
// min width should be the defined column width or the default min width
|
|
31
|
+
if (columnProps.minWidth === undefined) {
|
|
32
|
+
if (newWidth < TableDefaults.td.minWidth)
|
|
33
|
+
newWidth = TableDefaults.td.minWidth;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
if (newWidth < columnProps.minWidth)
|
|
37
|
+
newWidth = columnProps.minWidth;
|
|
38
|
+
}
|
|
39
|
+
selectedColumn.forEach((col) => {
|
|
40
|
+
var _a;
|
|
41
|
+
col.style.width = `${newWidth}px`;
|
|
42
|
+
col.style.flex = "0 0 auto";
|
|
43
|
+
// col.style.maxWidth = `${newWidth}px`;
|
|
44
|
+
// col.style.minWidth = `${newWidth}px`;
|
|
45
|
+
newColumns.push({
|
|
46
|
+
dataField: ((_a = col === null || col === void 0 ? void 0 : col.dataset) === null || _a === void 0 ? void 0 : _a.field) || "",
|
|
47
|
+
width: newWidth,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
newColumns = Array.from(columnHeaders).map((col) => {
|
|
51
|
+
var _a;
|
|
52
|
+
return {
|
|
53
|
+
dataField: ((_a = col === null || col === void 0 ? void 0 : col.dataset) === null || _a === void 0 ? void 0 : _a.field) || "",
|
|
54
|
+
width: newWidth,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
onResize({
|
|
58
|
+
columns: newColumns,
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
const mouseUpHandler = function () {
|
|
62
|
+
var _a, _b, _c;
|
|
63
|
+
let newWidth = ((_c = (_b = (_a = document === null || document === void 0 ? void 0 : document.querySelector) === null || _a === void 0 ? void 0 : _a.call(document, `.column-${columnId}`)) === null || _b === void 0 ? void 0 : _b.style) === null || _c === void 0 ? void 0 : _c.width) || null;
|
|
64
|
+
if (newWidth) {
|
|
65
|
+
newWidth = newWidth.replace("px", "");
|
|
66
|
+
}
|
|
67
|
+
disableResizeClass(columnId);
|
|
68
|
+
document.removeEventListener("mousemove", mouseMoveHandler);
|
|
69
|
+
document.removeEventListener("mouseup", mouseUpHandler);
|
|
70
|
+
onResizeFinished === null || onResizeFinished === void 0 ? void 0 : onResizeFinished({
|
|
71
|
+
column: columnProps,
|
|
72
|
+
columnId: columnId,
|
|
73
|
+
targetColumn: document.querySelector(`.column-${columnId}`),
|
|
74
|
+
newWidth,
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
x = event.clientX;
|
|
78
|
+
const styles = window.getComputedStyle(col);
|
|
79
|
+
w = parseInt(styles.width, 10);
|
|
80
|
+
document.addEventListener("mousemove", mouseMoveHandler);
|
|
81
|
+
document.addEventListener("mouseup", mouseUpHandler);
|
|
82
|
+
enableResizeClass(columnId);
|
|
83
|
+
};
|
|
84
|
+
export default resizeHandler;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monolith-forensics/monolith-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"author": "Matt Danner (Monolith Forensics LLC)",
|
|
@@ -48,7 +48,10 @@
|
|
|
48
48
|
"@tiptap/extension-horizontal-rule": "3.22.4",
|
|
49
49
|
"@tiptap/extension-image": "3.22.4",
|
|
50
50
|
"@tiptap/extension-link": "3.22.4",
|
|
51
|
+
"@tiptap/extension-list": "3.22.4",
|
|
51
52
|
"@tiptap/extension-table": "3.22.4",
|
|
53
|
+
"@tiptap/extension-task-item": "3.22.4",
|
|
54
|
+
"@tiptap/extension-task-list": "3.22.4",
|
|
52
55
|
"@tiptap/extension-text-align": "3.22.4",
|
|
53
56
|
"@tiptap/extension-text-style": "3.22.4",
|
|
54
57
|
"@tiptap/extensions": "3.22.4",
|