aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/ObservableReactComponent.tsx27
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx10
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx9
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx7
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx7
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx12
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx11
-rw-r--r--src/client/views/nodes/DiagramBox.tsx12
-rw-r--r--src/client/views/nodes/ImageBox.scss9
-rw-r--r--src/client/views/nodes/ImageBox.tsx156
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx7
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx6
-rw-r--r--src/server/ApiManagers/FireflyManager.ts12
14 files changed, 174 insertions, 116 deletions
diff --git a/src/client/views/ObservableReactComponent.tsx b/src/client/views/ObservableReactComponent.tsx
index bb7a07f0e..2290516dc 100644
--- a/src/client/views/ObservableReactComponent.tsx
+++ b/src/client/views/ObservableReactComponent.tsx
@@ -15,6 +15,33 @@ export abstract class ObservableReactComponent<T> extends React.Component<T, obj
this._props = props;
makeObservable(this);
}
+ __passiveWheel: HTMLElement | null = null;
+ _isContentActive: () => boolean | undefined = () => false;
+
+ /**
+ * default method to stop wheel events from bubbling up to parent components.
+ * @param e
+ */
+ onPassiveWheel = (e: WheelEvent) => {
+ if (this._isContentActive?.()) e.stopPropagation();
+ };
+
+ /**
+ * This fixes the problem where a component uses wheel events to scroll, but is nested inside another component that
+ * can also scroll. In that case, the wheel event will bubble up to the parent component and cause it to scroll in addition.
+ * This is based on the native HTML5 behavior where wheel events are passive by default, meaning that they do not prevent the default action of scrolling.
+ * This method should be called from a ref={} property on or above the component that uses wheel events to scroll.
+ * @param ele HTMLELement containing the component that will scroll
+ * @param isContentActive function determining if the component is active and should handle the wheel event.
+ * @param onPassiveWheel an optional function to call to handle the wheel event (and block its propagation. If omitted, the event won't propagate.
+ */
+ fixWheelEvents = (ele: HTMLElement | null, isContentActive: () => boolean | undefined, onPassiveWheel?: (e: WheelEvent) => void) => {
+ this._isContentActive = isContentActive;
+ this.__passiveWheel?.removeEventListener('wheel', onPassiveWheel ?? this.onPassiveWheel);
+ this.__passiveWheel = ele;
+ ele?.addEventListener('wheel', onPassiveWheel ?? this.onPassiveWheel, { passive: false });
+ };
+
componentDidUpdate(prevProps: Readonly<T>): void {
Object.keys(prevProps)
.filter(pkey => (prevProps as {[key:string]: unknown})[pkey] !== (this.props as {[key:string]: unknown})[pkey])
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 50de7c601..d5edc3e0b 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -40,7 +40,6 @@ import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
export class CollectionCardView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
private _disposers: { [key: string]: IReactionDisposer } = {};
- private _oldWheel: HTMLElement | null = null;
private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center)
private _setCurDocScript = () => ScriptField.MakeScript('scriptContext.layoutDoc._card_curDoc=this', { scriptContext: 'any' })!;
private _draggerRef = React.createRef<HTMLDivElement>();
@@ -56,13 +55,7 @@ export class CollectionCardView extends CollectionSubView() {
}
protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
this._dropDisposer?.();
- if (ele) {
- this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
- }
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = ele;
- // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
- ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ this.fixWheelEvents(ele, this._props.isContentActive);
};
@computed get cardWidth() {
return NumCast(this.layoutDoc._cardWidth, 50);
@@ -487,7 +480,6 @@ export class CollectionCardView extends CollectionSubView() {
);
});
}
- onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
contentScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1);
docViewProps = (): DocumentViewProps => ({
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 9c8ef5519..755e31925 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -25,7 +25,6 @@ const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = requi
@observer
export class CollectionCarousel3DView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
- private _oldWheel: HTMLElement | null = null;
constructor(props: SubCollectionViewProps) {
super(props);
@@ -44,10 +43,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
if (ele) {
this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
}
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = ele;
- // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
- ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ this.fixWheelEvents(ele, this._props.isContentActive);
};
@computed get scrollSpeed() {
@@ -101,7 +97,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
focus = (anchor: Doc, options: FocusViewOptions): Opt<number> => {
const docs = DocListCast(this.Document[this.fieldKey]);
if (anchor.type === DocumentType.CONFIG || docs.includes(anchor)) {
- const newIndex = anchor.config_carousel_index ?? docs.getIndex(DocCast(anchor.annotationOn, anchor));
+ const newIndex = anchor.config_carousel_index ?? docs.getIndex(DocCast(anchor.annotationOn, anchor)!);
options.didMove = newIndex !== this.layoutDoc._carousel_index;
options.didMove && (this.layoutDoc._carousel_index = newIndex);
}
@@ -221,7 +217,6 @@ export class CollectionCarousel3DView extends CollectionSubView() {
return this.panelWidth() * (1 - index);
}
- onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
curDoc = () => this.carouselItems[NumCast(this.layoutDoc._carousel_index)]?.layout;
answered = (correct: boolean) => (!correct || !this.curDoc() || NumCast(this.layoutDoc._carousel_index) === this.carouselItems.length - 1) && this.changeSlide(1);
docViewProps = () => ({
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 975dc52fe..ac1981012 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -21,7 +21,6 @@ import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
export class CollectionCarouselView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
- _oldWheel: HTMLElement | null = null;
_fadeTimer: NodeJS.Timeout | undefined;
@observable _last_index = this.carouselIndex;
@observable _last_opacity = 1;
@@ -43,10 +42,7 @@ export class CollectionCarouselView extends CollectionSubView() {
if (ele) {
this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
}
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = ele;
- // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
- ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ this.fixWheelEvents(ele, this._props.isContentActive);
};
@computed get captionMarginX(){ return NumCast(this.layoutDoc.caption_xMargin, 50); } // prettier-ignore
@@ -115,7 +111,6 @@ export class CollectionCarouselView extends CollectionSubView() {
: this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
? false
: undefined; // prettier-ignore
- onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
renderDoc = (doc: Doc, showCaptions: boolean, overlayFunc?: (r: DocumentView | null) => void) => {
return (
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index f11e646cc..be570564b 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -55,7 +55,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
_docXfs: { height: () => number; width: () => number; stackedDocTransform: () => Transform }[] = [];
// Doesn't look like this field is being used anywhere. Obsolete?
_columnStart: number = 0;
- _oldWheel: HTMLElement | null = null;
@observable _refList: HTMLElement[] = [];
// map of node headers to their heights. Used in Masonry
@@ -721,7 +720,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return this._props.isContentActive() === false ? 'none' : undefined;
}
- onPassiveWheel = (e: WheelEvent) => this._props.isContentActive() && e.stopPropagation();
render() {
TraceMobx();
const editableViewProps = {
@@ -744,10 +742,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
ref={ele => {
this._masonryGridRef = ele;
this.createDashEventsTarget(ele); // so the whole grid is the drop target?
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = ele;
- // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
- ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ this.fixWheelEvents(ele, this._props.isContentActive);
}}
style={{
overflowY: this.isContentActive() ? 'auto' : 'hidden',
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c4971c204..2364fd74a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -2268,10 +2268,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
id={this._paintedId}
ref={r => {
this.createDashEventsTarget(r);
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = r;
- // prevent wheel events from passivly propagating up through containers
- r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel);
r?.addEventListener('mouseleave', this.onMouseLeave);
r?.addEventListener('mouseenter', this.onMouseEnter);
}}
diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index 624c85beb..142085e14 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -150,11 +150,6 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this.Document);
}, 'remove doc from face');
- /**
- * This stops scroll wheel events when they are used to scroll the face collection.
- */
- onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
-
render() {
return (
<div className="face-document-item" ref={ele => this.createDropTarget(ele!)}>
@@ -181,12 +176,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
style={{
pointerEvents: this._props.isContentActive() ? undefined : 'none',
}}
- ref={action((ele: HTMLDivElement | null) => {
- this._listRef?.removeEventListener('wheel', this.onPassiveWheel);
- this._listRef = ele;
- // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
- ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
- })}>
+ ref={r => this.fixWheelEvents(r, this._props.isContentActive)}>
{FaceRecognitionHandler.UniqueFaceImages(this.Document).map((doc, i) => {
const [name, type] = ImageCastToNameType(doc?.[Doc.LayoutDataKey(doc)]) ?? ['-missing-', '.png'];
return (
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 82ca96839..c06391f35 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1293,7 +1293,6 @@ export class CollectionSchemaView extends CollectionSubView() {
isContentActive = () => this._props.isSelected() || this._props.isContentActive();
screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0);
previewWidthFunc = () => this.previewWidth;
- onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
displayedDocsFunc = () => this.docsWithDrag.docs;
render() {
return (
@@ -1307,15 +1306,7 @@ export class CollectionSchemaView extends CollectionSubView() {
this.setColDrag(false);
}}>
<div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }} />
- <div
- className="schema-table"
- style={{ width: `calc(100% - ${this.previewWidth}px)` }}
- onWheel={e => this._props.isContentActive() && e.stopPropagation()}
- ref={ele => {
- // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- (this._oldWheel = ele)?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
- }}>
+ <div className="schema-table" style={{ width: `calc(100% - ${this.previewWidth}px)` }} onWheel={e => this._props.isContentActive() && e.stopPropagation()} ref={ele => this.fixWheelEvents(ele, this._props.isContentActive)}>
<div className="schema-header-row" style={{ height: this.rowHeightFunc() }}>
<div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
<IconButton
diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx
index 3b666bad5..7cfccf0dc 100644
--- a/src/client/views/nodes/DiagramBox.tsx
+++ b/src/client/views/nodes/DiagramBox.tsx
@@ -185,11 +185,6 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return '( )';
};
- /**
- * This stops scroll wheel events when they are used to scroll the face collection.
- */
- onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
-
render() {
return (
<div
@@ -197,12 +192,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
style={{
pointerEvents: this._props.isContentActive() ? undefined : 'none',
}}
- ref={action((ele: HTMLDivElement | null) => {
- this._boxRef?.removeEventListener('wheel', this.onPassiveWheel);
- this._boxRef = ele;
- // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
- ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
- })}>
+ ref={r => this.fixWheelEvents(r, this._props.isContentActive)}>
<div className="DIYNodeBox-searchbar">
<input type="text" value={this._inputValue} onKeyDown={action(e => e.key === 'Enter' && this.generateMermaidCode())} onChange={action(e => (this._inputValue = e.target.value))} />
<button type="button" onClick={this.generateMermaidCode}>
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index ac1a6ece9..9f7a5d03f 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -106,7 +106,7 @@
height: 100%;
img {
object-fit: contain;
- height: fit-content;
+ height: 100%;
}
.imageBox-fadeBlocker,
@@ -242,12 +242,9 @@
}
}
.imageBox-regenerate-dialog {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
+ position: absolute;
background: white;
- padding: 20px;
+ padding: 10px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
z-index: 10000;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 31a135fa7..d16baada6 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,4 +1,4 @@
-import { Button, Colors, EditableText, Size, Type } from '@dash/components';
+import { Button, Colors, EditableText, IconButton, Size, Toggle, ToggleType, Type } from '@dash/components';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Slider, Tooltip } from '@mui/material';
import axios from 'axios';
@@ -353,6 +353,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
openOutpaintPrompt = () => {
+ this._outpaintVAlign = '';
+ this._outpaintAlign = '';
this._showOutpaintPrompt = true;
};
@@ -362,6 +364,16 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
@action
+ cancelOutpaintPrompt = () => {
+ const origWidth = NumCast(this.Document[this.fieldKey + '_outpaintOriginalWidth']);
+ const origHeight = NumCast(this.Document[this.fieldKey + '_outpaintOriginalHeight']);
+ this.Document._width = origWidth;
+ this.Document._height = origHeight;
+ this._outpaintingInProgress = false;
+ this.closeOutpaintPrompt();
+ };
+
+ @action
handlePromptChange = (val: string | number) => {
this._outpaintPromptInput = '' + val;
};
@@ -377,17 +389,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const field = Cast(this.dataDoc[this.fieldKey], ImageField);
if (!field) return;
- const origWidth = NumCast(this.Document[this.fieldKey + '_outpaintOriginalWidth']);
- const origHeight = NumCast(this.Document[this.fieldKey + '_outpaintOriginalHeight']);
-
// Set flag that outpainting is in progress
this._outpaintingInProgress = true;
// Revert dimensions if prompt is blank (acts like Cancel)
if (!customPrompt) {
- this.Document._width = origWidth;
- this.Document._height = origHeight;
- this._outpaintingInProgress = false;
+ this.cancelOutpaintPrompt();
return;
}
@@ -410,11 +417,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
loadingOverlay.innerHTML = '<div style="color: white; font-size: 16px;">Generating outpainted image...</div>';
this._mainCont?.appendChild(loadingOverlay);
+ const origWidth = NumCast(this.Document[this.fieldKey + '_outpaintOriginalWidth']);
+ const origHeight = NumCast(this.Document[this.fieldKey + '_outpaintOriginalHeight']);
const response = await Networking.PostToServer('/outpaintImage', {
imageUrl: currentPath,
prompt: customPrompt,
originalDimensions: { width: Math.min(newWidth, origWidth), height: Math.min(newHeight, origHeight) },
newDimensions: { width: newWidth, height: newHeight },
+ halignment: this._outpaintAlign,
+ valignment: this._outpaintVAlign,
});
const error = ('error' in response && (response.error as string)) || '';
@@ -447,8 +458,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this.Document[this.fieldKey + '_outpaintOriginalWidth'] = undefined;
this.Document[this.fieldKey + '_outpaintOriginalHeight'] = undefined;
} else {
- this.Document._width = origWidth;
- this.Document._height = origHeight;
+ this.cancelOutpaintPrompt();
alert('Failed to receive a valid image URL from server.');
}
batch.end();
@@ -456,30 +466,106 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._mainCont?.removeChild(loadingOverlay);
} catch (error) {
- console.error('Error during outpainting:', error);
- this.Document._width = origWidth;
- this.Document._height = origHeight;
- alert('An error occurred while outpainting. Please try again.');
+ this.cancelOutpaintPrompt();
+ alert('An error occurred while outpainting.' + error);
} finally {
runInAction(() => (this._outpaintingInProgress = false));
}
};
- componentUI = () =>
+ @observable _outpaintAlign = '';
+ @observable _outpaintVAlign = '';
+ @computed get outpaintVertical() {
+ return this._props.PanelWidth() / this._props.PanelHeight() < this.nativeSize.nativeWidth / this.nativeSize.nativeHeight;
+ }
+
+ componentUI = (/* boundsLeft: number, boundsTop: number*/) =>
!this._showOutpaintPrompt ? null : (
- <div key="imageBox-componentui" className="imageBox-regenerate-dialog" style={{ backgroundColor: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
- <h3>Outpaint Image</h3>
- <EditableText
- placeholder="Enter a prompt for extending the image:"
- setVal={val => this.handlePromptChange(val)}
- val={this._outpaintPromptInput}
- type={Type.TERT}
- color={SettingsManager.userColor}
- background={SettingsManager.userBackgroundColor}
- />
- <div className="buttons">
- <Button text="Cancel" type={Type.TERT} onClick={this.closeOutpaintPrompt} color={SnappingManager.userColor} background={SnappingManager.userVariantColor} />
- <Button text="Generate" type={Type.TERT} onClick={this.submitOutpaintPrompt} color={SnappingManager.userColor} background={SnappingManager.userVariantColor} />
+ <div
+ key="imageBox-componentui"
+ className="imageBox-regenerate-dialog"
+ style={{
+ top: -70 + (this._props.DocumentView?.().getBounds?.top ?? 0),
+ left: this._props.DocumentView?.().getBounds?.left ?? 0,
+ backgroundColor: SettingsManager.userBackgroundColor,
+ color: SettingsManager.userColor,
+ }}>
+ <div style={{ position: 'absolute', top: 5, right: 5 }}>
+ <IconButton type={Type.TERT} onClick={this.cancelOutpaintPrompt} icon={<FontAwesomeIcon icon="times" color={'red'} />} color={SnappingManager.userColor} background={SnappingManager.userVariantColor} />
+ </div>
+ <div>Outpaint Image</div>
+ <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
+ <EditableText
+ placeholder="Enter a prompt for extending the image:"
+ setVal={val => this.handlePromptChange(val)}
+ val={this._outpaintPromptInput}
+ type={Type.TERT}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
+ />
+ <div className="buttons" style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
+ <IconButton type={Type.TERT} onClick={this.submitOutpaintPrompt} icon={<AiOutlineSend />} color={SnappingManager.userColor} background={SnappingManager.userVariantColor} />
+ <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
+ {this.outpaintVertical ? null : (
+ <Toggle
+ type={Type.TERT}
+ toggleType={ToggleType.BUTTON}
+ toggleStatus={this._outpaintAlign === 'left' && this._outpaintVAlign === ''}
+ onClick={action(() => (this._outpaintAlign = 'left'))}
+ icon={<FontAwesomeIcon icon="chevron-left" color={SnappingManager.userColor} />}
+ color={SnappingManager.userColor}
+ background={SnappingManager.userVariantColor}
+ />
+ )}
+ <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
+ {!this.outpaintVertical ? null : (
+ <Toggle
+ type={Type.TERT}
+ toggleType={ToggleType.BUTTON}
+ toggleStatus={this._outpaintAlign === '' && this._outpaintVAlign === 'top'}
+ onClick={action(() => (this._outpaintVAlign = 'top'))}
+ icon={<FontAwesomeIcon icon="chevron-up" color={SnappingManager.userColor} />}
+ color={SnappingManager.userColor}
+ background={SnappingManager.userColor}
+ />
+ )}
+ <Toggle
+ type={Type.TERT}
+ toggleType={ToggleType.BUTTON}
+ toggleStatus={this._outpaintAlign === '' && this._outpaintVAlign === ''}
+ onClick={action(() => {
+ this._outpaintAlign = '';
+ this._outpaintVAlign = '';
+ })}
+ icon={<FontAwesomeIcon icon="bullseye" color={SnappingManager.userColor} />}
+ color={SnappingManager.userColor}
+ background={SnappingManager.userColor}
+ />
+ {!this.outpaintVertical ? null : (
+ <Toggle
+ type={Type.TERT}
+ toggleType={ToggleType.BUTTON}
+ toggleStatus={this._outpaintAlign === '' && this._outpaintVAlign === 'bottom'}
+ onClick={action(() => (this._outpaintVAlign = 'bottom'))}
+ icon={<FontAwesomeIcon icon="chevron-down" color={SnappingManager.userColor} />}
+ color={SnappingManager.userColor}
+ background={SnappingManager.userColor}
+ />
+ )}
+ </div>
+ {this.outpaintVertical ? null : (
+ <Toggle
+ type={Type.TERT}
+ toggleType={ToggleType.BUTTON}
+ toggleStatus={this._outpaintAlign === 'right' && this._outpaintVAlign === ''}
+ onClick={action(() => (this._outpaintAlign = 'right'))}
+ icon={<FontAwesomeIcon icon="chevron-right" color={SnappingManager.userColor} />}
+ color={SnappingManager.userColor}
+ background={SnappingManager.userColor}
+ />
+ )}
+ </div>
+ </div>
</div>
</div>
);
@@ -718,13 +804,25 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
})}
key={this.layoutDoc[Id]}
onPointerDown={this.marqueeDown}>
- <div className="imageBox-fader" style={{ opacity: backAlpha }}>
+ <div
+ className="imageBox-fader"
+ style={{
+ opacity: backAlpha,
+ flexDirection: this._outpaintVAlign ? 'row' : 'column',
+ alignItems: this._outpaintAlign === 'left' || this._outpaintVAlign === 'top' ? 'flex-start' : this._outpaintAlign === 'right' || this._outpaintVAlign === 'bottom' ? 'flex-end' : undefined,
+ }}>
<img
alt=""
ref={action((r: HTMLImageElement | null) => (this.imageRef = r))}
key="paths"
src={srcpath}
- style={{ transform, transformOrigin, height: this.Document[this.fieldKey + '_outpaintOriginalWidth'] !== undefined ? '100%' : undefined }}
+ style={{
+ position: 'relative',
+ transform,
+ transformOrigin,
+ width: this._outpaintAlign ? 'max-content' : this._outpaintAlign ? '100%' : undefined,
+ height: this._outpaintVAlign ? 'max-content' : this.Document[this.fieldKey + '_outpaintOriginalWidth'] !== undefined ? '100%' : undefined,
+ }}
onError={action(e => (this._error = e.toString()))}
draggable={false}
width={nativeWidth}
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index bebd86ac2..df505eb16 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -26,7 +26,6 @@ type CalendarView = 'multiMonth' | 'dayGridMonth' | 'timeGridWeek' | 'timeGridDa
export class CalendarBox extends CollectionSubView() {
_calendarRef: HTMLDivElement | null = null;
_calendar: Calendar | undefined;
- _oldWheel: HTMLElement | null = null;
_observer: ResizeObserver | undefined;
_eventsDisposer: IReactionDisposer | undefined;
_selectDisposer: IReactionDisposer | undefined;
@@ -251,7 +250,6 @@ export class CalendarBox extends CollectionSubView() {
setTimeout(() => cal?.view.calendar.select(this.dateSelect.start, this.dateSelect.end));
};
- onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
render() {
return (
<div
@@ -275,10 +273,7 @@ export class CalendarBox extends CollectionSubView() {
}}
ref={r => {
this.createDashEventsTarget(r);
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = r;
- // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
- r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ this.fixWheelEvents(r, this._props.isContentActive);
if (r) {
this._observer?.disconnect();
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d6fa3172d..c51f6c38b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2120,11 +2120,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
) : styleFromLayout?.height === '0px' ? null : (
<div
className="formattedTextBox"
- ref={r => {
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = r;
- r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
- }}
+ ref={r => this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel)}
style={{
...(this._props.dontScale
? {}
diff --git a/src/server/ApiManagers/FireflyManager.ts b/src/server/ApiManagers/FireflyManager.ts
index 1b8a85a5c..e934e635b 100644
--- a/src/server/ApiManagers/FireflyManager.ts
+++ b/src/server/ApiManagers/FireflyManager.ts
@@ -343,14 +343,14 @@ export default class FireflyManager extends ApiManager {
numVariations: 1,
placement: {
inset: {
- left: Math.round((req.body.newDimensions.width - req.body.originalDimensions.width) / 2),
- top: Math.round((req.body.newDimensions.height - req.body.originalDimensions.height) / 2),
- right: Math.round((req.body.newDimensions.width - req.body.originalDimensions.width) / 2),
- bottom: Math.round((req.body.newDimensions.height - req.body.originalDimensions.height) / 2),
+ left: 0, // Math.round((req.body.newDimensions.width - req.body.originalDimensions.width) / 2),
+ top: 0, // Math.round((req.body.newDimensions.height - req.body.originalDimensions.height) / 2),
+ right: 0, // Math.round((req.body.newDimensions.width - req.body.originalDimensions.width) / 2),
+ bottom: 0, // Math.round((req.body.newDimensions.height - req.body.originalDimensions.height) / 2),
},
alignment: {
- horizontal: 'center',
- vertical: 'center',
+ horizontal: req.body.halignment || 'center',
+ vertical: req.body.valignment || 'center',
},
},
}),