@monolith-forensics/monolith-ui 1.8.1-dev.3 → 1.9.1-dev.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.
@@ -144,13 +144,13 @@ const Calendar = ({ defaultValue = new Date(), value, onChange = () => { }, hour
144
144
  const yearOptions = getYearOptions();
145
145
  const selectedMonthOption = MONTH_OPTIONS.find((option) => option.value === month);
146
146
  const selectedYearOption = yearOptions.find((option) => option.value === year);
147
- return (_jsxs(CalendarHeader, { children: [_jsx(CalendarNavButton, { type: "button", onClick: handlePrevious, onMouseUp: clearPressureTimer, "aria-label": "Go to previous month", title: "Previous month. Hold Shift to jump by year.", children: _jsx(ChevronLeftIcon, { "aria-hidden": "true" }) }), _jsxs(CalendarHeaderControls, { children: [_jsx(CalendarHeaderSelect, { children: _jsx(DropDownMenu, { data: MONTH_OPTIONS, value: selectedMonthOption ? [selectedMonthOption] : [], variant: "outlined", size: "xs", arrow: true, onItemSelect: (item) => commitMonthOrYearSelection(Number(item.value), year, "month"), dropDownProps: {
147
+ return (_jsxs(CalendarHeader, { children: [_jsx(CalendarNavButton, { type: "button", onClick: handlePrevious, onMouseUp: clearPressureTimer, "aria-label": "Go to previous month", title: "Previous month. Hold Shift to jump by year.", children: _jsx(ChevronLeftIcon, { "aria-hidden": "true" }) }), _jsxs(CalendarHeaderControls, { children: [_jsx(CalendarHeaderSelect, { children: _jsx(DropDownMenu, { data: MONTH_OPTIONS, value: selectedMonthOption ? [selectedMonthOption] : [], enableSelectedOptionStyling: true, variant: "outlined", size: "xs", arrow: true, onItemSelect: (item) => commitMonthOrYearSelection(Number(item.value), year, "month"), dropDownProps: {
148
148
  style: { maxHeight: 260, width: 125 },
149
149
  }, buttonProps: {
150
150
  title: "Select month",
151
151
  size: "xxs",
152
152
  style: { minWidth: 95 },
153
- }, children: _jsx(CalendarMonth, { children: monthName }) }) }), _jsx(CalendarHeaderSelect, { children: _jsx(DropDownMenu, { data: yearOptions, value: selectedYearOption ? [selectedYearOption] : [], variant: "outlined", size: "xs", arrow: true, searchable: true, onItemSelect: (item) => commitMonthOrYearSelection(month, Number(item.value), "year"), dropDownProps: {
153
+ }, children: _jsx(CalendarMonth, { children: monthName }) }) }), _jsx(CalendarHeaderSelect, { children: _jsx(DropDownMenu, { data: yearOptions, value: selectedYearOption ? [selectedYearOption] : [], enableSelectedOptionStyling: true, variant: "outlined", size: "xs", arrow: true, searchable: true, onItemSelect: (item) => commitMonthOrYearSelection(month, Number(item.value), "year"), dropDownProps: {
154
154
  style: { width: 120, maxHeight: 260 },
155
155
  }, buttonProps: {
156
156
  title: "Select year",
@@ -1,7 +1,7 @@
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
- export const DropDownMenu = ({ data, children, defaultValue, value, variant, arrow, size, searchable, grouped, onAddNew, loading, onScroll, onScrollToTop, onScrollToBottom, onSearch, manualSearch, multiselect, enableSelectAll, renderOption, dynamicOptionHeight, onItemSelect, onChange, buttonProps, TooltipContent, dropDownProps, query, disabled, }) => {
4
+ 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
5
  var _a;
6
6
  const isObjectArray = (_a = Object.keys((data === null || data === void 0 ? void 0 : data[0]) || {})) === null || _a === void 0 ? void 0 : _a.includes("label");
7
7
  const [internalSelected, setInternalSelected] = useState(defaultValue || []);
@@ -35,5 +35,5 @@ export const DropDownMenu = ({ data, children, defaultValue, value, variant, arr
35
35
  const handleScrollToBottom = (e) => {
36
36
  onScrollToBottom === null || onScrollToBottom === void 0 ? void 0 : onScrollToBottom(e);
37
37
  };
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, size: size, handleAddItem: handleAddItem, handleRemoveItem: handleRemoveItem, handleSetSelected: handleSetSelected, onItemSelect: onItemSelect, renderOption: renderOption, onScroll: onScroll, onScrollToTop: onScrollToTop, onScrollToBottom: handleScrollToBottom, query: query }))] }) }));
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 }))] }) }));
39
39
  };
@@ -12,6 +12,7 @@ export declare const MenuItemList: React.FC<{
12
12
  TooltipContent?: ComponentType<any>;
13
13
  multiselect?: boolean;
14
14
  enableSelectAll?: boolean;
15
+ enableSelectedOptionStyling?: boolean;
15
16
  grouped?: boolean;
16
17
  onAddNew?: (value: string) => void;
17
18
  size?: Size;
@@ -121,7 +121,7 @@ const MeasuredRow = ({ children, index, setItemSize, style }) => {
121
121
  }, [children, index, setItemSize]);
122
122
  return (_jsx("div", { style: Object.assign(Object.assign({}, style), { overflow: "visible" }), children: _jsx("div", { ref: rowRef, children: children }) }));
123
123
  };
124
- export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dynamicOptionHeight, selected, TooltipContent, multiselect, enableSelectAll, grouped, onAddNew, size, handleAddItem, handleRemoveItem, handleSetSelected, onItemSelect, renderOption, onScroll, onScrollToTop, onScrollToBottom, query, }) => {
124
+ 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, }) => {
125
125
  const [searchValue, setSearchValue] = useState("");
126
126
  const _a = query !== null && query !== void 0 ? query : {}, { queryKey, queryFn, getNextPageParam, initialPageParam } = _a, rest = __rest(_a, ["queryKey", "queryFn", "getNextPageParam", "initialPageParam"]);
127
127
  const targetElm = useRef(null);
@@ -294,12 +294,15 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
294
294
  (_b = variableListRef.current) === null || _b === void 0 ? void 0 : _b.scrollToItem(selectedDisplayIndex, "smart");
295
295
  return;
296
296
  }
297
+ if (!enableSelectedOptionStyling)
298
+ return;
297
299
  if (selectedDisplayIndex < 0)
298
300
  return;
299
301
  (_c = fixedListRef.current) === null || _c === void 0 ? void 0 : _c.scrollToItem(selectedDisplayIndex, "smart");
300
302
  (_d = variableListRef.current) === null || _d === void 0 ? void 0 : _d.scrollToItem(selectedDisplayIndex, "smart");
301
303
  }, [
302
304
  displayItemsKey,
305
+ enableSelectedOptionStyling,
303
306
  itemCount,
304
307
  multiselect,
305
308
  selectedDisplayIndex,
@@ -320,7 +323,7 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
320
323
  if (item.items) {
321
324
  return (_jsx(DropDownMenu, { data: item.items, size: size, buttonProps: style ? Object.assign({ style }, item) : Object.assign({}, item), disabled: item.disabled, dynamicOptionHeight: dynamicListEnabled, children: item.label }));
322
325
  }
323
- return (_jsx(MenuItem, { className: "MenuItem", itemData: item, TooltipContent: TooltipContent, "data-selected": !multiselect && isSelected, "data-disabled": item.disabled, disabled: item.disabled, leftSection: multiselect ? (_jsxs(_Fragment, { children: [_jsx(CheckBox, { value: isSelected, size: size, onChange: (newValue) => {
326
+ return (_jsx(MenuItem, { className: "MenuItem", itemData: item, TooltipContent: TooltipContent, "data-selected": enableSelectedOptionStyling && !multiselect && isSelected, "data-disabled": item.disabled, disabled: item.disabled, leftSection: multiselect ? (_jsxs(_Fragment, { children: [_jsx(CheckBox, { value: isSelected, size: size, onChange: (newValue) => {
324
327
  var _a;
325
328
  newValue ? handleAddItem(item) : handleRemoveItem(item);
326
329
  (_a = item === null || item === void 0 ? void 0 : item.onClick) === null || _a === void 0 ? void 0 : _a.call(item, item);
@@ -32,6 +32,7 @@ export type DropDownMenuProps = {
32
32
  value?: DropDownItem[];
33
33
  multiselect?: boolean;
34
34
  enableSelectAll?: boolean;
35
+ enableSelectedOptionStyling?: boolean;
35
36
  size?: Size;
36
37
  title?: string;
37
38
  TooltipContent?: ComponentType<any>;
@@ -311,7 +311,9 @@ const BubbleMenu = ({ editor, rect, open, onOpen, customMenuItems = [], }) => {
311
311
  return (_jsx(BubbleItemButton, { variant: "subtle", onClick: () => { var _a; return (_a = item === null || item === void 0 ? void 0 : item.onClick) === null || _a === void 0 ? void 0 : _a.call(item, editor); }, color: isActive ? "primary" : undefined, selected: isActive, children: item.icon && _jsx(item.icon, { size: 14 }) }, item.name));
312
312
  }
313
313
  if (item.type === "menu") {
314
- return (_jsx(DropDownMenu, Object.assign({ data: item.items, size: "xs", arrow: item.arrow, buttonProps: item.buttonProps, variant: "subtle", buttonRender: item.buttonRender, onItemSelect: (item) => { var _a, _b; return (_b = (_a = item === null || item === void 0 ? void 0 : item.data) === null || _a === void 0 ? void 0 : _a.command) === null || _b === void 0 ? void 0 : _b.call(_a, editor, selectedText); } }, item.dropDownProps, { children: item.icon
314
+ return (_jsx(DropDownMenu, Object.assign({ data: item.items, size: "xs", arrow: item.arrow, buttonProps: item.buttonProps, variant: "subtle", buttonRender: item.buttonRender, onItemSelect: (item) => { var _a, _b; return (_b = (_a = item === null || item === void 0 ? void 0 : item.data) === null || _a === void 0 ? void 0 : _a.command) === null || _b === void 0 ? void 0 : _b.call(_a, editor, selectedText); }, dropDownProps: {
315
+ style: { width: 135 },
316
+ } }, item.dropDownProps, { children: item.icon
315
317
  ? (_jsx(item.icon, { size: 14 }))
316
318
  : (item.label || item.name) }), item.name));
317
319
  }
@@ -66,14 +66,84 @@ const getImageBlob = (src) => __awaiter(void 0, void 0, void 0, function* () {
66
66
  }
67
67
  return response.blob();
68
68
  });
69
+ const clipboardPngType = "image/png";
70
+ const canWriteClipboardType = (ClipboardItemCtor, type) => {
71
+ if (!type)
72
+ return false;
73
+ if (typeof ClipboardItemCtor.supports === "function") {
74
+ return ClipboardItemCtor.supports(type);
75
+ }
76
+ return type === clipboardPngType;
77
+ };
78
+ const loadImageSource = (src) => new Promise((resolve, reject) => {
79
+ const image = new Image();
80
+ image.crossOrigin = "anonymous";
81
+ image.onload = () => resolve(image);
82
+ image.onerror = () => {
83
+ reject(new Error("Unable to prepare image for clipboard."));
84
+ };
85
+ image.src = src;
86
+ });
87
+ const renderImageSourceToPngBlob = (src) => __awaiter(void 0, void 0, void 0, function* () {
88
+ const image = yield loadImageSource(src);
89
+ const width = image.naturalWidth || image.width;
90
+ const height = image.naturalHeight || image.height;
91
+ if (!width || !height) {
92
+ throw new Error("Unable to prepare image for clipboard.");
93
+ }
94
+ const canvas = document.createElement("canvas");
95
+ canvas.width = width;
96
+ canvas.height = height;
97
+ const context = canvas.getContext("2d");
98
+ if (!context) {
99
+ throw new Error("Unable to prepare image for clipboard.");
100
+ }
101
+ context.drawImage(image, 0, 0, width, height);
102
+ return new Promise((resolve, reject) => {
103
+ canvas.toBlob((blob) => {
104
+ if (blob) {
105
+ resolve(blob);
106
+ }
107
+ else {
108
+ reject(new Error("Unable to prepare image for clipboard."));
109
+ }
110
+ }, clipboardPngType);
111
+ });
112
+ });
113
+ const convertBlobToClipboardPng = (blob, fallbackSrc) => __awaiter(void 0, void 0, void 0, function* () {
114
+ const objectUrl = URL.createObjectURL(blob);
115
+ try {
116
+ return yield renderImageSourceToPngBlob(objectUrl);
117
+ }
118
+ catch (error) {
119
+ if (!fallbackSrc || fallbackSrc === objectUrl)
120
+ throw error;
121
+ return renderImageSourceToPngBlob(fallbackSrc);
122
+ }
123
+ finally {
124
+ URL.revokeObjectURL(objectUrl);
125
+ }
126
+ });
127
+ const getClipboardImageBlob = (image, ClipboardItemCtor) => __awaiter(void 0, void 0, void 0, function* () {
128
+ const src = image.currentSrc || image.src;
129
+ const blob = yield getImageBlob(src);
130
+ const type = blob.type || "";
131
+ if (canWriteClipboardType(ClipboardItemCtor, type)) {
132
+ return { blob, type };
133
+ }
134
+ return {
135
+ blob: yield convertBlobToClipboardPng(blob, src),
136
+ type: clipboardPngType,
137
+ };
138
+ });
69
139
  const copyImage = (image) => __awaiter(void 0, void 0, void 0, function* () {
70
140
  var _a;
71
- const ClipboardItemCtor = window.ClipboardItem;
141
+ const ClipboardItemCtor = window
142
+ .ClipboardItem;
72
143
  if (!((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.write) || !ClipboardItemCtor) {
73
144
  throw new Error("Image copying is not supported by this browser.");
74
145
  }
75
- const blob = yield getImageBlob(image.src);
76
- const type = blob.type || "image/png";
146
+ const { blob, type } = yield getClipboardImageBlob(image, ClipboardItemCtor);
77
147
  yield navigator.clipboard.write([
78
148
  new ClipboardItemCtor({
79
149
  [type]: blob,
@@ -11,6 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { useEffect, useRef, useState } from "react";
12
12
  import styled from "styled-components";
13
13
  import { EditorContent, useEditor } from "@tiptap/react";
14
+ import { DOMParser as ProseMirrorDOMParser } from "@tiptap/pm/model";
14
15
  import { Toolbar } from "./Toolbar";
15
16
  import getTipTapExtensions from "./Extensions/getTiptapExtensions";
16
17
  import { Extensions, SlashCommands } from "./Enums";
@@ -83,6 +84,12 @@ const htmlHasContent = (html) => {
83
84
  return Boolean(((_a = document.body.textContent) === null || _a === void 0 ? void 0 : _a.trim()) ||
84
85
  document.body.querySelector("table, ul, ol, blockquote, pre, code, hr, iframe, video, audio"));
85
86
  };
87
+ const insertHtmlAtSelection = (view, html) => {
88
+ const container = window.document.createElement("div");
89
+ container.innerHTML = html;
90
+ const slice = ProseMirrorDOMParser.fromSchema(view.state.schema).parseSlice(container);
91
+ view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());
92
+ };
86
93
  const createImageFileFromSource = (imageSource, index) => __awaiter(void 0, void 0, void 0, function* () {
87
94
  var _a;
88
95
  const response = yield fetch(imageSource.src);
@@ -191,7 +198,7 @@ const handleImagePaste = (view, event, handleImageUpload, handleImageUrlUpload)
191
198
  return false;
192
199
  event.preventDefault();
193
200
  if (html && htmlHasContent(htmlWithImageMarkers)) {
194
- view.pasteHTML(htmlWithImageMarkers);
201
+ insertHtmlAtSelection(view, htmlWithImageMarkers);
195
202
  imageSources.forEach((imageSource) => {
196
203
  replaceImageMarkerWithPlaceholder(view, imageSource);
197
204
  });
@@ -23,7 +23,11 @@ export const Toolbar = styled(({ className, editor, toolbarOptions }) => {
23
23
  return (_jsx(Button, Object.assign({}, item.options, { children: (_a = item === null || item === void 0 ? void 0 : item.options) === null || _a === void 0 ? void 0 : _a.label }), index));
24
24
  }
25
25
  else if (item.type === "menu") {
26
- return (_jsx(DropDownMenu, Object.assign({}, item.options, { children: (_b = item === null || item === void 0 ? void 0 : item.options) === null || _b === void 0 ? void 0 : _b.label }), index));
26
+ return (_jsx(DropDownMenu, Object.assign({ dropDownProps: {
27
+ style: {
28
+ width: 135,
29
+ },
30
+ } }, item.options, { children: (_b = item === null || item === void 0 ? void 0 : item.options) === null || _b === void 0 ? void 0 : _b.label }), index));
27
31
  }
28
32
  }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.FONT)) && (_jsx(DropDownMenu, { data: Object.values(Fonts).map((font) => ({
29
33
  label: font,
@@ -31,7 +35,11 @@ export const Toolbar = styled(({ className, editor, toolbarOptions }) => {
31
35
  onClick: () => {
32
36
  setFont(font);
33
37
  },
34
- })), size: "xxs", variant: "outlined", arrow: true, buttonProps: {
38
+ })), size: "xxs", variant: "outlined", arrow: true, dropDownProps: {
39
+ style: {
40
+ width: 135,
41
+ },
42
+ }, buttonProps: {
35
43
  title: "Select Font",
36
44
  }, children: (font || Fonts.DEFAULT) })), _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 })] }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.COLOR)) && (_jsx(DropDownMenu, { data: [
37
45
  {
@@ -60,6 +68,10 @@ export const Toolbar = styled(({ className, editor, toolbarOptions }) => {
60
68
  borderRadius: "3px",
61
69
  } }), item.label] })), size: "xxs", variant: "outlined", arrow: true, buttonProps: {
62
70
  title: "Select Color",
71
+ }, dropDownProps: {
72
+ style: {
73
+ width: 100,
74
+ },
63
75
  }, children: "Color" })), _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: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_1)) && (_jsx(Heading1Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_2)) && (_jsx(Heading2Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_3)) && (_jsx(Heading3Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_4)) && (_jsx(Heading4Control, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.BULLET_LIST)) && (_jsx(BulletListControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.ORDERED_LIST)) && (_jsx(OrderedListControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_LEFT)) && (_jsx(AlignLeftControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_CENTER)) && (_jsx(AlignCenterControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_RIGHT)) && (_jsx(AlignRightControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_JUSTIFIED)) && (_jsx(AlignJustifiedControl, { editor: editor }))] })] }));
64
76
  }) `
65
77
  display: flex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monolith-forensics/monolith-ui",
3
- "version": "1.8.1-dev.3",
3
+ "version": "1.9.1-dev.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Matt Danner (Monolith Forensics LLC)",
@@ -1,41 +0,0 @@
1
- import { ReactNode } from "react";
2
- import type { FormatOptions } from "../DateInput/DateInput";
3
- import { Size, Variant } from "../core";
4
- export type DateTimeRangeValue = {
5
- start?: string | null;
6
- end?: string | null;
7
- };
8
- export type DateTimeRangePreset = {
9
- label: string;
10
- getRange: () => Required<DateTimeRangeValue>;
11
- };
12
- export type DateTimeRangePickerChangeMeta = {
13
- source: "apply" | "clear" | "preset";
14
- preset?: DateTimeRangePreset;
15
- };
16
- export type DateTimeRangePickerProps = {
17
- className?: string;
18
- style?: React.CSSProperties;
19
- defaultValue?: DateTimeRangeValue;
20
- value?: DateTimeRangeValue;
21
- onChange?: (value: DateTimeRangeValue, meta: DateTimeRangePickerChangeMeta) => void;
22
- label?: string;
23
- description?: ReactNode;
24
- placeholder?: string;
25
- startLabel?: string;
26
- endLabel?: string;
27
- format?: FormatOptions;
28
- size?: Size;
29
- variant?: Variant;
30
- required?: boolean;
31
- clearable?: boolean;
32
- disabled?: boolean;
33
- error?: string;
34
- width?: string | number;
35
- min?: Date;
36
- max?: Date;
37
- utc?: boolean;
38
- presets?: DateTimeRangePreset[];
39
- };
40
- declare const DateTimeRangePicker: import("react").ForwardRefExoticComponent<DateTimeRangePickerProps & import("react").RefAttributes<HTMLElement>>;
41
- export default DateTimeRangePicker;
@@ -1,363 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { autoUpdate, flip, FloatingPortal, offset, shift, useDismiss, useFloating, useInteractions, } from "@floating-ui/react";
3
- import moment from "moment";
4
- import { CalendarDaysIcon, Clock3Icon } from "lucide-react";
5
- import { forwardRef, useCallback, useEffect, useMemo, useRef, useState, } from "react";
6
- import styled from "styled-components";
7
- import { Button, Calendar, DateInput, FieldLabel, SegmentedControl } from "..";
8
- import { ArrowButton, ClearButton, getControlSizeTokens, StyledContent, StyledFloatContainer, } from "../core";
9
- const DEFAULT_FORMAT = "YYYY-MM-DD HH:mm:ss";
10
- const resolveNow = (utc) => (utc ? moment.utc() : moment());
11
- const serializeMoment = (value, utc) => {
12
- const next = utc ? value.clone().utc() : value.clone();
13
- return next.toISOString();
14
- };
15
- const getDefaultPresets = (utc) => {
16
- const makePreset = (label, amount, unit) => ({
17
- label,
18
- getRange: () => {
19
- const end = resolveNow(utc);
20
- const start = end.clone().subtract(amount, unit);
21
- return {
22
- start: serializeMoment(start, utc),
23
- end: serializeMoment(end, utc),
24
- };
25
- },
26
- });
27
- return [
28
- makePreset("Last 15 minutes", 15, "minutes"),
29
- makePreset("Last 30 minutes", 30, "minutes"),
30
- makePreset("Last 1 hour", 1, "hour"),
31
- makePreset("Last 24 hours", 24, "hours"),
32
- makePreset("Last 7 days", 7, "days"),
33
- makePreset("Last 30 days", 30, "days"),
34
- ];
35
- };
36
- const parseRangeMoment = (value, utc) => {
37
- if (!value)
38
- return null;
39
- const parsed = utc ? moment.utc(value) : moment(value);
40
- return parsed.isValid() ? parsed : null;
41
- };
42
- const momentToCalendarDate = (value, utc) => {
43
- const parsed = parseRangeMoment(value, utc);
44
- if (!parsed)
45
- return undefined;
46
- if (!utc)
47
- return parsed.toDate();
48
- return new Date(parsed.year(), parsed.month(), parsed.date(), parsed.hour(), parsed.minute(), parsed.second(), parsed.millisecond());
49
- };
50
- const calendarDateToMoment = (value, utc) => {
51
- if (!utc)
52
- return moment(value);
53
- return moment.utc({
54
- year: value.getFullYear(),
55
- month: value.getMonth(),
56
- date: value.getDate(),
57
- hour: value.getHours(),
58
- minute: value.getMinutes(),
59
- second: value.getSeconds(),
60
- millisecond: value.getMilliseconds(),
61
- });
62
- };
63
- const formatDisplay = (value, format, utc) => {
64
- const parsed = parseRangeMoment(value, utc);
65
- if (!parsed)
66
- return "";
67
- return parsed.format(format);
68
- };
69
- const StyledContainer = styled.div.attrs({
70
- className: "mfui-DateTimeRangePicker",
71
- }) `
72
- width: ${({ $width }) => {
73
- if ($width === undefined || $width === null)
74
- return "100%";
75
- return typeof $width === "number" ? `${$width}px` : $width;
76
- }};
77
- `;
78
- const StyledTrigger = styled.button `
79
- position: relative;
80
- display: flex;
81
- align-items: center;
82
- gap: ${({ size }) => `${getControlSizeTokens(size).iconGap}px`};
83
- width: 100%;
84
- height: ${({ size }) => `${getControlSizeTokens(size).height}px`};
85
- padding: ${({ size }) => `0 ${getControlSizeTokens(size).adornmentWidth}px 0 ${getControlSizeTokens(size).inputPaddingX}px`};
86
- border-radius: 5px;
87
- border: 1px solid
88
- ${({ theme, variant }) => variant === "filled" || variant === "text"
89
- ? "transparent"
90
- : theme.palette.input.border};
91
- outline: none;
92
- background: ${({ theme, variant }) => variant === "text" ? "transparent" : theme.palette.input.background};
93
- color: ${({ theme }) => theme.palette.text.primary};
94
- font-family: ${({ theme }) => theme.typography.fontFamily};
95
- font-size: ${({ size }) => `${getControlSizeTokens(size).fontSize}px`};
96
- text-align: left;
97
- cursor: pointer;
98
- transition: border 0.1s ease-in-out;
99
-
100
- &:focus-visible,
101
- &:focus {
102
- border-color: ${({ theme }) => theme.palette.primary.main};
103
- }
104
-
105
- &:disabled {
106
- cursor: not-allowed;
107
- opacity: 0.5;
108
- }
109
- `;
110
- const TriggerIcon = styled.span `
111
- display: inline-flex;
112
- align-items: center;
113
- color: ${({ theme }) => theme.palette.text.secondary};
114
-
115
- svg {
116
- width: ${({ size }) => `${getControlSizeTokens(size).iconSize}px`};
117
- height: ${({ size }) => `${getControlSizeTokens(size).iconSize}px`};
118
- }
119
- `;
120
- const TriggerText = styled.span `
121
- min-width: 0;
122
- overflow: hidden;
123
- text-overflow: ellipsis;
124
- white-space: nowrap;
125
- color: ${({ theme, $empty }) => $empty ? theme.palette.input.placeholder : theme.palette.text.primary};
126
- `;
127
- const TriggerActions = styled.span `
128
- position: absolute;
129
- right: 0;
130
- top: 0;
131
- display: flex;
132
- height: 100%;
133
- `;
134
- const PickerPanel = styled.div `
135
- display: grid;
136
- grid-template-columns: 172px minmax(430px, 1fr);
137
- gap: 10px;
138
- width: min(720px, calc(100vw - 32px));
139
-
140
- @media (max-width: 640px) {
141
- grid-template-columns: minmax(0, 1fr);
142
- width: calc(100vw - 32px);
143
- }
144
- `;
145
- const PresetColumn = styled.div `
146
- display: flex;
147
- flex-direction: column;
148
- gap: 4px;
149
- padding-right: 10px;
150
- border-right: 1px solid ${({ theme }) => theme.palette.divider};
151
-
152
- @media (max-width: 640px) {
153
- padding-right: 0;
154
- padding-bottom: 10px;
155
- border-right: none;
156
- border-bottom: 1px solid ${({ theme }) => theme.palette.divider};
157
- }
158
- `;
159
- const PanelTitle = styled.div `
160
- font-size: 11px;
161
- font-weight: 700;
162
- line-height: 1.2;
163
- text-transform: uppercase;
164
- color: ${({ theme }) => theme.palette.text.secondary};
165
- margin-bottom: 4px;
166
- `;
167
- const PresetButton = styled.button `
168
- display: flex;
169
- align-items: center;
170
- width: 100%;
171
- min-height: 28px;
172
- padding: 0 8px;
173
- border: none;
174
- border-radius: 4px;
175
- background: transparent;
176
- color: ${({ theme }) => theme.palette.text.primary};
177
- font: inherit;
178
- font-size: 12px;
179
- text-align: left;
180
- cursor: pointer;
181
-
182
- &:hover,
183
- &:focus-visible {
184
- background: ${({ theme }) => theme.palette.action.hover};
185
- outline: none;
186
- }
187
- `;
188
- const CustomColumn = styled.div `
189
- display: flex;
190
- flex-direction: column;
191
- gap: 10px;
192
- min-width: 0;
193
- `;
194
- const InputGrid = styled.div `
195
- display: grid;
196
- grid-template-columns: repeat(2, minmax(0, 1fr));
197
- gap: 8px;
198
-
199
- @media (max-width: 640px) {
200
- grid-template-columns: minmax(0, 1fr);
201
- }
202
- `;
203
- const EndpointField = styled.div `
204
- min-width: 0;
205
- `;
206
- const ActiveControlRow = styled.div `
207
- display: flex;
208
- align-items: center;
209
- justify-content: space-between;
210
- gap: 10px;
211
- `;
212
- const CalendarShell = styled.div `
213
- display: flex;
214
- justify-content: center;
215
- padding: 8px;
216
- overflow-x: auto;
217
- border: 1px solid ${({ theme }) => theme.palette.divider};
218
- border-radius: 5px;
219
- background: ${({ theme }) => theme.palette.background.paper};
220
- `;
221
- const ValidationText = styled.div `
222
- min-height: 16px;
223
- font-size: 11px;
224
- color: ${({ theme }) => theme.palette.error.main};
225
- `;
226
- const ActionRow = styled.div `
227
- display: flex;
228
- justify-content: flex-end;
229
- gap: 8px;
230
- `;
231
- const FooterMeta = styled.div `
232
- display: flex;
233
- align-items: center;
234
- gap: 5px;
235
- margin-right: auto;
236
- color: ${({ theme }) => theme.palette.text.secondary};
237
- font-size: 11px;
238
-
239
- svg {
240
- width: 13px;
241
- height: 13px;
242
- }
243
- `;
244
- const DateTimeRangePicker = forwardRef(({ className, style, defaultValue = { start: null, end: null }, value, onChange = () => { }, label, description, placeholder = "Select date/time range", startLabel = "Start", endLabel = "End", format = DEFAULT_FORMAT, size = "sm", variant = "outlined", required = false, clearable = true, disabled = false, error, width, min, max, utc = false, presets, }, ref) => {
245
- var _a, _b;
246
- const isControlled = useRef(value !== undefined);
247
- const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
248
- const _value = isControlled.current ? value || {} : uncontrolledValue;
249
- const [isOpen, setIsOpen] = useState(false);
250
- const [draftValue, setDraftValue] = useState(_value);
251
- const [activeEndpoint, setActiveEndpoint] = useState("start");
252
- const resolvedPresets = useMemo(() => presets || getDefaultPresets(utc), [presets, utc]);
253
- const { refs, floatingStyles, context } = useFloating({
254
- open: isOpen,
255
- onOpenChange: setIsOpen,
256
- placement: "bottom-start",
257
- strategy: "absolute",
258
- middleware: [offset(5), flip(), shift({ padding: 8 })],
259
- whileElementsMounted: autoUpdate,
260
- });
261
- const dismiss = useDismiss(context, {
262
- outsidePress: (event) => {
263
- var _a, _b, _c;
264
- const target = event.target;
265
- if (((_a = target === null || target === void 0 ? void 0 : target.closest) === null || _a === void 0 ? void 0 : _a.call(target, ".mfui-DateInput")) ||
266
- ((_b = target === null || target === void 0 ? void 0 : target.closest) === null || _b === void 0 ? void 0 : _b.call(target, ".mfui-DropDownMenu")) ||
267
- ((_c = target === null || target === void 0 ? void 0 : target.closest) === null || _c === void 0 ? void 0 : _c.call(target, ".Menu"))) {
268
- return false;
269
- }
270
- return true;
271
- },
272
- });
273
- const { getReferenceProps, getFloatingProps } = useInteractions([dismiss]);
274
- useEffect(() => {
275
- if (isOpen) {
276
- setDraftValue(_value);
277
- setActiveEndpoint(_value.start ? "end" : "start");
278
- }
279
- }, [isOpen, _value.start, _value.end]);
280
- const commitValue = useCallback((nextValue, meta) => {
281
- if (!isControlled.current) {
282
- setUncontrolledValue(nextValue);
283
- }
284
- onChange(nextValue, meta);
285
- }, [onChange]);
286
- const displayValue = useMemo(() => {
287
- if (!_value.start && !_value.end)
288
- return "";
289
- const start = formatDisplay(_value.start, format, utc) || "Start";
290
- const end = formatDisplay(_value.end, format, utc) || "End";
291
- return `${start} - ${end}${utc ? " UTC" : ""}`;
292
- }, [_value.start, _value.end, format, utc]);
293
- const validationError = useMemo(() => {
294
- const start = parseRangeMoment(draftValue.start, utc);
295
- const end = parseRangeMoment(draftValue.end, utc);
296
- if (!start || !end)
297
- return "Select both a start and end timestamp.";
298
- if (start.isAfter(end))
299
- return "Start timestamp must be before end.";
300
- if (min && start.isBefore(moment(min)))
301
- return "Start is before minimum.";
302
- if (max && end.isAfter(moment(max)))
303
- return "End is after maximum.";
304
- return "";
305
- }, [draftValue.start, draftValue.end, min, max, utc]);
306
- const patchDraft = (patch) => {
307
- setDraftValue((prev) => (Object.assign(Object.assign({}, prev), patch)));
308
- };
309
- const handleClear = (event) => {
310
- event === null || event === void 0 ? void 0 : event.preventDefault();
311
- event === null || event === void 0 ? void 0 : event.stopPropagation();
312
- const emptyValue = { start: null, end: null };
313
- setDraftValue(emptyValue);
314
- commitValue(emptyValue, { source: "clear" });
315
- setIsOpen(false);
316
- };
317
- const handleApply = () => {
318
- if (validationError)
319
- return;
320
- commitValue(draftValue, { source: "apply" });
321
- setIsOpen(false);
322
- };
323
- const handleCancel = () => {
324
- setDraftValue(_value);
325
- setIsOpen(false);
326
- };
327
- const handlePreset = (preset) => {
328
- const nextValue = preset.getRange();
329
- setDraftValue(nextValue);
330
- commitValue(nextValue, { source: "preset", preset });
331
- setIsOpen(false);
332
- };
333
- const handleCalendarChange = (date) => {
334
- if (!date) {
335
- patchDraft({ [activeEndpoint]: null });
336
- return;
337
- }
338
- patchDraft({
339
- [activeEndpoint]: serializeMoment(calendarDateToMoment(date, utc), utc),
340
- });
341
- };
342
- const activeValue = draftValue[activeEndpoint];
343
- const activeMin = activeEndpoint === "end"
344
- ? ((_a = parseRangeMoment(draftValue.start, utc)) === null || _a === void 0 ? void 0 : _a.toDate()) || min
345
- : min;
346
- const activeMax = activeEndpoint === "start"
347
- ? ((_b = parseRangeMoment(draftValue.end, utc)) === null || _b === void 0 ? void 0 : _b.toDate()) || max
348
- : max;
349
- return (_jsxs(StyledContainer, Object.assign({ ref: (node) => {
350
- if (typeof ref === "function") {
351
- ref(node);
352
- }
353
- else if (ref) {
354
- ref.current = node;
355
- }
356
- refs.setReference(node);
357
- }, className: className, "$width": width }, getReferenceProps(), { children: [label && (_jsx(FieldLabel, { error: error, asterisk: required, size: size, description: description, children: label })), _jsxs(StyledTrigger, { type: "button", size: size, variant: variant, disabled: disabled, style: style, "aria-haspopup": "dialog", "aria-expanded": isOpen, onClick: () => setIsOpen((prev) => !prev), children: [_jsx(TriggerIcon, { size: size, children: _jsx(CalendarDaysIcon, {}) }), _jsx(TriggerText, { "$empty": !displayValue, children: displayValue || placeholder }), _jsx(TriggerActions, { children: clearable && (_value.start || _value.end) ? (_jsx(ClearButton, { size: size, onClick: handleClear })) : (_jsx(ArrowButton, { size: size })) })] }), !disabled && isOpen && (_jsx(FloatingPortal, { preserveTabOrder: true, children: _jsx(StyledFloatContainer, Object.assign({ ref: refs.setFloating, style: floatingStyles }, getFloatingProps(), { children: _jsx(StyledContent, { maxDropdownHeight: "fit-content", children: _jsxs(PickerPanel, { children: [_jsxs(PresetColumn, { children: [_jsx(PanelTitle, { children: "Quick ranges" }), resolvedPresets.map((preset) => (_jsx(PresetButton, { type: "button", onClick: () => handlePreset(preset), children: preset.label }, preset.label)))] }), _jsxs(CustomColumn, { children: [_jsxs(InputGrid, { children: [_jsx(EndpointField, { onClick: () => setActiveEndpoint("start"), children: _jsx(DateInput, { label: startLabel, value: draftValue.start, onChange: (next) => patchDraft({ start: next }), format: format, size: size, variant: variant, clearable: true, utc: utc, min: min, max: activeEndpoint === "start" ? activeMax : max }) }), _jsx(EndpointField, { onClick: () => setActiveEndpoint("end"), children: _jsx(DateInput, { label: endLabel, value: draftValue.end, onChange: (next) => patchDraft({ end: next }), format: format, size: size, variant: variant, clearable: true, utc: utc, min: activeEndpoint === "end" ? activeMin : min, max: max }) })] }), _jsxs(ActiveControlRow, { children: [_jsxs(PanelTitle, { children: ["Editing ", activeEndpoint === "start" ? startLabel : endLabel] }), _jsx(SegmentedControl, { data: [
358
- { label: startLabel, value: "start" },
359
- { label: endLabel, value: "end" },
360
- ], value: activeEndpoint, onChange: (next) => setActiveEndpoint(next), size: "xs" })] }), _jsx(CalendarShell, { children: _jsx(Calendar, { value: momentToCalendarDate(activeValue, utc), onChange: handleCalendarChange, includeTime: true, clearable: false, min: activeMin, max: activeMax }) }), _jsx(ValidationText, { children: validationError }), _jsxs(ActionRow, { children: [_jsxs(FooterMeta, { children: [_jsx(Clock3Icon, {}), utc ? "UTC" : "Local time"] }), clearable && (_jsx(Button, { type: "button", size: size, variant: "subtle", onClick: handleClear, children: "Clear" })), _jsx(Button, { type: "button", size: size, variant: "outlined", onClick: handleCancel, children: "Cancel" }), _jsx(Button, { type: "button", size: size, variant: "contained", onClick: handleApply, disabled: Boolean(validationError), children: "Apply" })] })] })] }) }) })) }))] })));
361
- });
362
- DateTimeRangePicker.displayName = "DateTimeRangePicker";
363
- export default DateTimeRangePicker;
@@ -1,2 +0,0 @@
1
- export { default } from "./DateTimeRangePicker";
2
- export * from "./DateTimeRangePicker";
@@ -1,2 +0,0 @@
1
- export { default } from "./DateTimeRangePicker";
2
- export * from "./DateTimeRangePicker";
@@ -1 +0,0 @@
1
- export { DefaultOperators, Operators, DEFAULT_QUERY_FILTER_OPERATORS, QUERY_FILTER_OPERATORS, } from "./QueryFilter.constants";
@@ -1 +0,0 @@
1
- export { DefaultOperators, Operators, DEFAULT_QUERY_FILTER_OPERATORS, QUERY_FILTER_OPERATORS, } from "./QueryFilter.constants";
@@ -1 +0,0 @@
1
- export * from "./QueryFilter.types";
@@ -1 +0,0 @@
1
- export * from "./QueryFilter.types";
@@ -1,3 +0,0 @@
1
- import { ResizeHandlerProps } from "../types";
2
- declare const resizeHandler: ({ event, columnId, columnProps, onResize, onResizeFinished, }: ResizeHandlerProps) => void;
3
- export default resizeHandler;
@@ -1,84 +0,0 @@
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;