gristlabs_grist-core/app/client/widgets/ChoiceEditor.js
George Gevoian 2f900f68f8 (core) Add color options to choice config UI
Summary:
Includes overhauled choice configuration UI for choice and choice list
columns based on the TokenField library. Features include rich copy
and paste support, keyboard shortcuts for token manipulation, and
drag-and-drop support for arrangement.

Configured choice colors are visible throughout the application, such
as in the autocomplete window for both choice and choice list cells, and
in table cells directly.

Choice cells in particular are now styled closer to choice list cells,
and render their contents as colored tokens. Choice cells now also
use the improved autocomplete component that choice lists use, with
some room for future improvement (e.g. allowing new choice items to be
added inline like in choice list's autocomplete).

Also includes a minor fix for choice list cells where right align
was not working.

Test Plan: Browser tests updated.

Reviewers: jarek, dsagal

Reviewed By: jarek, dsagal

Subscribers: jarek

Differential Revision: https://phab.getgrist.com/D2890
2021-07-09 12:07:38 -07:00

70 lines
2.6 KiB
JavaScript

var _ = require('underscore');
var dispose = require('../lib/dispose');
var TextEditor = require('./TextEditor');
const {Autocomplete} = require('app/client/lib/autocomplete');
const {ACIndexImpl, buildHighlightedDom} = require('app/client/lib/ACIndex');
const {ChoiceItem, cssChoiceList, cssItem, cssItemLabel, cssMatchText} = require('app/client/widgets/ChoiceListEditor');
const {cssRefList} = require('app/client/widgets/ReferenceEditor');
const {getFillColor, getTextColor} = require('app/client/widgets/ChoiceTextBox');
const {menuCssClass} = require('app/client/ui2018/menus');
const {testId} = require('app/client/ui2018/cssVars');
const {dom} = require('grainjs');
/**
* ChoiceEditor - TextEditor with a dropdown for possible choices.
*/
function ChoiceEditor(options) {
TextEditor.call(this, options);
this.choices = options.field.widgetOptionsJson.peek().choices || [];
this.choiceOptions = options.field.widgetOptionsJson.peek().choiceOptions || {};
}
dispose.makeDisposable(ChoiceEditor);
_.extend(ChoiceEditor.prototype, TextEditor.prototype);
ChoiceEditor.prototype.getCellValue = function() {
const selectedItem = this.autocomplete && this.autocomplete.getSelectedItem();
return selectedItem ? selectedItem.label : TextEditor.prototype.getCellValue.call(this);
}
ChoiceEditor.prototype.renderACItem = function(item, highlightFunc) {
const options = this.choiceOptions[item.label];
const fillColor = getFillColor(options);
const textColor = getTextColor(options);
return cssItem(
cssItemLabel(
buildHighlightedDom(item.label, highlightFunc, cssMatchText),
dom.style('background-color', fillColor),
dom.style('color', textColor),
testId('choice-editor-item-label')
),
testId('choice-editor-item'),
);
}
ChoiceEditor.prototype.attach = function(cellElem) {
TextEditor.prototype.attach.call(this, cellElem);
// Don't create autocomplete if readonly, or if there are no choices.
if (this.options.readonly || this.choices.length === 0) { return; }
const acItems = this.choices.map(c => new ChoiceItem(c, false));
const acIndex = new ACIndexImpl(acItems);
const acOptions = {
popperOptions: {
placement: 'bottom'
},
menuCssClass: menuCssClass + ' ' + cssRefList.className + ' ' + cssChoiceList.className + ' test-autocomplete',
search: (term) => acIndex.search(term),
renderItem: (item, highlightFunc) => this.renderACItem(item, highlightFunc),
getItemText: (item) => item.label,
onClick: () => this.options.commands.fieldEditSave(),
};
this.autocomplete = Autocomplete.create(this, this.textInput, acOptions);
}
module.exports = ChoiceEditor;