@silexlabs/grapesjs-symbols
Version:
Symbols for GrapesJS
228 lines • 8.85 kB
JavaScript
import { render, html } from 'lit-html';
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
import { allowDrop, createSymbol, deleteSymbol, getSymbol, getSymbols } from '../utils';
function closestHtml(child, attr) {
let ptr = child;
while (ptr && !ptr.getAttribute(attr)) {
ptr = ptr.parentElement;
}
return ptr;
}
export function confirmDialog({ editor, content: main, title, primaryLabel, secondaryLabel = 'Cancel', cbk, lsKey, }) {
// Check if the user has already been asked
if (localStorage.getItem(lsKey) === 'on') {
cbk();
}
else {
const content = document.createElement('div');
editor.Modal.open({
title,
content,
});
let remember = 'off';
render(html `<main>
${unsafeHTML(main)}
</main><footer style="
display: flex;
justify-content: space-between;
margin-top: 30px;
">
<div>
<label class="gjs-field gjs-field-checkbox" style="
float: left;
margin-right: 10px;
">
<input type="checkbox" id="remember" @click=${({ target: rememberCheckbox }) => remember = rememberCheckbox === null || rememberCheckbox === void 0 ? void 0 : rememberCheckbox.value}>
<i class="gjs-chk-icon"></i>
</label>
<label for="remember">Don't ask me again</label>
</div>
<div>
<button
class="gjs-btn-prim"
@click=${() => editor.Modal.close()}
style="
margin-left: auto;
background: transparent;
margin-right: 10px;
">${secondaryLabel}</button>
<button class="gjs-btn-prim" @click=${() => {
cbk();
localStorage.setItem(lsKey, remember);
editor.Modal.close();
}}>${primaryLabel}</button>
</div>
</footer>`, content);
}
}
export default class SymbolsView {
constructor(options) {
this.options = options;
this.lastPos = null;
this.lastTarget = null;
// listen to redraw UI
options.editor.on('component:selected', () => this.render());
// listen to drag event in order to have access to the drop target
options.editor.on('sorter:drag', (event) => {
this.lastPos = event.pos;
this.lastTarget = event.target;
});
// Listen to events on `symbol`
options.editor.on('symbol', () => {
// Redraw the UI
this.render();
});
// list wrapper
this.el = document.createElement('div');
this.el.classList.add('symbols__wrapper');
document.querySelector(options.appendTo)
.appendChild(this.el);
// first render
this.render();
}
render() {
const symbols = getSymbols(this.options.editor);
symbols.forEach(symbolInfo => {
if (!symbolInfo.main) {
console.warn('Symbol has no main component:', symbolInfo);
return;
}
});
const selected = this.options.editor.getSelected();
render(html `
<style>
.symbols__symbol-selected {
border: 1px solid ${this.options.highlightColor};
}
.symbols__symbol {
position: relative;
}
.symbols__num {
font-size: xx-small;
}
.symbols__empty {
padding: 10px;
text-align: center;
width: 100%;
}
.symbols__remove {
position: absolute;
top: 0; right: 0;
width: 20px;
line-height: 1;
cursor: pointer;
}
</style>
<main class="symbols__list" @dragend=${(event) => this.onDrop(event)}>
<div class="gjs-blocks-c">
${
// keep the same structure as the layers panel
symbols
.filter(s => s.main)
.map(symbolData => html `
<div
class="gjs-block gjs-one-bg gjs-four-color-h symbols__symbol
${!!selected && symbolData.instances.includes(selected) ? 'symbols__symbol-selected' : ''}
${symbolData.main.get('icon') || 'fa fa-diamond'}
"
title="" draggable="true"
data-symbol-id=${symbolData.main.getId()}
>
<div title="Unlink all instances and delete Symbol" class="symbols__remove" @click=${(event) => this.onRemove(event)}>
<svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"></path></svg>
</div>
<div class="gjs-block-label">
${symbolData.main.getName()}
<div class="symbols__num">
${symbolData.instances.length} instances
</div>
</div>
</div>
`)}
${symbols.length ? '' : html `<div class="symbols__empty">
${this.options.emptyText}
</div>`}
</div>
</main>
`, this.el);
return this;
}
onDrop(event) {
var _a;
const symbolId = event.target.dataset.symbolId;
if (symbolId) {
const symbolInfo = getSymbol(this.options.editor, this.options.editor.Components.getById(symbolId));
if (symbolInfo) {
const parentId = (_a = this.lastTarget) === null || _a === void 0 ? void 0 : _a.id;
if (!parentId)
throw new Error('Can not create the symbol: missing param id');
const parent = this.lastTarget ? this.options.editor.Components.getById(parentId) : null;
if (parent) {
// Make sure we have a target and position
this.lastTarget = this.lastTarget || this.options.editor.Canvas.getBody();
this.lastPos = this.lastPos || { placement: 'after', index: 0 };
// Get the parent component from the HTML element
const parentId = this.lastTarget.getAttribute('id');
if (!parentId)
throw new Error('Can not create the symbol: missing param id');
const parent = this.options.editor.Components.allById()[parentId];
// Check if we can drop the symbol there
if (allowDrop(this.options.editor, parent)) {
// create the new component
const { instances } = createSymbol(this.options.editor, symbolInfo.main);
// Last one is the added one
const instance = instances[instances.length - 1];
const [c] = this.lastPos.placement === 'after' ? parent.append(instance) :
parent.append(instance, { at: this.lastPos.index });
// Select the new component
// Break unit tests? editor.select(c, { scroll: true })
return c;
}
else {
throw new Error('Can not create the symbol: one of the parent is in the symbol');
}
}
else {
throw new Error('Can not create the symbol: parent not found');
}
}
else {
throw new Error(`Could not create an instance of symbol ${symbolId}: symbol not found`);
}
}
else {
// not a symbol creation
}
return null;
}
onRemove({ target: deleteButton }) {
// Warn the user
confirmDialog({
editor: this.options.editor,
title: 'Delete Symbol',
content: `
<p>Are you sure you want to delete this symbol?</p>
<p>Deleting this symbol <em>will not</em> delete its instances, just disconnects them. Confirm to proceed or cancel to maintain the current link.</p>
`,
primaryLabel: 'Delete',
cbk: () => {
this.onRemoveConfirm(deleteButton);
},
lsKey: 'delete-symbol',
});
}
onRemoveConfirm(target) {
var _a;
const symbolId = (_a = closestHtml((target), 'data-symbol-id')) === null || _a === void 0 ? void 0 : _a.dataset.symbolId;
if (!symbolId) {
throw new Error('Can not delete symbol: missing param symbolId');
}
const symbol = this.options.editor.Components.getSymbols()
.find(symbol => symbol.getId() === symbolId);
if (!symbol) {
throw new Error('Can not delete symbol: symbol not found');
}
deleteSymbol(this.options.editor, symbol);
}
}
//# sourceMappingURL=SymbolsView.js.map