@starzhuimeng/formula-editor
Version:
A configurable formula editor with customizable symbols
288 lines • 10.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SymbolPanel = void 0;
const dom_1 = require("../utils/dom");
/**
* 符号面板类
*/
class SymbolPanel {
constructor(options) {
this.tabButtons = [];
this.contentPanels = [];
this.activeTabIndex = 0;
this.options = options;
this.container = options.container;
this.panel = (0, dom_1.createElement)('div', 'formula-editor-symbol-panel');
this.initStyles();
this.renderPanel();
this.container.appendChild(this.panel);
}
/**
* 初始化面板样式
*/
initStyles() {
const styles = this.options.styles || {};
(0, dom_1.setStyles)(this.panel, {
backgroundColor: styles.backgroundColor || '#fff',
border: `1px solid ${styles.borderColor || '#ddd'}`,
borderRadius: '4px',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
display: 'flex',
flexDirection: 'column',
margin: '8px 0',
overflow: 'hidden',
width: '100%'
});
}
/**
* 渲染符号面板
*/
renderPanel() {
var _a, _b;
// 创建标签页导航
const tabNav = (0, dom_1.createElement)('div', 'formula-editor-symbol-tabs');
(0, dom_1.setStyles)(tabNav, {
display: 'flex',
borderBottom: `2px solid ${((_a = this.options.styles) === null || _a === void 0 ? void 0 : _a.borderColor) || '#ddd'}`,
backgroundColor: '#f5f5f5',
flexWrap: 'wrap',
padding: '4px 4px 0 4px',
position: 'relative',
zIndex: '1'
});
// 创建内容区域
const contentContainer = (0, dom_1.createElement)('div', 'formula-editor-symbol-content');
(0, dom_1.setStyles)(contentContainer, {
padding: '12px',
display: 'flex',
flexWrap: 'wrap',
maxHeight: '180px',
overflowY: 'auto',
backgroundColor: '#fff',
borderTop: `1px solid ${((_b = this.options.styles) === null || _b === void 0 ? void 0 : _b.borderColor) || '#eee'}`
});
// 解析组并创建标签
const groups = this.parseGroups();
groups.forEach((group, index) => {
// 创建标签按钮
const tabButton = this.createTabButton(group, index);
this.tabButtons.push(tabButton);
tabNav.appendChild(tabButton);
// 创建内容面板
const contentPanel = this.createContentPanel(group, index);
this.contentPanels.push(contentPanel);
contentContainer.appendChild(contentPanel);
});
// 默认激活第一个标签
if (this.tabButtons.length > 0) {
this.activateTab(0);
}
// 添加到面板
(0, dom_1.appendChildren)(this.panel, tabNav, contentContainer);
}
/**
* 解析符号组
* 支持两种格式:
* 1. 老格式: { category: symbols[] }
* 2. 新格式: { category: SymbolGroup }
*/
parseGroups() {
const result = [];
const categories = Object.keys(this.options.symbols);
categories.forEach(category => {
const value = this.options.symbols[category];
if (value) {
// 检查是否为 SymbolGroup 对象 (有 symbols 属性)
if (typeof value === 'object' && 'symbols' in value) {
const group = value;
result.push({
name: category,
displayName: group.displayName || this.formatCategoryName(category),
symbols: group.symbols,
style: group.style
});
}
// 老格式: 直接是符号数组
else if (Array.isArray(value)) {
result.push({
name: category,
displayName: this.formatCategoryName(category),
symbols: value
});
}
}
});
return result;
}
/**
* 创建标签按钮
*/
createTabButton(group, index) {
var _a, _b;
const button = (0, dom_1.createElement)('button', 'formula-editor-tab-button');
button.textContent = group.displayName;
// 基本样式
const buttonStyle = {
padding: '10px 15px',
border: 'none',
background: '#f0f0f0',
cursor: 'pointer',
outline: 'none',
borderRight: `1px solid ${((_a = this.options.styles) === null || _a === void 0 ? void 0 : _a.borderColor) || '#ddd'}`,
fontWeight: 'normal',
color: ((_b = this.options.styles) === null || _b === void 0 ? void 0 : _b.tabColor) || '#333',
transition: 'all 0.2s ease',
margin: '0',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
minWidth: '85px',
textAlign: 'center',
fontSize: '14px',
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)'
};
// 应用自定义样式
if (group.style) {
Object.assign(buttonStyle, group.style);
}
(0, dom_1.setStyles)(button, buttonStyle);
(0, dom_1.addEventListeners)(button, {
click: () => this.activateTab(index)
});
return button;
}
/**
* 创建内容面板
*/
createContentPanel(group, index) {
const panel = (0, dom_1.createElement)('div', 'formula-editor-content-panel');
(0, dom_1.setStyles)(panel, {
display: 'none',
flexWrap: 'wrap',
width: '100%',
padding: '5px'
});
// 为每个符号创建按钮
group.symbols.forEach(symbolItem => {
var _a, _b;
const symbolButton = (0, dom_1.createElement)('button', 'formula-editor-symbol-button');
// 获取符号显示值
const displayValue = typeof symbolItem === 'string' ?
symbolItem :
symbolItem.value;
symbolButton.textContent = displayValue;
// 如果有描述,添加为title属性
if (typeof symbolItem !== 'string' && symbolItem.description) {
symbolButton.title = symbolItem.description;
}
// 基本样式
const buttonStyle = {
width: '40px',
height: '40px',
margin: '5px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
border: `1px solid ${((_a = this.options.styles) === null || _a === void 0 ? void 0 : _a.borderColor) || '#ddd'}`,
borderRadius: '4px',
background: 'white',
cursor: 'pointer',
color: ((_b = this.options.styles) === null || _b === void 0 ? void 0 : _b.symbolColor) || '#333',
fontSize: '18px',
transition: 'transform 0.1s ease, box-shadow 0.1s ease',
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)'
};
// 如果有自定义样式,应用它
if (typeof symbolItem !== 'string' && symbolItem.style) {
Object.assign(buttonStyle, symbolItem.style);
}
(0, dom_1.setStyles)(symbolButton, buttonStyle);
(0, dom_1.addEventListeners)(symbolButton, {
click: () => this.options.onSymbolClick(symbolItem),
mousedown: (e) => {
(0, dom_1.setStyles)(symbolButton, {
transform: 'scale(0.95)',
boxShadow: '0 0 1px rgba(0, 0, 0, 0.2)'
});
},
mouseup: (e) => {
(0, dom_1.setStyles)(symbolButton, {
transform: 'scale(1)',
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)'
});
},
mouseleave: (e) => {
(0, dom_1.setStyles)(symbolButton, {
transform: 'scale(1)',
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)'
});
}
});
panel.appendChild(symbolButton);
});
return panel;
}
/**
* 激活指定的标签
*/
activateTab(index) {
// 更新标签按钮样式
this.tabButtons.forEach((button, i) => {
var _a, _b, _c, _d;
if (i === index) {
(0, dom_1.setStyles)(button, {
fontWeight: 'bold',
borderBottom: `3px solid ${((_a = this.options.styles) === null || _a === void 0 ? void 0 : _a.activeTabBorderColor) || '#007bff'}`,
backgroundColor: ((_b = this.options.styles) === null || _b === void 0 ? void 0 : _b.activeTabColor) || '#fff',
color: ((_c = this.options.styles) === null || _c === void 0 ? void 0 : _c.activeTabColor) ? undefined : '#007bff',
boxShadow: '0 -2px 5px rgba(0, 0, 0, 0.05)'
});
}
else {
(0, dom_1.setStyles)(button, {
fontWeight: 'normal',
borderBottom: 'none',
backgroundColor: '#f0f0f0',
color: ((_d = this.options.styles) === null || _d === void 0 ? void 0 : _d.tabColor) || '#555',
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)'
});
}
});
// 显示/隐藏内容面板
this.contentPanels.forEach((panel, i) => {
panel.style.display = i === index ? 'flex' : 'none';
});
this.activeTabIndex = index;
}
/**
* 格式化分类名称
*/
formatCategoryName(category) {
return category.charAt(0).toUpperCase() + category.slice(1);
}
/**
* 显示符号面板
*/
show() {
this.panel.style.display = 'flex';
}
/**
* 隐藏符号面板
*/
hide() {
this.panel.style.display = 'none';
}
/**
* 切换显示/隐藏状态
*/
toggle() {
if (this.panel.style.display === 'none') {
this.show();
}
else {
this.hide();
}
}
}
exports.SymbolPanel = SymbolPanel;
//# sourceMappingURL=SymbolPanel.js.map