(core) Improve highlighting of previewed formula

Summary:
Also improves highlighting of columns when the "Click to insert"
tooltip is shown, and improves highlighting of transforming columns.

Test Plan: Manual.

Reviewers: paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D3962
This commit is contained in:
George Gevoian 2023-07-20 14:18:32 -04:00
parent 5a703a1972
commit beffd02c41
12 changed files with 74 additions and 33 deletions

View File

@ -346,23 +346,23 @@
}
}
/* Column hover effect */
/* Highlight the entire column when the "Click to insert" tooltip is shown. */
.column_name.hover-column > .selection,
.column_name.hover-column.selected > .selection,
.gridview_row .field.hover-column > .selection {
background-color: var(--grist-theme-selection, var(--grist-color-selection));
inset: 0;
position: absolute;
}
.gridview_row .field.hover-column, /* normal field in a row */
.gridview_row .field.hover-column .field_clip,
.column_name.hover-column, /* column name */
.column_name.hover-column.selected, /* selected column name */
.gridview_row .field.frozen.hover-column /* frozen field in a row */ {
/* for frozen fields can't use alpha channel */
background-color: var(--grist-theme-selection-opaque-bg, var(--grist-color-selection-opaque));
color: var(--grist-theme-selection-opaque-fg, unset);
/* Use a darker highlight if the column is being transformed. */
.gridview_row .field.transform_field.hover-column > .selection {
background-color: var(--grist-theme-selection-darkest, rgba(22,179,120,0.35));
inset: 0;
position: absolute;
}
/* For zebra stripes, make the selection little darker */
.record-zebra.record-even .field.hover-column {
background-color: var(--grist-theme-selection-opaque-dark-bg, var(--grist-color-selection-darker-opaque));
color: var(--grist-theme-selection-opaque-fg, unset);
}
/* When column has a hover, remove menu button. */
/* And hide the column menu button. */
.column_name.hover-column .menu_toggle {
visibility: hidden;
}

View File

@ -1139,7 +1139,8 @@ GridView.prototype.buildDom = function() {
},
menu(ctl => this.columnContextMenu(ctl, this.getSelection(), field, filterTriggerCtl)),
testId('column-menu-trigger'),
)
),
dom('div.selection'),
);
}),
this.isPreview ? null : kd.maybe(() => !this.gristDoc.isReadonlyKo(), () => (
@ -1346,7 +1347,7 @@ GridView.prototype.buildDom = function() {
kd.toggleClass('selected', isSelected),
fieldBuilder.buildDomWithCursor(row, isCellActive, isCellSelected),
dom('div.field_selection')
dom('div.selection'),
);
})
)

View File

