mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Floating formula editor
Summary: Adding a way to detach an editor. Initially only implemented for the formula editor, includes redesign for the AI part. - Initially, the detached editor is tight with the formula assistant and both are behind GRIST_FORMULA_ASSISTANT flag, but this can be relaxed later on, as the detached editor can be used on its own. - Detached editor is only supported in regular fields and on the creator panel. It is not supported yet for conditional styles, due to preview limitations. - Old code for the assistant was removed completely, as it was only a temporary solution, but the AI conversation part was copied to the new one. - Prompting was not modified in this diff, it will be included in the follow-up with more test cases. Test Plan: Added only new tests; existing tests should pass. Reviewers: JakubSerafin Reviewed By: JakubSerafin Differential Revision: https://phab.getgrist.com/D3863
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import {documentCursor} from 'app/client/lib/popupUtils';
|
||||
import {hoverTooltip} from 'app/client/ui/tooltips';
|
||||
import {isNarrowScreen, isNarrowScreenObs, theme, vars} from 'app/client/ui2018/cssVars';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {Disposable, dom, DomArg, DomContents, IDisposable, makeTestId, Observable, styled} from 'grainjs';
|
||||
import {Disposable, dom, DomContents, DomElementArg,
|
||||
IDisposable, makeTestId, Observable, styled} from 'grainjs';
|
||||
|
||||
const POPUP_INITIAL_PADDING_PX = 16;
|
||||
const POPUP_MIN_HEIGHT = 300;
|
||||
@@ -15,9 +17,11 @@ export interface PopupOptions {
|
||||
content?: () => DomContents;
|
||||
onClose?: () => void;
|
||||
closeButton?: boolean;
|
||||
closeButtonHover?: () => DomContents;
|
||||
autoHeight?: boolean;
|
||||
/** Defaults to false. */
|
||||
stopClickPropagationOnMove?: boolean;
|
||||
args?: DomElementArg[];
|
||||
}
|
||||
|
||||
export class FloatingPopup extends Disposable {
|
||||
@@ -34,7 +38,7 @@ export class FloatingPopup extends Disposable {
|
||||
private _resize = false;
|
||||
private _cursorGrab: IDisposable|null = null;
|
||||
|
||||
constructor(protected _options: PopupOptions = {}, private _args: DomArg[] = []) {
|
||||
constructor(protected _options: PopupOptions = {}) {
|
||||
super();
|
||||
|
||||
if (_options.stopClickPropagationOnMove){
|
||||
@@ -98,7 +102,7 @@ export class FloatingPopup extends Disposable {
|
||||
}
|
||||
|
||||
protected _buildArgs(): any {
|
||||
return this._args;
|
||||
return this._options.args ?? [];
|
||||
}
|
||||
|
||||
private _rememberPosition() {
|
||||
@@ -272,12 +276,12 @@ export class FloatingPopup extends Disposable {
|
||||
// Copy buttons on the left side of the header, to automatically
|
||||
// center the title.
|
||||
cssPopupButtons(
|
||||
!this._options.closeButton ? null : cssPopupHeaderButton(
|
||||
icon('CrossSmall'),
|
||||
),
|
||||
cssPopupHeaderButton(
|
||||
icon('Maximize')
|
||||
),
|
||||
!this._options.closeButton ? null : cssPopupHeaderButton(
|
||||
icon('CrossBig'),
|
||||
),
|
||||
dom.style('visibility', 'hidden'),
|
||||
),
|
||||
cssPopupTitle(
|
||||
@@ -285,19 +289,20 @@ export class FloatingPopup extends Disposable {
|
||||
testId('title'),
|
||||
),
|
||||
cssPopupButtons(
|
||||
!this._options.closeButton ? null : cssPopupHeaderButton(
|
||||
icon('CrossSmall'),
|
||||
dom.on('click', () => {
|
||||
this._options.onClose?.() ?? this._closePopup();
|
||||
}),
|
||||
testId('close'),
|
||||
),
|
||||
this._popupMinimizeButtonElement = cssPopupHeaderButton(
|
||||
isMinimized ? icon('Maximize'): icon('Minimize'),
|
||||
hoverTooltip(isMinimized ? 'Maximize' : 'Minimize', {key: 'docTutorialTooltip'}),
|
||||
dom.on('click', () => this._minimizeOrMaximize()),
|
||||
testId('minimize-maximize'),
|
||||
),
|
||||
!this._options.closeButton ? null : cssPopupHeaderButton(
|
||||
icon('CrossBig'),
|
||||
dom.on('click', () => {
|
||||
this._options.onClose?.() ?? this._closePopup();
|
||||
}),
|
||||
testId('close'),
|
||||
this._options.closeButtonHover && hoverTooltip(this._options.closeButtonHover())
|
||||
),
|
||||
// Disable dragging when a button in the header is clicked.
|
||||
dom.on('mousedown', ev => ev.stopPropagation()),
|
||||
dom.on('touchstart', ev => ev.stopPropagation()),
|
||||
@@ -345,20 +350,7 @@ export class FloatingPopup extends Disposable {
|
||||
private _forceCursor() {
|
||||
this._cursorGrab?.dispose();
|
||||
const type = this._resize ? 'ns-resize' : 'grabbing';
|
||||
const cursorStyle: HTMLStyleElement = document.createElement('style');
|
||||
cursorStyle.innerHTML = `*{cursor: ${type}!important;}`;
|
||||
cursorStyle.id = 'cursor-style';
|
||||
document.head.appendChild(cursorStyle);
|
||||
const cursorOwner = {
|
||||
dispose() {
|
||||
if (this.isDisposed()) { return; }
|
||||
document.head.removeChild(cursorStyle);
|
||||
},
|
||||
isDisposed() {
|
||||
return !cursorStyle.isConnected;
|
||||
}
|
||||
};
|
||||
this._cursorGrab = cursorOwner;
|
||||
this._cursorGrab = documentCursor(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +364,7 @@ const POPUP_HEIGHT = `min(var(--height), calc(100% - (2 * ${POPUP_INITIAL_PADDIN
|
||||
const POPUP_HEIGHT_MOBILE = `min(var(--height), calc(100% - (2 * ${POPUP_INITIAL_PADDING_PX}px) - (2 * 50px)))`;
|
||||
const POPUP_WIDTH = `min(436px, calc(100% - (2 * ${POPUP_INITIAL_PADDING_PX}px)))`;
|
||||
|
||||
const cssPopup = styled('div', `
|
||||
const cssPopup = styled('div.floating-popup', `
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
Reference in New Issue
Block a user