@monolith-forensics/monolith-ui 1.8.1-dev.4 → 1.9.1-dev.1

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
  }
@@ -60,20 +60,123 @@ const getImageFilename = (image) => {
60
60
  return "image.png";
61
61
  };
62
62
  const getImageBlob = (src) => __awaiter(void 0, void 0, void 0, function* () {
63
- const response = yield fetch(src);
63
+ const response = yield fetch(src, {
64
+ mode: "cors",
65
+ credentials: "omit",
66
+ });
64
67
  if (!response.ok) {
65
68
  throw new Error("Unable to load image.");
66
69
  }
67
- return response.blob();
70
+ return {
71
+ blob: yield response.blob(),
72
+ contentType: response.headers.get("content-type") || "",
73
+ };
74
+ });
75
+ const clipboardPngType = "image/png";
76
+ const imageMimeTypesByExtension = {
77
+ gif: "image/gif",
78
+ jpg: "image/jpeg",
79
+ jpeg: "image/jpeg",
80
+ png: clipboardPngType,
81
+ svg: "image/svg+xml",
82
+ webp: "image/webp",
83
+ };
84
+ const normalizeMimeType = (type) => type.toLowerCase().split(";")[0].trim();
85
+ const getImageMimeTypeFromSource = (src) => {
86
+ var _a;
87
+ try {
88
+ const url = new URL(src);
89
+ const filename = url.pathname.split("/").filter(Boolean).pop();
90
+ const extension = (_a = filename === null || filename === void 0 ? void 0 : filename.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
91
+ return extension ? imageMimeTypesByExtension[extension] || "" : "";
92
+ }
93
+ catch (_b) {
94
+ const dataUrlMatch = src.match(/^data:([^;,]+)/);
95
+ return (dataUrlMatch === null || dataUrlMatch === void 0 ? void 0 : dataUrlMatch[1]) || "";
96
+ }
97
+ };
98
+ const canWriteClipboardType = (ClipboardItemCtor, type) => {
99
+ if (!type)
100
+ return false;
101
+ if (typeof ClipboardItemCtor.supports === "function") {
102
+ return ClipboardItemCtor.supports(type);
103
+ }
104
+ return type === clipboardPngType;
105
+ };
106
+ const loadImageSource = (src) => new Promise((resolve, reject) => {
107
+ const image = new Image();
108
+ image.crossOrigin = "anonymous";
109
+ image.onload = () => resolve(image);
110
+ image.onerror = () => {
111
+ reject(new Error("Unable to prepare image for clipboard."));
112
+ };
113
+ image.src = src;
114
+ });
115
+ const renderImageSourceToPngBlob = (src) => __awaiter(void 0, void 0, void 0, function* () {
116
+ const image = yield loadImageSource(src);
117
+ const width = image.naturalWidth || image.width;
118
+ const height = image.naturalHeight || image.height;
119
+ if (!width || !height) {
120
+ throw new Error("Unable to prepare image for clipboard.");
121
+ }
122
+ const canvas = document.createElement("canvas");
123
+ canvas.width = width;
124
+ canvas.height = height;
125
+ const context = canvas.getContext("2d");
126
+ if (!context) {
127
+ throw new Error("Unable to prepare image for clipboard.");
128
+ }
129
+ context.drawImage(image, 0, 0, width, height);
130
+ return new Promise((resolve, reject) => {
131
+ canvas.toBlob((blob) => {
132
+ if (blob) {
133
+ resolve(blob);
134
+ }
135
+ else {
136
+ reject(new Error("Unable to prepare image for clipboard."));
137
+ }
138
+ }, clipboardPngType);
139
+ });
140
+ });
141
+ const convertBlobToClipboardPng = (blob, fallbackSrc) => __awaiter(void 0, void 0, void 0, function* () {
142
+ const objectUrl = URL.createObjectURL(blob);
143
+ try {
144
+ return yield renderImageSourceToPngBlob(objectUrl);
145
+ }
146
+ catch (error) {
147
+ if (!fallbackSrc || fallbackSrc === objectUrl)
148
+ throw error;
149
+ return renderImageSourceToPngBlob(fallbackSrc);
150
+ }
151
+ finally {
152
+ URL.revokeObjectURL(objectUrl);
153
+ }
154
+ });
155
+ const getClipboardImageBlob = (image, ClipboardItemCtor) => __awaiter(void 0, void 0, void 0, function* () {
156
+ const src = image.currentSrc || image.src;
157
+ const { blob, contentType } = yield getImageBlob(src);
158
+ const type = normalizeMimeType(blob.type) ||
159
+ normalizeMimeType(contentType) ||
160
+ getImageMimeTypeFromSource(src);
161
+ if (canWriteClipboardType(ClipboardItemCtor, type)) {
162
+ return {
163
+ blob: blob.type === type ? blob : new Blob([blob], { type }),
164
+ type,
165
+ };
166
+ }
167
+ return {
168
+ blob: yield convertBlobToClipboardPng(blob, src),
169
+ type: clipboardPngType,
170
+ };
68
171
  });
69
172
  const copyImage = (image) => __awaiter(void 0, void 0, void 0, function* () {
70
173
  var _a;
71
- const ClipboardItemCtor = window.ClipboardItem;
174
+ const ClipboardItemCtor = window
175
+ .ClipboardItem;
72
176
  if (!((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.write) || !ClipboardItemCtor) {
73
177
  throw new Error("Image copying is not supported by this browser.");
74
178
  }
75
- const blob = yield getImageBlob(image.src);
76
- const type = blob.type || "image/png";
179
+ const { blob, type } = yield getClipboardImageBlob(image, ClipboardItemCtor);
77
180
  yield navigator.clipboard.write([
78
181
  new ClipboardItemCtor({
79
182
  [type]: blob,
@@ -85,7 +188,7 @@ const downloadImage = (image) => __awaiter(void 0, void 0, void 0, function* ()
85
188
  let href = image.src;
86
189
  let objectUrl = null;
87
190
  try {
88
- const blob = yield getImageBlob(image.src);
191
+ const { blob } = yield getImageBlob(image.src);
89
192
  objectUrl = URL.createObjectURL(blob);
90
193
  href = objectUrl;
91
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monolith-forensics/monolith-ui",
3
- "version": "1.8.1-dev.4",
3
+ "version": "1.9.1-dev.1",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Matt Danner (Monolith Forensics LLC)",