(core) updates from grist-core

This commit is contained in:
Paul Fitzpatrick
2023-02-27 09:30:46 -05:00
23 changed files with 1453 additions and 40 deletions

View File

@@ -5,10 +5,10 @@ import {BEHAVIOR, ColumnRec} from 'app/client/models/entities/ColumnRec';
import {buildHighlightedCode, cssCodeBlock} from 'app/client/ui/CodeHighlight';
import {GristTooltips} from 'app/client/ui/GristTooltips';
import {cssBlockedCursor, cssLabel, cssRow} from 'app/client/ui/RightPanelStyles';
import {withInfoTooltip} from 'app/client/ui/tooltips';
import { withInfoTooltip } from 'app/client/ui/tooltips';
import {buildFormulaTriggers} from 'app/client/ui/TriggerFormulas';
import {textButton} from 'app/client/ui2018/buttons';
import {testId, theme} from 'app/client/ui2018/cssVars';
import { testId, theme } from 'app/client/ui2018/cssVars';
import {textInput} from 'app/client/ui2018/editableLabel';
import {cssIconButton, icon} from 'app/client/ui2018/icons';
import {IconName} from 'app/client/ui2018/IconList';
@@ -18,6 +18,7 @@ import {sanitizeIdent} from 'app/common/gutil';
import {bundleChanges, Computed, dom, DomContents, DomElementArg, fromKo, MultiHolder,
Observable, styled} from 'grainjs';
import * as ko from 'knockout';
import { textarea } from './inputs';
const t = makeT('FieldConfig');
@@ -88,6 +89,40 @@ export function buildNameConfig(
];
}
export function buildDescriptionConfig(
owner: MultiHolder,
origColumn: ColumnRec,
cursor: ko.Computed<CursorPos>,
) {
// We will listen to cursor position and force a blur event on
// the text input, which will trigger save before the column observable
// will change its value.
// Otherwise, blur will be invoked after column change and save handler will
// update a different column.
let editor: HTMLTextAreaElement | undefined;
owner.autoDispose(
cursor.subscribe(() => {
editor?.blur();
})
);
return [
cssLabel(t("DESCRIPTION")),
cssRow(
editor = cssTextArea(fromKo(origColumn.description),
{ onInput: false },
{ rows: '3' },
dom.on('blur', async (e, elem) => {
await origColumn.description.saveOnly(elem.value);
}),
testId('column-description'),
)
),
];
}
type SaveHandler = (column: ColumnRec, formula: string) => Promise<void>;
type BuildEditor = (
cellElem: Element,
@@ -494,3 +529,22 @@ const cssInput = styled(textInput, `
color: ${theme.inputDisabledFg};
}
`);
const cssTextArea = styled(textarea, `
color: ${theme.inputFg};
background-color: ${theme.mainPanelBg};
border: 1px solid ${theme.inputBorder};
width: 100%;
outline: none;
border-radius: 3px;
padding: 3px 7px;
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
&[readonly] {
background-color: ${theme.inputDisabledBg};
color: ${theme.inputDisabledFg};
}
`);

View File

@@ -43,6 +43,7 @@ import {bundleChanges, Computed, Disposable, dom, domComputed, DomContents,
DomElementArg, DomElementMethod, IDomComponent} from 'grainjs';
import {MultiHolder, Observable, styled, subscribe} from 'grainjs';
import * as ko from 'knockout';
import { buildDescriptionConfig } from './FieldConfig';
const t = makeT('RightPanel');
@@ -235,6 +236,9 @@ export class RightPanel extends Disposable {
cssSection(
dom.create(buildNameConfig, origColumn, cursor, isMultiSelect),
),
cssSection(
dom.create(buildDescriptionConfig, origColumn, cursor),
),
cssSeparator(),
cssSection(
dom.create(buildFormulaConfig,

View File

@@ -242,7 +242,7 @@ export function tooltipCloseButton(ctl: ITooltipControl): HTMLElement {
/**
* Renders an info icon that shows a tooltip with the specified `content` on click.
*/
function infoTooltip(content: DomContents, menuOptions?: IMenuOptions, ...domArgs: DomElementArg[]) {
export function infoTooltip(content: DomContents, menuOptions?: IMenuOptions, ...domArgs: DomElementArg[]) {
return cssInfoTooltipButton('?',
(elem) => {
setPopupToCreateDom(
@@ -314,6 +314,62 @@ export function withInfoTooltip(
);
}
/**
* Renders an column info icon that shows a tooltip with the specified `content` on click.
*/
export function columnInfoTooltip(content: DomContents, menuOptions?: IMenuOptions, ...domArgs: DomElementArg[]) {
return cssColumnInfoTooltipButton(
icon('Info', dom.cls("info_toggle_icon")),
(elem) => {
setPopupToCreateDom(
elem,
(ctl) => {
return cssInfoTooltipPopup(
cssInfoTooltipPopupCloseButton(
icon('CrossSmall'),
dom.on('click', () => ctl.close()),
testId('column-info-tooltip-close'),
),
cssInfoTooltipPopupBody(
content,
{ style: 'white-space: pre-wrap;' },
testId('column-info-tooltip-popup-body'),
),
dom.cls(menuCssClass),
dom.cls(cssMenu.className),
dom.onKeyDown({
Enter: () => ctl.close(),
Escape: () => ctl.close(),
}),
(popup) => { setTimeout(() => popup.focus(), 0); },
testId('column-info-tooltip-popup'),
);
},
{ ...defaultMenuOptions, ...{ placement: 'bottom-end' }, ...menuOptions },
);
},
testId('column-info-tooltip'),
...domArgs,
);
}
const cssColumnInfoTooltipButton = styled('div', `
cursor: pointer;
--icon-color: ${theme.infoButtonFg};
border-radius: 50%;
display: inline-block;
margin-left: 5px;
line-height: 0px;
&:hover {
--icon-color: ${theme.infoButtonHoverFg};
}
&:active {
--icon-color: ${theme.infoButtonActiveFg};
}
`);
const cssTooltip = styled('div', `
position: absolute;
z-index: 5000; /* should be higher than a modal */