mirror of
https://github.com/google/blockly.git
synced 2026-01-04 23:50:12 +01:00
Our files are up to a decade old, and have churned so much, that the initial author of the file no longer has much meaning. Furthermore, this will encourage developers to post to the developer group, rather than emailing Googlers (usually me) directly.
644 lines
18 KiB
JavaScript
644 lines
18 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2012 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Colour input field.
|
|
*/
|
|
'use strict';
|
|
|
|
/**
|
|
* Colour input field.
|
|
* @class
|
|
*/
|
|
goog.module('Blockly.FieldColour');
|
|
|
|
const Css = goog.require('Blockly.Css');
|
|
const DropDownDiv = goog.require('Blockly.DropDownDiv');
|
|
const Field = goog.require('Blockly.Field');
|
|
const KeyCodes = goog.require('Blockly.utils.KeyCodes');
|
|
const Size = goog.require('Blockly.utils.Size');
|
|
const aria = goog.require('Blockly.utils.aria');
|
|
const browserEvents = goog.require('Blockly.browserEvents');
|
|
const colour = goog.require('Blockly.utils.colour');
|
|
const dom = goog.require('Blockly.utils.dom');
|
|
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
|
const idGenerator = goog.require('Blockly.utils.idGenerator');
|
|
const object = goog.require('Blockly.utils.object');
|
|
/** @suppress {extraRequire} */
|
|
goog.require('Blockly.Events.BlockChange');
|
|
|
|
|
|
/**
|
|
* Class for a colour input field.
|
|
* @param {string=} opt_value The initial value of the field. Should be in
|
|
* '#rrggbb' format. Defaults to the first value in the default colour array.
|
|
* @param {Function=} opt_validator A function that is called to validate
|
|
* changes to the field's value. Takes in a colour string & returns a
|
|
* validated colour string ('#rrggbb' format), or null to abort the
|
|
* change.Blockly.
|
|
* @param {Object=} opt_config A map of options used to configure the field.
|
|
* See the [field creation documentation]{@link
|
|
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/colour}
|
|
* for a list of properties this parameter supports.
|
|
* @extends {Field}
|
|
* @constructor
|
|
* @alias Blockly.FieldColour
|
|
*/
|
|
const FieldColour = function(opt_value, opt_validator, opt_config) {
|
|
FieldColour.superClass_.constructor.call(
|
|
this, opt_value, opt_validator, opt_config);
|
|
|
|
/**
|
|
* The field's colour picker element.
|
|
* @type {?Element}
|
|
* @private
|
|
*/
|
|
this.picker_ = null;
|
|
|
|
/**
|
|
* Index of the currently highlighted element.
|
|
* @type {?number}
|
|
* @private
|
|
*/
|
|
this.highlightedIndex_ = null;
|
|
|
|
/**
|
|
* Mouse click event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onClickWrapper_ = null;
|
|
|
|
/**
|
|
* Mouse move event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onMouseMoveWrapper_ = null;
|
|
|
|
/**
|
|
* Mouse enter event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onMouseEnterWrapper_ = null;
|
|
|
|
/**
|
|
* Mouse leave event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onMouseLeaveWrapper_ = null;
|
|
|
|
/**
|
|
* Key down event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onKeyDownWrapper_ = null;
|
|
};
|
|
object.inherits(FieldColour, Field);
|
|
|
|
/**
|
|
* Construct a FieldColour from a JSON arg object.
|
|
* @param {!Object} options A JSON object with options (colour).
|
|
* @return {!FieldColour} The new field instance.
|
|
* @package
|
|
* @nocollapse
|
|
*/
|
|
FieldColour.fromJson = function(options) {
|
|
// `this` might be a subclass of FieldColour if that class doesn't override
|
|
// the static fromJson method.
|
|
return new this(options['colour'], undefined, options);
|
|
};
|
|
|
|
/**
|
|
* Serializable fields are saved by the XML renderer, non-serializable fields
|
|
* are not. Editable fields should also be serializable.
|
|
* @type {boolean}
|
|
*/
|
|
FieldColour.prototype.SERIALIZABLE = true;
|
|
|
|
/**
|
|
* Mouse cursor style when over the hotspot that initiates the editor.
|
|
*/
|
|
FieldColour.prototype.CURSOR = 'default';
|
|
|
|
/**
|
|
* Used to tell if the field needs to be rendered the next time the block is
|
|
* rendered. Colour fields are statically sized, and only need to be
|
|
* rendered at initialization.
|
|
* @type {boolean}
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.isDirty_ = false;
|
|
|
|
/**
|
|
* Array of colours used by this field. If null, use the global list.
|
|
* @type {Array<string>}
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.colours_ = null;
|
|
|
|
/**
|
|
* Array of colour tooltips used by this field. If null, use the global list.
|
|
* @type {Array<string>}
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.titles_ = null;
|
|
|
|
/**
|
|
* Number of colour columns used by this field. If 0, use the global setting.
|
|
* By default use the global constants for columns.
|
|
* @type {number}
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.columns_ = 0;
|
|
|
|
/**
|
|
* Configure the field based on the given map of options.
|
|
* @param {!Object} config A map of options to configure the field based on.
|
|
* @protected
|
|
* @override
|
|
*/
|
|
FieldColour.prototype.configure_ = function(config) {
|
|
FieldColour.superClass_.configure_.call(this, config);
|
|
if (config['colourOptions']) {
|
|
this.colours_ = config['colourOptions'];
|
|
this.titles_ = config['colourTitles'];
|
|
}
|
|
if (config['columns']) {
|
|
this.columns_ = config['columns'];
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Create the block UI for this colour field.
|
|
* @package
|
|
*/
|
|
FieldColour.prototype.initView = function() {
|
|
this.size_ = new Size(
|
|
this.getConstants().FIELD_COLOUR_DEFAULT_WIDTH,
|
|
this.getConstants().FIELD_COLOUR_DEFAULT_HEIGHT);
|
|
if (!this.getConstants().FIELD_COLOUR_FULL_BLOCK) {
|
|
this.createBorderRect_();
|
|
this.borderRect_.style['fillOpacity'] = '1';
|
|
} else {
|
|
this.clickTarget_ = this.sourceBlock_.getSvgRoot();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
FieldColour.prototype.applyColour = function() {
|
|
if (!this.getConstants().FIELD_COLOUR_FULL_BLOCK) {
|
|
if (this.borderRect_) {
|
|
this.borderRect_.style.fill = /** @type {string} */ (this.getValue());
|
|
}
|
|
} else {
|
|
this.sourceBlock_.pathObject.svgPath.setAttribute('fill', this.getValue());
|
|
this.sourceBlock_.pathObject.svgPath.setAttribute('stroke', '#fff');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Ensure that the input value is a valid colour.
|
|
* @param {*=} opt_newValue The input value.
|
|
* @return {?string} A valid colour, or null if invalid.
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.doClassValidation_ = function(opt_newValue) {
|
|
if (typeof opt_newValue !== 'string') {
|
|
return null;
|
|
}
|
|
return colour.parse(opt_newValue);
|
|
};
|
|
|
|
/**
|
|
* Update the value of this colour field, and update the displayed colour.
|
|
* @param {*} newValue The value to be saved. The default validator guarantees
|
|
* that this is a colour in '#rrggbb' format.
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.doValueUpdate_ = function(newValue) {
|
|
this.value_ = newValue;
|
|
if (this.borderRect_) {
|
|
this.borderRect_.style.fill = /** @type {string} */ (newValue);
|
|
} else if (this.sourceBlock_ && this.sourceBlock_.rendered) {
|
|
this.sourceBlock_.pathObject.svgPath.setAttribute('fill', newValue);
|
|
this.sourceBlock_.pathObject.svgPath.setAttribute('stroke', '#fff');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get the text for this field. Used when the block is collapsed.
|
|
* @return {string} Text representing the value of this field.
|
|
*/
|
|
FieldColour.prototype.getText = function() {
|
|
let colour = /** @type {string} */ (this.value_);
|
|
// Try to use #rgb format if possible, rather than #rrggbb.
|
|
if (/^#(.)\1(.)\2(.)\3$/.test(colour)) {
|
|
colour = '#' + colour[1] + colour[3] + colour[5];
|
|
}
|
|
return colour;
|
|
};
|
|
|
|
/**
|
|
* An array of colour strings for the palette.
|
|
* Copied from goog.ui.ColorPicker.SIMPLE_GRID_COLORS
|
|
* All colour pickers use this unless overridden with setColours.
|
|
* @type {!Array<string>}
|
|
*/
|
|
FieldColour.COLOURS = [
|
|
// grays
|
|
'#ffffff', '#cccccc', '#c0c0c0', '#999999', '#666666', '#333333', '#000000',
|
|
// reds
|
|
'#ffcccc', '#ff6666', '#ff0000', '#cc0000', '#990000', '#660000', '#330000',
|
|
// oranges
|
|
'#ffcc99', '#ff9966', '#ff9900', '#ff6600', '#cc6600', '#993300', '#663300',
|
|
// yellows
|
|
'#ffff99', '#ffff66', '#ffcc66', '#ffcc33', '#cc9933', '#996633', '#663333',
|
|
// olives
|
|
'#ffffcc', '#ffff33', '#ffff00', '#ffcc00', '#999900', '#666600', '#333300',
|
|
// greens
|
|
'#99ff99', '#66ff99', '#33ff33', '#33cc00', '#009900', '#006600', '#003300',
|
|
// turquoises
|
|
'#99ffff', '#33ffff', '#66cccc', '#00cccc', '#339999', '#336666', '#003333',
|
|
// blues
|
|
'#ccffff', '#66ffff', '#33ccff', '#3366ff', '#3333ff', '#000099', '#000066',
|
|
// purples
|
|
'#ccccff', '#9999ff', '#6666cc', '#6633ff', '#6600cc', '#333399', '#330099',
|
|
// violets
|
|
'#ffccff', '#ff99ff', '#cc66cc', '#cc33cc', '#993399', '#663366', '#330033'
|
|
];
|
|
|
|
/**
|
|
* The default value for this field.
|
|
* @type {*}
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.DEFAULT_VALUE = FieldColour.COLOURS[0];
|
|
|
|
/**
|
|
* An array of tooltip strings for the palette. If not the same length as
|
|
* COLOURS, the colour's hex code will be used for any missing titles.
|
|
* All colour pickers use this unless overridden with setColours.
|
|
* @type {!Array<string>}
|
|
*/
|
|
FieldColour.TITLES = [];
|
|
|
|
/**
|
|
* Number of columns in the palette.
|
|
* All colour pickers use this unless overridden with setColumns.
|
|
*/
|
|
FieldColour.COLUMNS = 7;
|
|
|
|
/**
|
|
* Set a custom colour grid for this field.
|
|
* @param {Array<string>} colours Array of colours for this block,
|
|
* or null to use default (FieldColour.COLOURS).
|
|
* @param {Array<string>=} opt_titles Optional array of colour tooltips,
|
|
* or null to use default (FieldColour.TITLES).
|
|
* @return {!FieldColour} Returns itself (for method chaining).
|
|
*/
|
|
FieldColour.prototype.setColours = function(colours, opt_titles) {
|
|
this.colours_ = colours;
|
|
if (opt_titles) {
|
|
this.titles_ = opt_titles;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Set a custom grid size for this field.
|
|
* @param {number} columns Number of columns for this block,
|
|
* or 0 to use default (FieldColour.COLUMNS).
|
|
* @return {!FieldColour} Returns itself (for method chaining).
|
|
*/
|
|
FieldColour.prototype.setColumns = function(columns) {
|
|
this.columns_ = columns;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Create and show the colour field's editor.
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.showEditor_ = function() {
|
|
this.dropdownCreate_();
|
|
DropDownDiv.getContentDiv().appendChild(this.picker_);
|
|
|
|
DropDownDiv.showPositionedByField(this, this.dropdownDispose_.bind(this));
|
|
|
|
// Focus so we can start receiving keyboard events.
|
|
this.picker_.focus({preventScroll: true});
|
|
};
|
|
|
|
/**
|
|
* Handle a click on a colour cell.
|
|
* @param {!MouseEvent} e Mouse event.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onClick_ = function(e) {
|
|
const cell = /** @type {!Element} */ (e.target);
|
|
const colour = cell && cell.label;
|
|
if (colour !== null) {
|
|
this.setValue(colour);
|
|
DropDownDiv.hideIfOwner(this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle a key down event. Navigate around the grid with the
|
|
* arrow keys. Enter selects the highlighted colour.
|
|
* @param {!KeyboardEvent} e Keyboard event.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onKeyDown_ = function(e) {
|
|
let handled = false;
|
|
if (e.keyCode === KeyCodes.UP) {
|
|
this.moveHighlightBy_(0, -1);
|
|
handled = true;
|
|
} else if (e.keyCode === KeyCodes.DOWN) {
|
|
this.moveHighlightBy_(0, 1);
|
|
handled = true;
|
|
} else if (e.keyCode === KeyCodes.LEFT) {
|
|
this.moveHighlightBy_(-1, 0);
|
|
handled = true;
|
|
} else if (e.keyCode === KeyCodes.RIGHT) {
|
|
this.moveHighlightBy_(1, 0);
|
|
handled = true;
|
|
} else if (e.keyCode === KeyCodes.ENTER) {
|
|
// Select the highlighted colour.
|
|
const highlighted = this.getHighlighted_();
|
|
if (highlighted) {
|
|
const colour = highlighted && highlighted.label;
|
|
if (colour !== null) {
|
|
this.setValue(colour);
|
|
}
|
|
}
|
|
DropDownDiv.hideWithoutAnimation();
|
|
handled = true;
|
|
}
|
|
if (handled) {
|
|
e.stopPropagation();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Move the currently highlighted position by dx and dy.
|
|
* @param {number} dx Change of x
|
|
* @param {number} dy Change of y
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.moveHighlightBy_ = function(dx, dy) {
|
|
const colours = this.colours_ || FieldColour.COLOURS;
|
|
const columns = this.columns_ || FieldColour.COLUMNS;
|
|
|
|
// Get the current x and y coordinates
|
|
let x = this.highlightedIndex_ % columns;
|
|
let y = Math.floor(this.highlightedIndex_ / columns);
|
|
|
|
// Add the offset
|
|
x += dx;
|
|
y += dy;
|
|
|
|
if (dx < 0) {
|
|
// Move left one grid cell, even in RTL.
|
|
// Loop back to the end of the previous row if we have room.
|
|
if (x < 0 && y > 0) {
|
|
x = columns - 1;
|
|
y--;
|
|
} else if (x < 0) {
|
|
x = 0;
|
|
}
|
|
} else if (dx > 0) {
|
|
// Move right one grid cell, even in RTL.
|
|
// Loop to the start of the next row, if there's room.
|
|
if (x > columns - 1 && y < Math.floor(colours.length / columns) - 1) {
|
|
x = 0;
|
|
y++;
|
|
} else if (x > columns - 1) {
|
|
x--;
|
|
}
|
|
} else if (dy < 0) {
|
|
// Move up one grid cell, stop at the top.
|
|
if (y < 0) {
|
|
y = 0;
|
|
}
|
|
} else if (dy > 0) {
|
|
// Move down one grid cell, stop at the bottom.
|
|
if (y > Math.floor(colours.length / columns) - 1) {
|
|
y = Math.floor(colours.length / columns) - 1;
|
|
}
|
|
}
|
|
|
|
// Move the highlight to the new coordinates.
|
|
const cell =
|
|
/** @type {!Element} */ (this.picker_.childNodes[y].childNodes[x]);
|
|
const index = (y * columns) + x;
|
|
this.setHighlightedCell_(cell, index);
|
|
};
|
|
|
|
/**
|
|
* Handle a mouse move event. Highlight the hovered colour.
|
|
* @param {!MouseEvent} e Mouse event.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onMouseMove_ = function(e) {
|
|
const cell = /** @type {!Element} */ (e.target);
|
|
const index = cell && Number(cell.getAttribute('data-index'));
|
|
if (index !== null && index !== this.highlightedIndex_) {
|
|
this.setHighlightedCell_(cell, index);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle a mouse enter event. Focus the picker.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onMouseEnter_ = function() {
|
|
this.picker_.focus({preventScroll: true});
|
|
};
|
|
|
|
/**
|
|
* Handle a mouse leave event. Blur the picker and unhighlight
|
|
* the currently highlighted colour.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onMouseLeave_ = function() {
|
|
this.picker_.blur();
|
|
const highlighted = this.getHighlighted_();
|
|
if (highlighted) {
|
|
dom.removeClass(highlighted, 'blocklyColourHighlighted');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Returns the currently highlighted item (if any).
|
|
* @return {?HTMLElement} Highlighted item (null if none).
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.getHighlighted_ = function() {
|
|
const columns = this.columns_ || FieldColour.COLUMNS;
|
|
const x = this.highlightedIndex_ % columns;
|
|
const y = Math.floor(this.highlightedIndex_ / columns);
|
|
const row = this.picker_.childNodes[y];
|
|
if (!row) {
|
|
return null;
|
|
}
|
|
const col = /** @type {HTMLElement} */ (row.childNodes[x]);
|
|
return col;
|
|
};
|
|
|
|
/**
|
|
* Update the currently highlighted cell.
|
|
* @param {!Element} cell the new cell to highlight
|
|
* @param {number} index the index of the new cell
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.setHighlightedCell_ = function(cell, index) {
|
|
// Unhighlight the current item.
|
|
const highlighted = this.getHighlighted_();
|
|
if (highlighted) {
|
|
dom.removeClass(highlighted, 'blocklyColourHighlighted');
|
|
}
|
|
// Highlight new item.
|
|
dom.addClass(cell, 'blocklyColourHighlighted');
|
|
// Set new highlighted index.
|
|
this.highlightedIndex_ = index;
|
|
|
|
// Update accessibility roles.
|
|
aria.setState(
|
|
/** @type {!Element} */ (this.picker_), aria.State.ACTIVEDESCENDANT,
|
|
cell.getAttribute('id'));
|
|
};
|
|
|
|
/**
|
|
* Create a colour picker dropdown editor.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.dropdownCreate_ = function() {
|
|
const columns = this.columns_ || FieldColour.COLUMNS;
|
|
const colours = this.colours_ || FieldColour.COLOURS;
|
|
const titles = this.titles_ || FieldColour.TITLES;
|
|
const selectedColour = this.getValue();
|
|
// Create the palette.
|
|
const table = document.createElement('table');
|
|
table.className = 'blocklyColourTable';
|
|
table.tabIndex = 0;
|
|
table.dir = 'ltr';
|
|
aria.setRole(table, aria.Role.GRID);
|
|
aria.setState(table, aria.State.EXPANDED, true);
|
|
aria.setState(
|
|
table, aria.State.ROWCOUNT, Math.floor(colours.length / columns));
|
|
aria.setState(table, aria.State.COLCOUNT, columns);
|
|
let row;
|
|
for (let i = 0; i < colours.length; i++) {
|
|
if (i % columns === 0) {
|
|
row = document.createElement('tr');
|
|
aria.setRole(row, aria.Role.ROW);
|
|
table.appendChild(row);
|
|
}
|
|
const cell = document.createElement('td');
|
|
row.appendChild(cell);
|
|
cell.label = colours[i]; // This becomes the value, if clicked.
|
|
cell.title = titles[i] || colours[i];
|
|
cell.id = idGenerator.getNextUniqueId();
|
|
cell.setAttribute('data-index', i);
|
|
aria.setRole(cell, aria.Role.GRIDCELL);
|
|
aria.setState(cell, aria.State.LABEL, colours[i]);
|
|
aria.setState(cell, aria.State.SELECTED, colours[i] === selectedColour);
|
|
cell.style.backgroundColor = colours[i];
|
|
if (colours[i] === selectedColour) {
|
|
cell.className = 'blocklyColourSelected';
|
|
this.highlightedIndex_ = i;
|
|
}
|
|
}
|
|
|
|
// Configure event handler on the table to listen for any event in a cell.
|
|
this.onClickWrapper_ =
|
|
browserEvents.conditionalBind(table, 'click', this, this.onClick_, true);
|
|
this.onMouseMoveWrapper_ = browserEvents.conditionalBind(
|
|
table, 'mousemove', this, this.onMouseMove_, true);
|
|
this.onMouseEnterWrapper_ = browserEvents.conditionalBind(
|
|
table, 'mouseenter', this, this.onMouseEnter_, true);
|
|
this.onMouseLeaveWrapper_ = browserEvents.conditionalBind(
|
|
table, 'mouseleave', this, this.onMouseLeave_, true);
|
|
this.onKeyDownWrapper_ =
|
|
browserEvents.conditionalBind(table, 'keydown', this, this.onKeyDown_);
|
|
|
|
this.picker_ = table;
|
|
};
|
|
|
|
/**
|
|
* Disposes of events and DOM-references belonging to the colour editor.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.dropdownDispose_ = function() {
|
|
if (this.onClickWrapper_) {
|
|
browserEvents.unbind(this.onClickWrapper_);
|
|
this.onClickWrapper_ = null;
|
|
}
|
|
if (this.onMouseMoveWrapper_) {
|
|
browserEvents.unbind(this.onMouseMoveWrapper_);
|
|
this.onMouseMoveWrapper_ = null;
|
|
}
|
|
if (this.onMouseEnterWrapper_) {
|
|
browserEvents.unbind(this.onMouseEnterWrapper_);
|
|
this.onMouseEnterWrapper_ = null;
|
|
}
|
|
if (this.onMouseLeaveWrapper_) {
|
|
browserEvents.unbind(this.onMouseLeaveWrapper_);
|
|
this.onMouseLeaveWrapper_ = null;
|
|
}
|
|
if (this.onKeyDownWrapper_) {
|
|
browserEvents.unbind(this.onKeyDownWrapper_);
|
|
this.onKeyDownWrapper_ = null;
|
|
}
|
|
this.picker_ = null;
|
|
this.highlightedIndex_ = null;
|
|
};
|
|
|
|
/**
|
|
* CSS for colour picker. See css.js for use.
|
|
*/
|
|
Css.register(`
|
|
.blocklyColourTable {
|
|
border-collapse: collapse;
|
|
display: block;
|
|
outline: none;
|
|
padding: 1px;
|
|
}
|
|
|
|
.blocklyColourTable>tr>td {
|
|
border: .5px solid #888;
|
|
box-sizing: border-box;
|
|
cursor: pointer;
|
|
display: inline-block;
|
|
height: 20px;
|
|
padding: 0;
|
|
width: 20px;
|
|
}
|
|
|
|
.blocklyColourTable>tr>td.blocklyColourHighlighted {
|
|
border-color: #eee;
|
|
box-shadow: 2px 2px 7px 2px rgba(0,0,0,.3);
|
|
position: relative;
|
|
}
|
|
|
|
.blocklyColourSelected, .blocklyColourSelected:hover {
|
|
border-color: #eee !important;
|
|
outline: 1px solid #333;
|
|
position: relative;
|
|
}
|
|
`);
|
|
|
|
fieldRegistry.register('field_colour', FieldColour);
|
|
|
|
exports = FieldColour;
|