UNPKG

@silexlabs/grapesjs-data-source

Version:
384 lines 14.8 kB
"use strict"; /* * Silex website builder, free/libre no-code tool for makers. * Copyright (c) 2023 lexoyo and Silex Labs foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CustomStatesEditor = void 0; const lit_1 = require("lit"); const ref_js_1 = require("lit/directives/ref.js"); const decorators_js_1 = require("lit/decorators.js"); const state_1 = require("../model/state"); require("./state-editor"); const defaultStyles_1 = require("./defaultStyles"); const token_1 = require("../model/token"); const utils_1 = require("../utils"); /** * Editor for selected element's states * */ class CustomStatesEditor extends lit_1.LitElement { constructor() { super(...arguments); this.disabled = false; this.privateState = false; this.title = 'Custom states'; this.defaultFixed = false; this.createPrompt = 'Name this state'; this.renamePrompt = 'Rename this state'; this.defaultName = 'New state'; this.hideLoopData = false; this.helpText = ''; this.helpLink = ''; this._reservedNames = []; this.editor = null; this.redrawing = false; } // This is a comma separated list of reserved names // Or an array of reserved names get reservedNames() { return this._reservedNames; } set reservedNames(value) { if (typeof value === 'string') this._reservedNames = value.split(',').map(s => s.trim()); else this._reservedNames = value; } setEditor(editor) { if (this.editor) { console.warn('property-editor setEditor already set'); return; } this.editor = editor; // Update the UI when a page is added/renamed/removed this.editor.on('page', () => this.requestUpdate()); // Update the UI on component selection change this.editor.on('component:selected', () => this.requestUpdate()); // Update the UI on component change this.editor.on('component:update', () => this.requestUpdate()); } getHead(selected) { return (0, lit_1.html) ` <style> ${defaultStyles_1.PROPERTY_STYLES} </style> <slot></slot> <section class="ds-section"> <div> <div class="gjs-traits-label"> <span>${this.title}</span> <span> ${selected ? (0, lit_1.html) ` <button title="Add a new state" class="ds-states__add-button ds-states__button" @click=${() => { const item = this.createCustomState(selected); if (!item) return; this.setState(selected, item.name, item.state); }} >+</button> ` : ''} ${this.helpText ? (0, lit_1.html) ` <details class="ds-states__help"> <summary>Help</summary> <div class="ds-states__help--tooltip"> <span>${this.helpText}</span> ${this.helpLink ? (0, lit_1.html) ` <a class="ds-states__help-link" href="${this.helpLink}" target="_blank" >\u{1F517} Read more...</a> ` : ''} </div> </details> ` : ''} </span> </div> </div> </section> `; } render() { var _a; super.render(); this.redrawing = true; const selected = (_a = this.editor) === null || _a === void 0 ? void 0 : _a.getSelected(); const empty = (0, lit_1.html) ` ${this.getHead(null)} <p class="ds-empty">Select an element to edit its states</p> `; if (!this.editor || this.disabled) { this.redrawing = false; return (0, lit_1.html) ``; } if (!selected) { this.redrawing = false; return empty; } const items = this.getStateIds(selected) .map(stateId => ({ name: stateId, publicState: !this.privateState, state: this.getState(selected, stateId), })) .filter(item => item.state && !item.state.hidden); const result = (0, lit_1.html) ` ${this.getHead(selected)} <div class="ds-states"> <div class="ds-states__items"> ${items.length === 0 ? (0, lit_1.html) ` <p>Use the "+" button to add elements to this list</p> ` : ''} ${items .map((item, index) => (0, lit_1.html) ` <div class="ds-states__item"> ${this.getStateEditor(selected, item.state.label || '', item.name)} <div class="ds-states__buttons"> <button title="Remove this state" class="ds-states__remove-button ds-states__button" @click=${() => { this.removeState(selected, item.name); this.requestUpdate(); }} >x</button> <button title="Rename this state" class="ds-states__rename-button ds-states__button" @click=${() => { const newItem = this.renameCustomState(item); if (!newItem || newItem === item) return; this.removeState(selected, item.name); this.setState(selected, newItem.name, newItem.state); this.requestUpdate(); }} >\u270F</button> <button title="Move this state up" class="ds-states__item-move-up ds-states__button${index === 0 ? ' ds-states__button--disabled' : ''}" @click=${() => { items.splice(index - 1, 0, items.splice(index, 1)[0]); this.updateOrderCustomStates(selected, items); }} >\u2191</button> <button title="Move this state down" class="ds-states__item-move-down ds-states__button${index === items.length - 1 ? ' ds-states__button--disabled' : ''}" @click=${() => { items.splice(index + 1, 0, items.splice(index, 1)[0]); this.updateOrderCustomStates(selected, items); }} >\u2193</button> </div> </div> <hr class="ds-states__sep" /> `)} </div> </div> `; this.redrawing = false; return result; } /** * Get the states for this type of editor */ getStateIds(component) { return (0, state_1.getStateIds)(component, !this.privateState) // Filter out the states which are properties .filter(stateId => !this.reservedNames.includes(stateId)); } /** * Get the states for this type of editor */ getState(component, name) { return (0, state_1.getState)(component, name, !this.privateState); } /** * Set the states for this type of editor */ setState(component, name, state) { (0, state_1.setState)(component, name, state, !this.privateState); } /** * Remove the states for this type of editor */ removeState(component, name) { (0, state_1.removeState)(component, name, !this.privateState); } getStateEditor(selected, label, name) { return (0, lit_1.html) ` <state-editor .selected=${selected} .editor=${this.editor} id="${name}" name=${name} ?hide-loop-data=${this.hideLoopData} default-fixed=${this.defaultFixed} ${(0, ref_js_1.ref)(el => { if (el) { const stateEditor = el; stateEditor.data = this.getTokens(selected, name); } })} @change=${() => this.onChange(selected, name, label)} .disabled=${this.disabled} > <label slot="label">${label || name}</label> </state-editor> `; } onChange(component, name, label) { if (this.redrawing) return; const stateEditor = this.shadowRoot.querySelector(`#${name}`); this.setState(component, name, { expression: stateEditor.data, label, }); } getTokens(component, name) { const state = this.getState(component, name); if (!state || !state.expression) return []; return state.expression.map(token => { try { return (0, token_1.fromStored)(token, component.getId()); } catch (_a) { // FIXME: notify user console.error('Error while getting expression result type in getTokens', { expression: state.expression, component, name }); return { type: 'property', propType: 'field', fieldId: 'unknown', label: 'unknown', kind: 'scalar', typeIds: [], }; } }); } /** * Rename a custom state */ renameCustomState(item) { var _a, _b, _c; const label = (_c = (_b = (_a = prompt(this.renamePrompt, item.state.label)) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === null || _b === void 0 ? void 0 : _b.replace(/[^a-z0-9]/g, '-')) === null || _c === void 0 ? void 0 : _c.replace(/^-+|-+$/g, ''); if (!label || label === item.state.label) return item; return Object.assign(Object.assign({}, item), { state: Object.assign(Object.assign({}, item.state), { label: label }) }); } /** * Update the custom states, in the order of the list */ updateOrderCustomStates(component, items) { const stateIds = this.getStateIds(component); // Remove all states stateIds.forEach(stateId => { if (items.map(item => item.name).includes(stateId)) { this.removeState(component, stateId); } }); // Add states in the order of the list items.forEach(item => { this.setState(component, item.name, item.state); }); } /** * Create a new custom state */ createCustomState(component) { const label = (0, utils_1.cleanStateName)(prompt(this.createPrompt, this.defaultName)); if (!label) return null; if (this.reservedNames.includes(label)) { alert(`The name ${label} is reserved, please choose another name`); return null; } const stateId = `${component.getId()}-${Math.random().toString(36).slice(2)}`; const state = { label, expression: [], }; this.setState(component, stateId, state); return { name: stateId, state, publicState: !this.privateState, }; } } exports.CustomStatesEditor = CustomStatesEditor; __decorate([ (0, decorators_js_1.property)({ type: Boolean }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "disabled", void 0); __decorate([ (0, decorators_js_1.property)({ type: Boolean, attribute: 'private-state' }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "privateState", void 0); __decorate([ (0, decorators_js_1.property)({ type: String }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "title", void 0); __decorate([ (0, decorators_js_1.property)({ type: Boolean, attribute: 'default-fixed' }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "defaultFixed", void 0); __decorate([ (0, decorators_js_1.property)({ type: String, attribute: 'create-prompt' }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "createPrompt", void 0); __decorate([ (0, decorators_js_1.property)({ type: String, attribute: 'rename-prompt' }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "renamePrompt", void 0); __decorate([ (0, decorators_js_1.property)({ type: String, attribute: 'default-name' }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "defaultName", void 0); __decorate([ (0, decorators_js_1.property)({ type: String, attribute: 'reserved-names' }), __metadata("design:type", Object), __metadata("design:paramtypes", [Object]) ], CustomStatesEditor.prototype, "reservedNames", null); __decorate([ (0, decorators_js_1.property)({ type: Boolean, attribute: 'hide-loop-data' }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "hideLoopData", void 0); __decorate([ (0, decorators_js_1.property)({ type: String, attribute: 'help-text' }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "helpText", void 0); __decorate([ (0, decorators_js_1.property)({ type: String, attribute: 'help-link' }), __metadata("design:type", Object) ], CustomStatesEditor.prototype, "helpLink", void 0); if (!customElements.get('custom-states-editor')) { customElements.define('custom-states-editor', CustomStatesEditor); } //# sourceMappingURL=custom-states-editor.js.map