mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(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:
		
							parent
							
								
									5a703a1972
								
							
						
					
					
						commit
						beffd02c41
					
				@ -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 */
 | 
					/* Use a darker highlight if the column is being transformed. */
 | 
				
			||||||
.gridview_row .field.hover-column .field_clip,
 | 
					.gridview_row .field.transform_field.hover-column > .selection {
 | 
				
			||||||
.column_name.hover-column, /* column name */
 | 
					  background-color: var(--grist-theme-selection-darkest, rgba(22,179,120,0.35));
 | 
				
			||||||
.column_name.hover-column.selected, /* selected column name */
 | 
					  inset: 0;
 | 
				
			||||||
.gridview_row .field.frozen.hover-column /* frozen field in a row */ {
 | 
					  position: absolute;
 | 
				
			||||||
  /* 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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/* For zebra stripes, make the selection little darker */
 | 
					
 | 
				
			||||||
.record-zebra.record-even .field.hover-column {
 | 
					/* And hide the column menu button. */
 | 
				
			||||||
  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. */
 | 
					 | 
				
			||||||
.column_name.hover-column .menu_toggle {
 | 
					.column_name.hover-column .menu_toggle {
 | 
				
			||||||
  visibility: hidden;
 | 
					  visibility: hidden;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1139,7 +1139,8 @@ GridView.prototype.buildDom = function() {
 | 
				
			|||||||
                  },
 | 
					                  },
 | 
				
			||||||
                  menu(ctl => this.columnContextMenu(ctl, this.getSelection(), field, filterTriggerCtl)),
 | 
					                  menu(ctl => this.columnContextMenu(ctl, this.getSelection(), field, filterTriggerCtl)),
 | 
				
			||||||
                  testId('column-menu-trigger'),
 | 
					                  testId('column-menu-trigger'),
 | 
				
			||||||
                )
 | 
					                ),
 | 
				
			||||||
 | 
					                dom('div.selection'),
 | 
				
			||||||
              );
 | 
					              );
 | 
				
			||||||
            }),
 | 
					            }),
 | 
				
			||||||
            this.isPreview ? null : kd.maybe(() => !this.gristDoc.isReadonlyKo(), () => (
 | 
					            this.isPreview ? null : kd.maybe(() => !this.gristDoc.isReadonlyKo(), () => (
 | 
				
			||||||
@ -1346,7 +1347,7 @@ GridView.prototype.buildDom = function() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            kd.toggleClass('selected', isSelected),
 | 
					            kd.toggleClass('selected', isSelected),
 | 
				
			||||||
            fieldBuilder.buildDomWithCursor(row, isCellActive, isCellSelected),
 | 
					            fieldBuilder.buildDomWithCursor(row, isCellActive, isCellSelected),
 | 
				
			||||||
            dom('div.field_selection')
 | 
					            dom('div.selection'),
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
				
			|||||||
@ -110,13 +110,20 @@
 | 
				
			|||||||
  color: var(--grist-actual-cell-color, unset);
 | 
					  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));
 | 
					  background-color: var(--grist-theme-selection, var(--grist-color-selection));
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  inset: 0;
 | 
					  inset: 0;
 | 
				
			||||||
  pointer-events: none;
 | 
					  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 {
 | 
					.field_clip.invalid, .field_clip.field-error-from-style {
 | 
				
			||||||
  background-color: #ffb6c1;
 | 
					  background-color: #ffb6c1;
 | 
				
			||||||
  color: black;
 | 
					  color: black;
 | 
				
			||||||
@ -126,6 +133,10 @@
 | 
				
			|||||||
  background-color: unset;
 | 
					  background-color: unset;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.field.transform_field > .field_clip.invalid + .selection {
 | 
				
			||||||
 | 
					  background-color: unset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.field_clip.field-error-P {
 | 
					.field_clip.field-error-P {
 | 
				
			||||||
  color: #B0B0B0;
 | 
					  color: #B0B0B0;
 | 
				
			||||||
  background-color: unset;
 | 
					  background-color: unset;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
import {ColumnRec, DocModel} from 'app/client/models/DocModel';
 | 
					import {ColumnRec, DocModel} from 'app/client/models/DocModel';
 | 
				
			||||||
import {Style} from 'app/client/models/Styles';
 | 
					import {Style} from 'app/client/models/Styles';
 | 
				
			||||||
import * as modelUtil from 'app/client/models/modelUtil';
 | 
					import * as modelUtil from 'app/client/models/modelUtil';
 | 
				
			||||||
 | 
					import {GristObjCode} from 'app/plugin/GristData';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface RuleOwner {
 | 
					export interface RuleOwner {
 | 
				
			||||||
  // Field or Section can have a list of conditional styling rules. Each style is a combination of a formula and options
 | 
					  // 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>;
 | 
					  tableId: ko.Computed<string>;
 | 
				
			||||||
  // If this field (or column) has a list of conditional styling rules.
 | 
					  // If this field (or column) has a list of conditional styling rules.
 | 
				
			||||||
  hasRules: ko.Computed<boolean>;
 | 
					  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.
 | 
					  // List of columns that are used as rules for conditional styles.
 | 
				
			||||||
  rulesCols: ko.Computed<ColumnRec[]>;
 | 
					  rulesCols: ko.Computed<ColumnRec[]>;
 | 
				
			||||||
  // List of columns ids that are used as rules for conditional styles.
 | 
					  // List of columns ids that are used as rules for conditional styles.
 | 
				
			||||||
 | 
				
			|||||||
@ -253,6 +253,7 @@ export function createViewFieldRec(this: ViewFieldRec, docModel: DocModel): void
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this.tableId = ko.pureComputed(() => this.column().table().tableId());
 | 
					  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.rulesCols = refListRecords(docModel.columns, ko.pureComputed(() => this._fieldOrColumn().rules()));
 | 
				
			||||||
  this.rulesColsIds = ko.pureComputed(() => this.rulesCols().map(c => c.colId()));
 | 
					  this.rulesColsIds = ko.pureComputed(() => this.rulesCols().map(c => c.colId()));
 | 
				
			||||||
  this.rulesStyles = modelUtil.fieldWithDefault(
 | 
					  this.rulesStyles = modelUtil.fieldWithDefault(
 | 
				
			||||||
 | 
				
			|||||||
@ -337,6 +337,8 @@ export const theme = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Selection */
 | 
					  /* Selection */
 | 
				
			||||||
  selection: new CustomProp('theme-selection', undefined, colors.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'),
 | 
					  selectionOpaqueFg: new CustomProp('theme-selection-opaque-fg', undefined, 'unset'),
 | 
				
			||||||
  selectionOpaqueBg: new CustomProp('theme-selection-opaque-bg', undefined,
 | 
					  selectionOpaqueBg: new CustomProp('theme-selection-opaque-bg', undefined,
 | 
				
			||||||
    colors.selectionOpaque),
 | 
					    colors.selectionOpaque),
 | 
				
			||||||
 | 
				
			|||||||
@ -56,6 +56,8 @@ export class FormulaAssistant extends Disposable {
 | 
				
			|||||||
  private _waiting = Observable.create(this, false);
 | 
					  private _waiting = Observable.create(this, false);
 | 
				
			||||||
  /** Is this feature enabled at all */
 | 
					  /** Is this feature enabled at all */
 | 
				
			||||||
  private _assistantEnabled: Computed<boolean>;
 | 
					  private _assistantEnabled: Computed<boolean>;
 | 
				
			||||||
 | 
					  /** Preview column ref */
 | 
				
			||||||
 | 
					  private _transformColRef: string;
 | 
				
			||||||
  /** Preview column id */
 | 
					  /** Preview column id */
 | 
				
			||||||
  private _transformColId: string;
 | 
					  private _transformColId: string;
 | 
				
			||||||
  /** Method to invoke when we are closed, it saves or reverts */
 | 
					  /** Method to invoke when we are closed, it saves or reverts */
 | 
				
			||||||
@ -136,14 +138,20 @@ export class FormulaAssistant extends Disposable {
 | 
				
			|||||||
      description: 'Formula Editor',
 | 
					      description: 'Formula Editor',
 | 
				
			||||||
      prepare: () => this._preparePreview(),
 | 
					      prepare: () => this._preparePreview(),
 | 
				
			||||||
      finalize: () => this._cleanupPreview(),
 | 
					      finalize: () => this._cleanupPreview(),
 | 
				
			||||||
      shouldIncludeInBundle: (a) => {
 | 
					      shouldIncludeInBundle: (actions) => {
 | 
				
			||||||
        const tableId = this._options.column.table.peek().tableId.peek();
 | 
					        if (actions.length !== 1) { return false; }
 | 
				
			||||||
        const allowed = a.length === 1
 | 
					
 | 
				
			||||||
          && a[0][0] === 'ModifyColumn'
 | 
					        const actionName = actions[0][0];
 | 
				
			||||||
          && a[0][1] === tableId
 | 
					        if (actionName === 'ModifyColumn') {
 | 
				
			||||||
          && typeof a[0][2] === 'string'
 | 
					          const tableId = this._options.column.table.peek().tableId.peek();
 | 
				
			||||||
          && [this._transformColId, this._options.column.id.peek()].includes(a[0][2]);
 | 
					          return actions[0][1] === tableId
 | 
				
			||||||
        return allowed;
 | 
					            && 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();
 | 
					    const tableId = this._options.column.table.peek().tableId.peek();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Add a new column to the table, and set it as the transform column.
 | 
					    // 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(),
 | 
					      type: this._options.column.type.peek(),
 | 
				
			||||||
      label: this._options.column.colId.peek(),
 | 
					      label: this._options.column.colId.peek(),
 | 
				
			||||||
      isFormula: true,
 | 
					      isFormula: true,
 | 
				
			||||||
      formula: this._options.column.formula.peek(),
 | 
					      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.
 | 
					    // Update the transform column so that it points to the original column.
 | 
				
			||||||
    const transformColumn = this._options.field?.column.peek();
 | 
					    const transformColumn = this._options.field?.column.peek();
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,6 @@
 | 
				
			|||||||
.record-add .field_clip {
 | 
					.record-add .field_clip {
 | 
				
			||||||
  background-color: var(--grist-theme-table-add-new-bg, inherit);
 | 
					  background-color: var(--grist-theme-table-add-new-bg, inherit);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.transform_field {
 | 
					 | 
				
			||||||
  color: black;
 | 
					 | 
				
			||||||
  background-color: #FEFFE8;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media not print {
 | 
					@media not print {
 | 
				
			||||||
  .formula_field, .formula_field_edit {
 | 
					  .formula_field, .formula_field_edit {
 | 
				
			||||||
 | 
				
			|||||||
@ -132,6 +132,8 @@ export const ThemeColors = t.iface([], {
 | 
				
			|||||||
  "card-list-form-border": "string",
 | 
					  "card-list-form-border": "string",
 | 
				
			||||||
  "card-list-blocks-border": "string",
 | 
					  "card-list-blocks-border": "string",
 | 
				
			||||||
  "selection": "string",
 | 
					  "selection": "string",
 | 
				
			||||||
 | 
					  "selection-darker": "string",
 | 
				
			||||||
 | 
					  "selection-darkest": "string",
 | 
				
			||||||
  "selection-opaque-fg": "string",
 | 
					  "selection-opaque-fg": "string",
 | 
				
			||||||
  "selection-opaque-bg": "string",
 | 
					  "selection-opaque-bg": "string",
 | 
				
			||||||
  "selection-opaque-dark-bg": "string",
 | 
					  "selection-opaque-dark-bg": "string",
 | 
				
			||||||
 | 
				
			|||||||
@ -168,6 +168,8 @@ export interface ThemeColors {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Selection */
 | 
					  /* Selection */
 | 
				
			||||||
  'selection': string;
 | 
					  'selection': string;
 | 
				
			||||||
 | 
					  'selection-darker': string;
 | 
				
			||||||
 | 
					  'selection-darkest': string;
 | 
				
			||||||
  'selection-opaque-fg': string;
 | 
					  'selection-opaque-fg': string;
 | 
				
			||||||
  'selection-opaque-bg': string;
 | 
					  'selection-opaque-bg': string;
 | 
				
			||||||
  'selection-opaque-dark-bg': string;
 | 
					  'selection-opaque-dark-bg': string;
 | 
				
			||||||
 | 
				
			|||||||
@ -147,6 +147,8 @@ export const GristDark: ThemeColors = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Selection */
 | 
					  /* Selection */
 | 
				
			||||||
  'selection': 'rgba(22,179,120,0.15)',
 | 
					  '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-fg': 'white',
 | 
				
			||||||
  'selection-opaque-bg': '#2F4748',
 | 
					  'selection-opaque-bg': '#2F4748',
 | 
				
			||||||
  'selection-opaque-dark-bg': '#253E3E',
 | 
					  'selection-opaque-dark-bg': '#253E3E',
 | 
				
			||||||
 | 
				
			|||||||
@ -147,6 +147,8 @@ export const GristLight: ThemeColors = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Selection */
 | 
					  /* Selection */
 | 
				
			||||||
  'selection': 'rgba(22,179,120,0.15)',
 | 
					  '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-fg': 'black',
 | 
				
			||||||
  'selection-opaque-bg': '#DCF4EB',
 | 
					  'selection-opaque-bg': '#DCF4EB',
 | 
				
			||||||
  'selection-opaque-dark-bg': '#D6EEE5',
 | 
					  'selection-opaque-dark-bg': '#D6EEE5',
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user