UNPKG

plotboilerplate

Version:

A simple javascript plotting boilerplate for 2d stuff.

327 lines 16.7 kB
"use strict"; /** * A simple class for rendering color gradient dropdowns. * * As native dropdown do not support custom stylings in the way we need, we will implement * our own dropdown class. * * @author Ikaros Kappler * @date 2025-08-19 * @version 1.0.0 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ColorGradientSelector = void 0; var NoReact = require("noreact"); var Color_1 = require("../../datastructures/Color"); var ColorGradient_1 = require("../../datastructures/ColorGradient"); var ColorGradientSelector = /** @class */ (function () { /** * The constructor: creates a new color gradient picker in the given container. * If no container or ID is given then a new unbound `container` will be created (DIV). * * Pass a container ID or nothing – in the latter case the constructor will create * a new DIV element. * * @param {string?} containerID - (optional) If you want to use an existing container (should be a DIV). */ function ColorGradientSelector(options) { var _this = this; this.isDropdownOpen = false; this.css_buttonWidth = "100px"; this.css_buttonHeight = "1.8em"; this.css_buttonFontSize = "0.725em"; this.css_buttonFontSize_larger = "1.0em"; this.colorGradients = []; // TODO: this does not really need to be a pair, does it? this.colorGradientOptionRefs = []; this.selectedGradientIndex = -1; this.installedChangeListeners = []; /** * Adds custom styles (global STYLE tag). * * @private */ this.__createCustomStylesElement = function () { // Thanks to Ana Tudor // https://css-tricks.com/multi-thumb-sliders-particular-two-thumb-case/ return (NoReact.createElement("style", null, "\n\n #".concat(_this.elementID, " button {\n border: 0px solid lightgray;\n padding: 0.25em;\n /* background-color: rgba(255,255,255,0.9); */\n }\n\n #").concat(_this.elementID, " .positioning-container button {\n border-radius: 0;\n }\n\n #").concat(_this.elementID, " .main-button:hover {\n background-color: rgba(216,216,216,0.9);\n }\n\n #").concat(_this.elementID, " .option-gradient-button:hover, #").concat(_this.elementID, " .option-delete-button:hover {\n background-color: rgba(216,216,216,0.9);\n }\n\n\n "))); }; options = options || {}; if (options.containerID) { var cont = document.getElementById(options.containerID); if (!cont) { throw "Cannot create ColorGradientPicker. Component ID does not exist."; } this.container = cont; } else { this.container = document.createElement("div"); } this.isMobileMode = Boolean(options.isMobileMode); if (this.isMobileMode) { this.css_buttonWidth = "200px"; this.css_buttonHeight = "2.5em"; this.css_buttonFontSize = "1.25em"; this.css_buttonFontSize_larger = "1.45em"; } this.baseID = Math.floor(Math.random() * 65535); this.elementID = "color-gradient-selector-".concat(this.baseID); this.colorGradients = typeof options.initialGradients === "undefined" ? ColorGradientSelector.DEFAULT_COLOR_GRADIENTS : options.initialGradients; this.selectedGradientIndex = typeof options.selectedGradientIndex === "undefined" ? 0 : options.selectedGradientIndex; document.head.appendChild(this.__createCustomStylesElement()); this.container.append(this._render()); } // END constructor // TODO: implement this? ColorGradientSelector.prototype.setGradients = function (gradients, selectedIndex) { var _this = this; // First empty the container this.__removeAllChildNodes(this.positioningContainerRef.current); this.colorGradients = []; this.colorGradientOptionRefs = []; this.selectedGradientIndex = selectedIndex; // Re-render button array gradients.map(function (grad) { _this.addGradient(grad); }); }; ColorGradientSelector.prototype.addGradient = function (gradient) { // Render a new button var index = this.colorGradients.length; var refMainContainer = NoReact.useRef(); var refActionButton = NoReact.useRef(); var refDeleteButton = NoReact.useRef(); this.__renderOptionButton(gradient, index, refMainContainer, refActionButton, refDeleteButton); this.colorGradients.push(gradient); this.colorGradientOptionRefs.push({ mainButton: refActionButton, deleteButton: refDeleteButton }); // Add to container this.positioningContainerRef.current.appendChild(refMainContainer.current); }; // +--------------------------------------------------------------------------------- // | A helper function to remove all child nodes. // +------------------------------- ColorGradientSelector.prototype.__removeAllChildNodes = function (node) { while (node.lastChild) { node.removeChild(node.lastChild); } }; /** * Adds a new color gradient change listener to this ColorGradientPicker. * * @param {ColorGradientChangeListener} listener - The listener to add. * @returns {boolean} True, if the listener was added and did not exist before. */ ColorGradientSelector.prototype.addChangeListener = function (listener) { for (var i = 0; i < this.installedChangeListeners.length; i++) { if (this.installedChangeListeners[i] === listener) { return false; } } this.installedChangeListeners.push(listener); return true; }; /** * * @param {ColorGradientChangeListener} listener The listener to remove. * @returns {boolean} True, if the listener existed and has been removed. */ ColorGradientSelector.prototype.removeChangeListener = function (listener) { for (var i = 0; i < this.installedChangeListeners.length; i++) { if (this.installedChangeListeners[i] === listener) { this.installedChangeListeners.splice(i, 1); return true; } } return false; }; ColorGradientSelector.prototype.getSelectedColorGradient = function () { return this.colorGradients[this.selectedGradientIndex]; }; ColorGradientSelector.prototype.__fireChangeEvent = function () { var newColorGradient = this.getSelectedColorGradient(); for (var i = 0; i < this.installedChangeListeners.length; i++) { this.installedChangeListeners[i](newColorGradient, this.selectedGradientIndex, this); } }; /** * Creates a handler for click events on the main button. * * @returns */ ColorGradientSelector.prototype.__mainButtonClickHandler = function () { var _self = this; return function (_evt) { // _self.mainButtonContainerRef.current.style.visibility = "hidden"; _self.positioningContainerRef.current.style.visibility = _self.isDropdownOpen ? "hidden" : "visible"; _self.isDropdownOpen = !_self.isDropdownOpen; }; }; /** * Creates a handler for click events on one of the option button in the dropdown. * * @returns */ ColorGradientSelector.prototype.__optionButtonClickHandler = function () { var _self = this; return function (evt) { _self.positioningContainerRef.current.style.visibility = "hidden"; _self.isDropdownOpen = false; var targetButton = evt.currentTarget; var clickedIndex_raw = targetButton.dataset["gradientIndex"]; var clickedIndex = Number.parseInt(clickedIndex_raw); console.log("clickedIndex", clickedIndex, clickedIndex_raw, targetButton.dataset, targetButton); if (Number.isNaN(clickedIndex)) { // Stop here. This is not what we want. return; } // Find child: and set selected. _self.__setSelectedIndex(clickedIndex); _self.__fireChangeEvent(); }; }; ColorGradientSelector.prototype.__optionButtonDeleteHandler = function () { var _this = this; var _self = this; return function (evt) { if (_this.colorGradientOptionRefs.length === 1) { // Keep the last record return; } var targetButton = evt.currentTarget; var clickedIndex_raw = targetButton.dataset["gradientIndex"]; var clickedIndex = Number.parseInt(clickedIndex_raw); console.log("clickedIndex", clickedIndex, clickedIndex_raw, targetButton.dataset, targetButton); if (Number.isNaN(clickedIndex)) { // Stop here. This is not what we want. return; } // Find child: and remove from DOM console.log("this.colorGradientOptionRefs", _this.colorGradientOptionRefs, "clickedIndex", clickedIndex); var refPair = _this.colorGradientOptionRefs[clickedIndex]; refPair.mainButton.current.parentElement.remove(); // Remove from logic // Remove 1 element at the given index _this.colorGradients.splice(clickedIndex, 1); _this.colorGradientOptionRefs.splice(clickedIndex, 1); // Update all following elements in the list. _this.__updateOptionDataSetIndices(clickedIndex); if (_this.selectedGradientIndex >= clickedIndex) { // this.selectedGradientIndex--; _this.__setSelectedIndex(_this.selectedGradientIndex); } console.log("All refs", _this.colorGradientOptionRefs); }; }; /** * Once a slider element was added or removed then the following indices must be updated. * * @param {number} startIndex - The slider index to start updating at. */ ColorGradientSelector.prototype.__updateOptionDataSetIndices = function (startIndex) { // Update all elements to the right of the new elelemt for (var i = startIndex; i < this.colorGradientOptionRefs.length; i++) { this.colorGradientOptionRefs[i].mainButton.current.dataset["gradientIndex"] = "".concat(i); this.colorGradientOptionRefs[i].deleteButton.current.dataset["gradientIndex"] = "".concat(i); } }; ColorGradientSelector.prototype.__setSelectedIndex = function (newSelectedIndex) { for (var i = 0; i < this.colorGradientOptionRefs.length; i++) { var ref = this.colorGradientOptionRefs[i].mainButton; // Find child: and set selected. ref.current.querySelectorAll(".option-gradient-radio-circle")[0].innerHTML = newSelectedIndex === i ? "🞊" : "🞅"; } this.selectedGradientIndex = newSelectedIndex; var selectedGradient = this.colorGradients[this.selectedGradientIndex]; // Display new gradient in the main button this.__setMainButtonGradient(selectedGradient); }; /** * Sets the backround color of the main button (of this dropdown) element. * * @param {ColorGradient} gradient - The gradient color to display. Must not be null. */ ColorGradientSelector.prototype.__setMainButtonGradient = function (gradient) { var colorDisplay = this.mainButtonContainerRef.current.querySelectorAll(".main-button-gradient-display")[0]; colorDisplay.style["background"] = gradient.toColorGradientString(); }; /** * Renders a new option button for the dropdown menu. * * @param {ColorGradient} gradient * @returns {JsxElement} */ ColorGradientSelector.prototype.__renderOptionButton = function (gradient, index, refMainContainer, refActionButton, refDelButton) { return (NoReact.createElement("div", { sx: { d: "flex", flexDirection: "row" }, ref: refMainContainer }, NoReact.createElement("button", { className: "option-gradient-button", onClick: this.__optionButtonClickHandler(), style: { d: "flex", w: "100%", fontSize: this.css_buttonFontSize, minHeight: this.css_buttonHeight, maxHeight: this.css_buttonHeight }, ref: refActionButton, "data-gradientIndex": "".concat(index) }, NoReact.createElement("div", { className: "option-gradient-radio-circle", sx: { w: "2em", flexShrink: 2, alignContent: "center" } }, index === 0 ? "🞊" : "🞅"), NoReact.createElement("div", { sx: { w: "calc( 100% - 2em )", mr: "1em", background: gradient.toColorGradientString() } }, "\u00A0")), NoReact.createElement("button", { classname: "option-delete-button", sx: { fontSize: this.css_buttonFontSize, minHeight: this.css_buttonHeight, maxHeight: this.css_buttonHeight }, onClick: this.__optionButtonDeleteHandler(), "data-gradientIndex": "".concat(index), ref: refDelButton }, NoReact.createElement("div", { sx: { w: "2em", flexShrink: 2, alignContent: "center" } }, "\uD83D\uDDD1")))); }; /** * Creates a new array of option buttons (refs). * @returns */ ColorGradientSelector.prototype._renderAllOptionButtons = function () { var _this = this; var _self = this; // First clear all references _self.colorGradientOptionRefs = []; return this.colorGradients.map(function (colorGradient, index) { // console.log("num", num, index); var refMainContainer = NoReact.useRef(); var refActionButton = NoReact.useRef(); var refDelButton = NoReact.useRef(); _self.colorGradientOptionRefs.push({ mainButton: refActionButton, deleteButton: refDelButton }); return _this.__renderOptionButton(colorGradient, index, refMainContainer, refActionButton, refDelButton); }); }; /** * Init the container contents. * * @private */ ColorGradientSelector.prototype._render = function () { var _self = this; // console.log("Rendering ...", NoReact); this.containerRef = NoReact.useRef(); this.mainButtonContainerRef = NoReact.useRef(); this.positioningContainerRef = NoReact.useRef(); var selectedGradient = this.colorGradients[this.selectedGradientIndex]; return (NoReact.createElement("div", { id: this.elementID, className: "color-gradient-selector", style: { minWidth: this.css_buttonWidth, maxWidth: this.css_buttonWidth, pos: "relative" }, ref: this.containerRef }, NoReact.createElement("button", { className: "main-button", ref: this.mainButtonContainerRef, style: { d: "flex", minWidth: this.css_buttonWidth, maxWidth: this.css_buttonWidth, minHeight: this.css_buttonHeight, maxHeight: this.css_buttonHeight }, onClick: this.__mainButtonClickHandler() }, NoReact.createElement("div", { className: "main-button-gradient-display", sx: { w: "calc( 100% - ".concat(this.css_buttonFontSize, " )"), background: selectedGradient.toColorGradientString() } }, "\u00A0"), NoReact.createElement("div", { sx: { w: this.css_buttonHeight, flexShrink: 2, fontSize: this.css_buttonFontSize_larger } }, "\u25BE")), NoReact.createElement("div", { className: "positioning-container", ref: this.positioningContainerRef, style: { minWidth: this.css_buttonWidth, maxHeight: "25vh", overflowY: "auto", v: "hidden", d: "flex", fd: "column", pos: "absolute", l: 0, zIndex: 999 } }, _self._renderAllOptionButtons()))); }; // END function render() ColorGradientSelector.DEFAULT_COLOR_GRADIENTS = [ ColorGradient_1.ColorGradient.createDefault(), ColorGradient_1.ColorGradient.createFrom(Color_1.Color.Red, Color_1.Color.Green), ColorGradient_1.ColorGradient.createFrom(Color_1.Color.Blue, Color_1.Color.Gold) ]; return ColorGradientSelector; }()); exports.ColorGradientSelector = ColorGradientSelector; //# sourceMappingURL=ColorGradientSelector.js.map