UNPKG

figma-gridgen

Version:

Utilizes built-in Figma rectangles, lines, and texts to generate tables with neatly organized layers

429 lines (413 loc) 15.9 kB
import "./ui.css"; import * as Utils from "./utils/utils"; import * as Interfaces from "./models/interfaces"; import * as Constants from "./models/constants"; import iro from "@jaames/iro"; /* State Changes Variable */ let isShiftHeld: boolean = false; let isAltHeld: boolean = false; /* Store Font Options, Active Mode, and Create Message */ let processedFontOptions: { [key: string]: string[] } = {}; let createMessage: Interfaces.PluginMessage; let activeMode: string = Constants.Modes.CELL_AND_TABLE_SIZE; /* Run after onLoad */ window.addEventListener("load", function() { Utils.getHTMLInputElementById("tableWidth").select(); }); /* Receive message from plugin code */ onmessage = msg => { processedFontOptions = msg.data.pluginMessage.fontOptions; createMessage = msg.data.pluginMessage.createMessage; const fontFamilyOptionsHTML = Utils.constructFontFamilyOptions(processedFontOptions); Utils.getHTMLElementById("tableFontFamilyOptions").innerHTML = fontFamilyOptionsHTML; Utils.getHTMLElementById("headerFontFamilyOptions").innerHTML = fontFamilyOptionsHTML; if (createMessage) { resetInputToDefault(createMessage); } else { setDefaultForMode(activeMode); setDefaultForGenericInputs(); } }; /* ----------------- Color Pickers ----------------- */ let backgroundPickerMode: number = -1; // 0 is primary, 1 is striped, 2 is border let backgroundColorPicker: iro.ColorPicker = new (iro.ColorPicker as any)( Utils.getHTMLElementById("backgroundPicker"), { width: 200, }, ); const primaryPickerButton: HTMLInputElement = Utils.getHTMLInputElementById("primaryPickerButton"); const stripedPickerButton: HTMLInputElement = Utils.getHTMLInputElementById("stripedPickerButton"); const borderPickerButton: HTMLInputElement = Utils.getHTMLInputElementById("borderPickerButton"); primaryPickerButton.onclick = () => { backgroundPickerMode = 0; const primaryBackgroundInput: HTMLInputElement = Utils.getHTMLInputElementById("primarybackgroundColor"); backgroundColorPicker.color.set(primaryBackgroundInput.value); backgroundColorPicker.on("color:change", function(color) { if (backgroundPickerMode === 0) { primaryBackgroundInput.value = (color.hexString as string).toUpperCase(); } }); let modal: HTMLElement = Utils.getHTMLElementById("pickerModal"); modal.style.display = "grid"; }; stripedPickerButton.onclick = () => { backgroundPickerMode = 1; const stripedBackgroundInput: HTMLInputElement = Utils.getHTMLInputElementById("stripedbackgroundColor"); backgroundColorPicker.color.set(stripedBackgroundInput.value); backgroundColorPicker.on("color:change", function(color) { if (backgroundPickerMode === 1) { stripedBackgroundInput.value = (color.hexString as string).toUpperCase(); } }); let modal: HTMLElement = Utils.getHTMLElementById("pickerModal"); modal.style.display = "grid"; }; borderPickerButton.onclick = () => { backgroundPickerMode = 2; const borderBackgroundInput: HTMLInputElement = Utils.getHTMLInputElementById("borderColor"); backgroundColorPicker.color.set(borderBackgroundInput.value); backgroundColorPicker.on("color:change", function(color) { if (backgroundPickerMode === 2) { borderBackgroundInput.value = (color.hexString as string).toUpperCase(); } }); let modal: HTMLElement = Utils.getHTMLElementById("pickerModal"); modal.style.display = "grid"; }; const modalCloseSpan: HTMLElement = Utils.getHTMLElementById("closeSpan"); modalCloseSpan.onclick = () => { let modal: HTMLElement = Utils.getHTMLElementById("pickerModal"); modal.style.display = "none"; }; /* ----------------- Document OnChange Actions ----------------- */ // Detect inputs state change const inputList: string[] = Object.keys(Constants.inputsAffectedByMode); for (let input of inputList) { document.getElementById(input).onchange = () => { Utils.getHTMLInputElementById(input).classList.remove("invalid"); }; } // Detect radio buttons state change Object.keys(Constants.defaultInputsForModes).forEach(mode => { document.getElementById(mode).onclick = () => { Utils.getHTMLInputElementById(mode).checked && activeMode !== mode ? setDefaultForMode(mode) : null; }; }); // Detect checkboxes state change Object.keys(Constants.CheckboxInputIds).forEach(id => { Utils.getHTMLElementById(Constants.CheckboxInputIds[id]).onchange = () => { toggleCheckboxSubOptions(Constants.CheckboxInputIds[id]); }; }); // Detect table font family dropdown state change document.getElementById("tableFontFamily").onchange = () => { Utils.getHTMLElementById("tableFontStyle").innerHTML = Utils.constructFontStyleOptions( processedFontOptions, Utils.getValue("tableFontFamily", Constants.InputType.STRING) as string, ); }; // Detect header font family dropdown state change document.getElementById("headerFontFamily").onchange = () => { Utils.getHTMLElementById("headerFontStyle").innerHTML = Utils.constructFontStyleOptions( processedFontOptions, Utils.getValue("headerFontFamily", Constants.InputType.STRING) as string, ); }; // Button Actions document.getElementById("create").onclick = () => { createTable(); }; document.getElementById("reset").onclick = () => { createMessage ? resetInputToDefault(createMessage) : null; }; /* Keyboard Navigation */ document.onkeydown = keyDown => { if (keyDown.key) { let activeElement = document.activeElement as HTMLInputElement; switch (keyDown.key) { case "Shift": isShiftHeld = true; keyDown.preventDefault(); break; case "Alt": isAltHeld = true; keyDown.preventDefault(); break; case Constants.ArrowPresses.UP: activeElement.value = computeValueOnArrowPress( Constants.ArrowPresses.UP, activeElement, isShiftHeld, ).toString(); keyDown.preventDefault(); break; case Constants.ArrowPresses.DOWN: activeElement.value = computeValueOnArrowPress( Constants.ArrowPresses.DOWN, activeElement, isShiftHeld, ).toString(); keyDown.preventDefault(); break; case "Tab": // Get selected Mode if (activeElement.id === "create" && isShiftHeld === false) { Utils.getHTMLInputElementById(Constants.defaultInputsForModes[Utils.getActiveMode()][0]).select(); keyDown.preventDefault(); } else if ( activeElement === Utils.getHTMLInputElementById(Constants.defaultInputsForModes[Utils.getActiveMode()][0]) && isShiftHeld === true ) { document.getElementById("create").focus(); keyDown.preventDefault(); } break; case "Enter": if (activeElement.type === "checkbox") { activeElement.checked = !activeElement.checked; toggleCheckboxSubOptions(activeElement.id); } break; case "C": isShiftHeld ? createTable() : null; isShiftHeld ? keyDown.preventDefault() : null; break; case "R": isShiftHeld ? (createMessage ? resetInputToDefault(createMessage) : null) : null; isShiftHeld ? keyDown.preventDefault() : null; break; case "1": isAltHeld && activeMode !== Constants.Modes.CELL_AND_TABLE_SIZE ? setDefaultForMode(Constants.Modes.CELL_AND_TABLE_SIZE) : null; isAltHeld ? keyDown.preventDefault() : null; break; case "2": isAltHeld && activeMode !== Constants.Modes.COUNT_AND_CELL_SIZE ? setDefaultForMode(Constants.Modes.COUNT_AND_CELL_SIZE) : null; isAltHeld ? keyDown.preventDefault() : null; break; case "3": isAltHeld && activeMode !== Constants.Modes.COUNT_AND_TABLE_SIZE ? setDefaultForMode(Constants.Modes.COUNT_AND_TABLE_SIZE) : null; isAltHeld ? keyDown.preventDefault() : null; break; default: break; } } }; document.onkeyup = keyUp => { if (keyUp.key === "Shift") { isShiftHeld = false; } else if (keyUp.key === "Alt") { isAltHeld = false; } }; /* Create Table */ function createTable(): void { // Disable create button and display loader Utils.getHTMLInputElementById("create").disabled = true; Utils.getHTMLElementById("lds").classList.add("is-visible"); Utils.processInputToMessage(); } function computeValueOnArrowPress( arrowPressed: Constants.ArrowPresses, activeElement: HTMLInputElement, isShiftHeld: boolean, ): number { let value: number = parseInt(activeElement.value, 10); return value && !activeElement.list && activeElement.type === "text" ? isShiftHeld ? arrowPressed === Constants.ArrowPresses.UP ? (value += 10) : (value -= 10) : arrowPressed === Constants.ArrowPresses.UP ? (value += 1) : (value -= 1) : null; } /* ----------------- Checkbox SubOptions Toggling ----------------- */ // Toggle (enable or disable) header suboptions or subinputs function toggleHeaderSubOptions(): void { Utils.toggleEditable( Constants.HtmlTagType.INPUT, "floatingFilter", Utils.getHTMLInputElementById("header").checked, Constants.DefaultValuesForInputs.CHECKBOX, ); Utils.toggleEditable( Constants.HtmlTagType.INPUT, "headerHeight", Utils.getHTMLInputElementById("header").checked, Constants.DefaultValuesForInputs.HEADER_HEIGHT, ); Utils.toggleEditable( Constants.HtmlTagType.INPUT, "headerFontFamily", Utils.getHTMLInputElementById("header").checked, Constants.DefaultValuesForInputs.OVERALL_FONT_NAME_FAMILY, ); Utils.toggleEditable( Constants.HtmlTagType.SELECT, "headerFontStyle", Utils.getHTMLInputElementById("header").checked, Utils.constructFontStyleOptions(processedFontOptions, Constants.DefaultValuesForInputs.OVERALL_FONT_NAME_FAMILY), ); Utils.toggleEditable( Constants.HtmlTagType.INPUT, "headerFontSize", Utils.getHTMLInputElementById("header").checked, Constants.DefaultValuesForInputs.OVERALL_FONT_SIZE, ); Utils.toggleEditable( Constants.HtmlTagType.INPUT, "floatingFilterHeight", Utils.getHTMLInputElementById("floatingFilter").checked, Constants.DefaultValuesForInputs.CHECKBOX, ); } // Toggle checkbox suboptions or subinputs function toggleCheckboxSubOptions(checkboxId: string): void { switch (checkboxId) { case Constants.CheckboxInputIds.HEADER: toggleHeaderSubOptions(); break; case Constants.CheckboxInputIds.FLOATING_FILTER: Utils.toggleEditable( Constants.HtmlTagType.INPUT, "floatingFilterHeight", Utils.getHTMLInputElementById(checkboxId).checked, Constants.DefaultValuesForInputs.FLOATING_FILTER_HEIGHT, ); break; case Constants.CheckboxInputIds.ALTERNATE_BACKGROUNDS: Utils.toggleEditable( Constants.HtmlTagType.INPUT, "stripedbackgroundColor", Utils.getHTMLInputElementById(checkboxId).checked, Constants.ColorNameToHex.WHITE, ); break; case Constants.CheckboxInputIds.BORDERS: Utils.toggleEditable( Constants.HtmlTagType.INPUT, "borderColor", Utils.getHTMLInputElementById(checkboxId).checked, Constants.ColorNameToHex.GREY_C7, ); break; default: break; } } /* ----------------- Pre-populate Input Values ----------------- */ /* Set or Reset To Create Message Default */ function resetInputToDefault(createMessage: Interfaces.PluginMessage): void { activeMode = createMessage.mode; Utils.getHTMLInputElementById(createMessage.mode).checked = true; Object.keys(Constants.inputIds).forEach(input => { // check if tag is of type SELECT if (Utils.getHTMLElementById(input).nodeName.toLowerCase() === Constants.HtmlTagType.SELECT) { // check if the SELECT HTML tag is for table font or header font if (input.toLowerCase().includes("header")) { // default value generation to prevent construction of options if header is disabled const defaultValue: string = createMessage.header ? Utils.constructFontStyleOptions( processedFontOptions, createMessage.headerFontFamily, createMessage.headerFontStyle, ) : null; Utils.toggleEditable(Constants.HtmlTagType.SELECT, input, createMessage.header, defaultValue); } else { Utils.toggleEditable( Constants.HtmlTagType.SELECT, input, true, Utils.constructFontStyleOptions( processedFontOptions, createMessage.tableFontFamily, createMessage.tableFontStyle, ), ); } // check if tag is one of the mode-specific ones } else if (Object.keys(Constants.inputsAffectedByMode).indexOf(input) > -1) { // then check if it's enabled for this mode if (Constants.defaultInputsForModes[createMessage.mode].indexOf(input) > -1) { Utils.toggleEditable(Constants.HtmlTagType.INPUT, input, true, createMessage[input]); } else { Utils.toggleEditable(Constants.HtmlTagType.INPUT, input, false, createMessage[input]); } } else { const dependentInputs: string[] = [ "headerHeight", "headerFontFamily", "headerFontStyle", "headerFontSize", "floatingFilterHeight", "stripedbackgroundColor", "borderColor", ]; // logic to determine if input is editable based on dependency input const editable: boolean = createMessage[input] === 0 ? false : createMessage[input] === "N.A." ? false : dependentInputs.indexOf(input) > -1 ? createMessage[input] : input === "floatingFilter" ? createMessage.header : true; Utils.toggleEditable(Constants.HtmlTagType.INPUT, input, editable, createMessage[input]); // then set the checkbox state based on the stored values if (Constants.genericInputs[input] === Constants.DefaultValuesForInputs.CHECKBOX) { Utils.getHTMLInputElementById(input).checked = createMessage[input]; } } }); Utils.resetInvalidInput(); Utils.getHTMLInputElementById(Constants.defaultInputsForModes[createMessage.mode][0]).select(); } /* Set Input Values */ // Default per mode function setDefaultForMode(mode: string): void { Utils.getHTMLInputElementById(mode).checked = true; const inputList: string[] = Object.keys(Constants.inputsAffectedByMode); for (let input of inputList) { if (Constants.defaultInputsForModes[mode].indexOf(input) > -1) { Utils.toggleEditable(Constants.HtmlTagType.INPUT, input, true, Constants.inputsAffectedByMode[input]); } else { Utils.toggleEditable(Constants.HtmlTagType.INPUT, input, false, Constants.inputsAffectedByMode[input]); } } Utils.resetInvalidInput(); Utils.getHTMLInputElementById(Constants.defaultInputsForModes[mode][0]).select(); activeMode = mode; } // Default for the rest function setDefaultForGenericInputs(): void { Object.keys(Constants.genericInputs).forEach(input => { if (Constants.genericInputs[input] === Constants.DefaultValuesForInputs.OVERALL_FONT_NAME_STYLE) { Utils.toggleEditable( Constants.HtmlTagType.SELECT, input, true, Utils.constructFontStyleOptions( processedFontOptions, Constants.DefaultValuesForInputs.OVERALL_FONT_NAME_FAMILY, ), ); } else { Utils.toggleEditable(Constants.HtmlTagType.INPUT, input, true, Constants.genericInputs[input]); if (Constants.genericInputs[input] === Constants.DefaultValuesForInputs.CHECKBOX) { Utils.getHTMLInputElementById(input).checked = true; } } }); }