@ -110,13 +110,20 @@
color: var(--grist-actual-cell-color, unset);
}
.field.selected > .field_selection {
.gridview_row .field.selected > .selection {
background-color: var(--grist-theme-selection, var(--grist-color-selection));
position: absolute;
inset: 0;
pointer-events: none;
}
.field.transform_field > .selection {
background-color: var(--grist-theme-selection-darker, rgba(22,179,120,0.25));
position: absolute;
inset: 0;
pointer-events: none;
}
.field_clip.invalid, .field_clip.field-error-from-style {
background-color: #ffb6c1;
color: black;
@ -126,6 +133,10 @@
background-color: unset;
}
.field.transform_field > .field_clip.invalid + .selection {
background-color: unset;
}
.field_clip.field-error-P {
color: #B0B0B0;
background-color: unset;

View File

@ -1,6 +1,7 @@
import {ColumnRec, DocModel} from 'app/client/models/DocModel';
import {Style} from 'app/client/models/Styles';
import * as modelUtil from 'app/client/models/modelUtil';
import {GristObjCode} from 'app/plugin/GristData';
export interface RuleOwner {
// Field or Section can have a list of conditional styling rules. Each style is a combination of a formula and options
@ -9,6 +10,8 @@ export interface RuleOwner {
tableId: ko.Computed<string>;
// If this field (or column) has a list of conditional styling rules.
hasRules: ko.Computed<boolean>;
// List of rules.
rulesList: ko.Computed<[GristObjCode.List, ...number[]] | null>;
// List of columns that are used as rules for conditional styles.
rulesCols: ko.Computed<ColumnRec[]>;
// List of columns ids that are used as rules for conditional styles.

View File

@ -253,6 +253,7 @@ export function createViewFieldRec(this: ViewFieldRec, docModel: DocModel): void
});
this.tableId = ko.pureComputed(() => this.column().table().tableId());
this.rulesList = ko.pureComputed(() => this._fieldOrColumn().rules());
this.rulesCols = refListRecords(docModel.columns, ko.pureComputed(() => this._fieldOrColumn().rules()));
this.rulesColsIds = ko.pureComputed(() => this.rulesCols().map(c => c.colId()));
this.rulesStyles = modelUtil.fieldWithDefault(

View File

@ -337,6 +337,8 @@ export const theme = {
/* Selection */
selection: new CustomProp('theme-selection', undefined, colors.selection),
selectionDarker: new CustomProp('theme-selection-darker', undefined, 'rgba(22,179,120,0.25)'),
selectionDarkest: new CustomProp('theme-selection-darkest', undefined, 'rgba(22,179,120,0.35)'),
selectionOpaqueFg: new CustomProp('theme-selection-opaque-fg', undefined, 'unset'),
selectionOpaqueBg: new CustomProp('theme-selection-opaque-bg', undefined,
colors.selectionOpaque),

View File

@ -56,6 +56,8 @@ export class FormulaAssistant extends Disposable {
private _waiting = Observable.create(this, false);
/** Is this feature enabled at all */
private _assistantEnabled: Computed<boolean>;
/** Preview column ref */
private _transformColRef: string;
/** Preview column id */
private _transformColId: string;
/** Method to invoke when we are closed, it saves or reverts */
@ -136,14 +138,20 @@ export class FormulaAssistant extends Disposable {
description: 'Formula Editor',
prepare: () => this._preparePreview(),
finalize: () => this._cleanupPreview(),
shouldIncludeInBundle: (a) => {
const tableId = this._options.column.table.peek().tableId.peek();
const allowed = a.length === 1
&& a[0][0] === 'ModifyColumn'
&& a[0][1] === tableId
&& typeof a[0][2] === 'string'
&& [this._transformColId, this._options.column.id.peek()].includes(a[0][2]);
return allowed;
shouldIncludeInBundle: (actions) => {
if (actions.length !== 1) { return false; }
const actionName = actions[0][0];
if (actionName === 'ModifyColumn') {
const tableId = this._options.column.table.peek().tableId.peek();
return actions[0][1] === tableId
&& typeof actions[0][2] === 'string'
&& [this._transformColId, this._options.column.id.peek()].includes(actions[0][2]);
} else if (actionName === 'UpdateRecord') {
return actions[0][1] === '_grist_Tables_column' && actions[0][2] === this._transformColRef;
} else {
return false;
}
}
});
@ -342,14 +350,25 @@ export class FormulaAssistant extends Disposable {
const tableId = this._options.column.table.peek().tableId.peek();
// Add a new column to the table, and set it as the transform column.
const colInfo = await docData.sendAction(['AddColumn', tableId, 'gristHelper_Transform', {
const {colRef, colId} = await docData.sendAction(['AddColumn', tableId, 'gristHelper_Transform', {
type: this._options.column.type.peek(),
label: this._options.column.colId.peek(),
isFormula: true,
formula: this._options.column.formula.peek(),
widgetOptions: JSON.stringify(this._options.field?.widgetOptionsJson()),
}]);
this._options.field?.colRef(colInfo.colRef); // Don't save, it is only in browser.
this._transformColId = colInfo.colId;
this._transformColRef = colRef;
this._transformColId = colId;
const rules = this._options.field?.rulesList();
if (rules) {
await docData.sendAction(['UpdateRecord', '_grist_Tables_column', colRef, {
rules: this._options.field?.rulesList(),
}]);
}
this._options.field?.colRef(colRef); // Don't save, it is only in browser.
// Update the transform column so that it points to the original column.
const transformColumn = this._options.field?.column.peek();

View File

@ -1,10 +1,6 @@
.record-add .field_clip {
background-color: var(--grist-theme-table-add-new-bg, inherit);
}
.transform_field {
color: black;
background-color: #FEFFE8;
}
@media not print {
.formula_field, .formula_field_edit {

View File

@ -132,6 +132,8 @@ export const ThemeColors = t.iface([], {
"card-list-form-border": "string",
"card-list-blocks-border": "string",
"selection": "string",
"selection-darker": "string",
"selection-darkest": "string",
"selection-opaque-fg": "string",
"selection-opaque-bg": "string",
"selection-opaque-dark-bg": "string",

View File

@ -168,6 +168,8 @@ export interface ThemeColors {
/* Selection */
'selection': string;
'selection-darker': string;
'selection-darkest': string;
'selection-opaque-fg': string;
'selection-opaque-bg': string;
'selection-opaque-dark-bg': string;

View File

@ -147,6 +147,8 @@ export const GristDark: ThemeColors = {
/* Selection */
'selection': 'rgba(22,179,120,0.15)',
'selection-darker': 'rgba(22,179,120,0.25)',
'selection-darkest': 'rgba(22,179,120,0.35)',
'selection-opaque-fg': 'white',
'selection-opaque-bg': '#2F4748',
'selection-opaque-dark-bg': '#253E3E',

View File

@ -147,6 +147,8 @@ export const GristLight: ThemeColors = {
/* Selection */
'selection': 'rgba(22,179,120,0.15)',
'selection-darker': 'rgba(22,179,120,0.25)',
'selection-darkest': 'rgba(22,179,120,0.35)',
'selection-opaque-fg': 'black',
'selection-opaque-bg': '#DCF4EB',
'selection-opaque-dark-bg': '#D6EEE5',