refactor: 重命名SDK为iflow-engine,使用npm包引入第三方引擎

- 将包名从 @fishdingding/bim-engine-sdk 改为 iflow-engine
- 将构建输出文件从 bim-engine-sdk.*.js 改为 iflow-engine.*.js
- 将全局变量从 LyzBimEngineSDK 改为 IflowEngine
- 将第三方引擎SDK从本地引入改为npm包引入 (iflow-engine-base)
- 移除本地 src/engine_base 目录,移至回收站
- 更新所有文档和demo中的引用
This commit is contained in:
yuding
2026-01-22 11:29:51 +08:00
parent 70523e54e5
commit f2460fb981
103 changed files with 32120 additions and 31434 deletions

View File

@@ -0,0 +1,309 @@
/* 根容器 */
.bim-btn-group-root {
display: flex;
gap: 8px;
z-index: 1000;
position: absolute;
pointer-events: auto;
}
.bim-btn-group-root.static {
position: relative;
top: auto;
left: auto;
bottom: auto;
right: auto;
transform: none;
}
.bim-btn-group-root.dir-row {
flex-direction: row;
align-items: center;
}
.bim-btn-group-root.dir-column {
flex-direction: column;
align-items: stretch;
}
/* 分组区域 */
.bim-btn-group-section {
display: flex;
gap: 4px;
background-color: var(--bim-btn-group-section-bg, rgba(17, 17, 17, 0.88));
border-radius: 6px;
padding: 4px;
/* 添加阴影效果,增强视觉层次感 */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2);
}
.bim-btn-group-root.dir-row .bim-btn-group-section {
flex-direction: row;
align-items: center;
}
.bim-btn-group-root.dir-column .bim-btn-group-section {
flex-direction: column;
}
/* 按钮外层 */
.opt-btn-wrapper {
position: relative;
}
/* 按钮本体 */
.opt-btn {
display: flex;
cursor: pointer;
border-radius: 4px;
transition: background-color 0.2s, color 0.2s, border-color 0.2s;
color: var(--bim-btn-text-color, #ccc);
background-color: var(--bim-btn-bg, transparent);
padding: 6px;
align-items: center;
position: relative;
/* 为绝对定位提供锚点 */
justify-content: center;
border: 1px solid transparent;
outline: none;
}
.opt-btn:hover {
background-color: var(--bim-btn-hover-bg, #444);
}
.opt-btn.active {
background-color: var(--bim-btn-active-bg, rgba(255, 255, 255, 0.15));
color: var(--bim-btn-text-active-color, #fff);
/* 开关按钮激活时不显示边框,只改变背景 */
}
/* 开关按钮激活时图标颜色保持不变,继承默认颜色 */
.opt-btn.disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* --- 图标 --- */
.opt-btn-icon {
width: var(--bim-icon-size, 24px);
height: var(--bim-icon-size, 24px);
display: flex;
align-items: center;
justify-content: center;
color: var(--bim-icon-color, #ccc);
flex-shrink: 0;
}
.opt-btn-icon svg {
width: 100%;
height: 100%;
fill: currentColor;
}
/* --- 箭头 --- */
.opt-btn-arrow {
font-size: 10px;
opacity: 0.6;
transition: transform 0.2s;
display: inline-block;
/* 默认情况 (有Label) */
margin-left: 4px;
}
.opt-btn-arrow.rotated {
transform: rotate(180deg);
}
/* --- 文字容器 --- */
.opt-btn-text-wrapper {
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
}
/* --- Label 显示控制 --- */
.opt-btn-label {
display: inline;
}
.opt-btn.no-label .opt-btn-label {
display: none;
}
/* --- 场景 A: 有 Label (常规布局) --- */
.opt-btn.align-vertical:not(.no-label) {
flex-direction: column;
text-align: center;
}
.opt-btn.align-vertical:not(.no-label) .opt-btn-text-wrapper {
margin-top: 4px;
}
.opt-btn.align-vertical:not(.no-label) .opt-btn-label {
font-size: 12px;
line-height: 1.2;
}
.opt-btn.align-horizontal:not(.no-label) {
flex-direction: row;
}
.opt-btn.align-horizontal:not(.no-label) .opt-btn-text-wrapper {
margin-left: 8px;
}
.opt-btn.align-horizontal:not(.no-label) .opt-btn-label {
font-size: 14px;
}
/* --- 场景 B: 无 Label (强制绝对定位) --- */
/* 当没有 label 时text-wrapper 其实只包裹了 arrow */
/* 我们需要让 wrapper 失去布局影响,直接定位内部的 arrow */
.opt-btn.no-label .opt-btn-text-wrapper {
/* 让 wrapper 变为 0 尺寸,不影响 flex 布局 */
width: 0;
height: 0;
margin: 0;
padding: 0;
overflow: visible;
/* 关键:允许子元素溢出 */
position: absolute;
/* 脱离文档流,相对于 .opt-btn */
top: 0;
right: 0;
}
.opt-btn.no-label .opt-btn-arrow {
position: absolute;
top: 2px;
right: 2px;
margin: 0;
/* 清除之前的 margin */
font-size: 8px;
/*
如果父级 wrapper 已经是 top:0, right:0
那么 arrow 相对 wrapper 定位即可
*/
}
/* --- 下拉菜单 & 动画 --- */
.opt-btn-dropdown {
position: absolute;
background-color: var(--bim-toolbar-bg, rgba(17, 17, 17, 0.95));
border-radius: 4px;
padding: 4px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
z-index: 1001;
display: flex;
flex-direction: column;
border: 1px solid rgba(255, 255, 255, 0.1);
/* 动画起始状态 */
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
/* 默认向上偏移一点 */
transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.2, 0, 0.2, 1), visibility 0.2s;
}
/* 动画激活状态 (需要 JS 添加 .show 类,或者直接在 display:flex 时生效?) */
/* 这里的实现有点 tricky因为 JS 里直接 appendChild */
/* 我们可以利用 CSS 动画关键帧,或者简单的 transition */
/* 由于 DOM 是动态插入的,插入瞬间是 opacity: 0 -> requestAnimationFrame -> opacity: 1 */
/* 简单的办法:添加动画 keyframes */
@keyframes dropdown-fade-in {
from {
opacity: 0;
transform: translateY(-8px) scale(0.98);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.opt-btn-dropdown {
/* 覆盖上面的 transition直接用 animation */
animation: dropdown-fade-in 0.2s cubic-bezier(0.2, 0, 0.2, 1) forwards;
/* 初始可见性由 JS 控制append 即显示) */
opacity: 1;
visibility: visible;
transform: none;
}
.opt-btn-dropdown-item {
display: flex;
align-items: center;
padding: 8px 12px;
cursor: pointer;
border-radius: 4px;
color: var(--bim-btn-text-color, #ccc);
transition: background 0.2s, border-color 0.2s, color 0.2s;
box-sizing: border-box;
border: 1px solid transparent;
outline: none;
}
/* 二级菜单项的图标默认颜色 */
.opt-btn-dropdown-item .opt-btn-icon {
color: var(--bim-icon-color, #ccc);
}
.opt-btn-dropdown-item:hover {
background-color: var(--bim-btn-hover-bg, #444);
}
/* 二级菜单项激活态(支持 keepActive 的可视化) */
.opt-btn-dropdown-item.active {
background-color: var(--bim-btn-active-bg, rgba(255, 255, 255, 0.15));
color: var(--bim-btn-text-active-color, #fff);
/* 开关按钮激活时不显示边框,只改变背景 */
}
/* 开关按钮激活时图标颜色保持不变,继承默认颜色 */
/* 下拉菜单项 - 横向布局(图标在左,默认) */
.opt-btn-dropdown-item.align-horizontal {
flex-direction: row;
}
.opt-btn-dropdown-item.align-horizontal .opt-btn-icon {
width: 18px;
height: 18px;
margin-right: 8px;
}
/* 下拉菜单项 - 纵向布局(图标在上) */
.opt-btn-dropdown-item.align-vertical {
flex-direction: column;
text-align: center;
}
.opt-btn-dropdown-item.align-vertical .opt-btn-icon {
width: 24px;
height: 24px;
margin-bottom: 4px;
}
.opt-btn-dropdown-item.align-vertical .opt-btn-dropdown-label {
font-size: 12px;
}
/* --- 特定样式覆盖:底部工具栏 --- */
.bim-btn-group-root.is-bottom-toolbar .opt-btn-icon {
width: 32px;
height: 32px;
}
.bim-btn-group-root.is-bottom-toolbar .opt-btn {
padding: 8px;
}

View File

@@ -0,0 +1,717 @@
import './index.css';
import type {
OptButton,
ButtonGroup,
ButtonGroupOptions,
ButtonConfig,
ButtonGroupColors
} from './index.type';
import { t, localeManager } from '../../services/locale';
import { themeManager } from '../../services/theme';
import type { ThemeConfig } from '../../themes/types';
import { IBimComponent } from '../../types/component';
import type { BimEngine } from '../../bim-engine';
import { EngineEvents } from '../../types/events';
/**
* 通用按钮组组件 (BimButtonGroup)
*/
export class BimButtonGroup implements IBimComponent {
private container: HTMLElement;
private options: ButtonGroupOptions;
private groups: ButtonGroup[] = [];
private activeBtnIds: Set<string> = new Set();
private btnRefs: Map<string, HTMLElement> = new Map();
private dropdownElement: HTMLElement | null = null;
private hoverTimeout: number | null = null;
private customColors: Set<keyof ButtonGroupColors> = new Set(); // 记录用户自定义的颜色属性
private unsubscribeLocale: (() => void) | null = null;
private unsubscribeTheme: (() => void) | null = null;
protected engine: BimEngine | null = null;
private readonly DEFAULT_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect></svg>';
constructor(options: ButtonGroupOptions) {
const el = typeof options.container === 'string'
? document.getElementById(options.container)
: options.container;
if (!el) throw new Error('Container not found');
this.container = el;
// 合并默认配置
this.options = {
showLabel: true,
visibility: {},
direction: 'row', // 默认横向
position: 'static', // 默认静态定位
align: 'vertical', // 默认图标在上
expand: 'down', // 默认向下展开
...options
};
// 记录初始传入的自定义颜色
const colorKeys: (keyof ButtonGroupColors)[] = [
'backgroundColor', 'btnBackgroundColor', 'btnHoverColor',
'btnActiveColor', 'iconColor', 'iconActiveColor',
'textColor', 'textActiveColor'
];
colorKeys.forEach(key => {
if (options[key]) {
this.customColors.add(key);
}
});
this.initContainer();
this.applyStyles();
}
public setEngine(engine: BimEngine) {
this.engine = engine;
}
protected emit<K extends keyof EngineEvents>(event: K, payload: EngineEvents[K]) {
if (this.engine) {
this.engine.emit(event, payload);
} else {
console.warn('[BimButtonGroup] Engine not set, cannot emit event:', event);
}
}
private initContainer(): void {
this.container.innerHTML = '';
this.container.classList.add('bim-btn-group-root');
if (this.options.direction === 'column') {
this.container.classList.add('dir-column');
} else {
this.container.classList.add('dir-row');
}
if (this.options.className) {
this.container.classList.add(this.options.className);
}
this.updatePosition();
// 添加事件拦截,防止点击穿透到 3D 引擎
this.setupEventInterception(this.container);
}
/**
* 设置事件拦截,防止事件冒泡到下层元素(如 3D 引擎)
*/
private setupEventInterception(el: HTMLElement): void {
const stopPropagation = (e: Event) => {
e.stopPropagation();
};
const events = [
'click', 'dblclick', 'contextmenu', 'wheel',
'mousedown', 'mouseup', 'mousemove',
'touchstart', 'touchend', 'touchmove',
'pointerdown', 'pointerup', 'pointermove', 'pointerenter', 'pointerleave', 'pointerover', 'pointerout'
];
events.forEach(eventType => {
el.addEventListener(eventType, stopPropagation, { passive: false });
});
}
private updatePosition() {
const pos = this.options.position;
const style = this.container.style;
style.top = ''; style.bottom = ''; style.left = ''; style.right = ''; style.transform = '';
if (pos === 'static') {
this.container.classList.add('static');
return;
}
this.container.classList.remove('static');
this.container.style.position = 'absolute';
if (typeof pos === 'object' && 'x' in pos) {
style.left = `${pos.x}px`;
style.top = `${pos.y}px`;
} else {
const margin = '20px';
switch (pos) {
case 'top-left':
style.top = margin; style.left = margin;
break;
case 'top-center':
style.top = margin; style.left = '50%'; style.transform = 'translateX(-50%)';
break;
case 'top-right':
style.top = margin; style.right = margin;
break;
case 'bottom-left':
style.bottom = margin; style.left = margin;
break;
case 'bottom-center':
style.bottom = margin; style.left = '50%'; style.transform = 'translateX(-50%)';
break;
case 'bottom-right':
style.bottom = margin; style.right = margin;
break;
case 'left-center':
style.left = margin; style.top = '50%'; style.transform = 'translateY(-50%)';
break;
case 'right-center':
style.right = margin; style.top = '50%'; style.transform = 'translateY(-50%)';
break;
case 'center':
style.top = '50%'; style.left = '50%'; style.transform = 'translate(-50%, -50%)';
break;
}
}
}
/**
* 应用样式到容器
*/
private applyStyles(): void {
const style = this.container.style;
if (this.options.backgroundColor) style.setProperty('--bim-btn-group-section-bg', this.options.backgroundColor);
if (this.options.btnBackgroundColor) style.setProperty('--bim-btn-bg', this.options.btnBackgroundColor);
if (this.options.btnHoverColor) style.setProperty('--bim-btn-hover-bg', this.options.btnHoverColor);
if (this.options.btnActiveColor) style.setProperty('--bim-btn-active-bg', this.options.btnActiveColor);
if (this.options.iconColor) style.setProperty('--bim-icon-color', this.options.iconColor);
if (this.options.iconActiveColor) style.setProperty('--bim-icon-active-color', this.options.iconActiveColor);
if (this.options.textColor) style.setProperty('--bim-btn-text-color', this.options.textColor);
if (this.options.textActiveColor) style.setProperty('--bim-btn-text-active-color', this.options.textActiveColor);
// 同步更新所有已存在的dropdown元素的CSS变量dropdown被添加到body无法继承容器的CSS变量
const dropdowns = document.querySelectorAll('.opt-btn-dropdown');
dropdowns.forEach(dropdown => {
const dropdownStyle = (dropdown as HTMLElement).style;
if (this.options.iconColor) dropdownStyle.setProperty('--bim-icon-color', this.options.iconColor);
if (this.options.iconActiveColor) dropdownStyle.setProperty('--bim-icon-active-color', this.options.iconActiveColor);
if (this.options.textColor) dropdownStyle.setProperty('--bim-btn-text-color', this.options.textColor);
if (this.options.textActiveColor) dropdownStyle.setProperty('--bim-btn-text-active-color', this.options.textActiveColor);
if (this.options.btnBackgroundColor) dropdownStyle.setProperty('--bim-btn-bg', this.options.btnBackgroundColor);
if (this.options.btnHoverColor) dropdownStyle.setProperty('--bim-btn-hover-bg', this.options.btnHoverColor);
if (this.options.btnActiveColor) dropdownStyle.setProperty('--bim-btn-active-bg', this.options.btnActiveColor);
});
}
/**
* 设置主题的primary颜色用于边框等
*/
private setPrimaryColor(color: string): void {
this.container.style.setProperty('--bim-primary-color', color);
// 同步更新所有dropdowndropdown被添加到body无法继承容器的CSS变量
const dropdowns = document.querySelectorAll('.opt-btn-dropdown');
dropdowns.forEach(dropdown => {
(dropdown as HTMLElement).style.setProperty('--bim-primary-color', color);
});
}
/**
* 设置主题颜色
* 只会应用到没有被用户自定义的颜色属性上
*/
public setTheme(theme: ThemeConfig): void {
const themeColors: ButtonGroupColors = {
backgroundColor: theme.panelBackground,
btnBackgroundColor: theme.componentBackground,
btnHoverColor: theme.componentHover,
btnActiveColor: theme.componentActive,
iconColor: theme.icon,
iconActiveColor: theme.iconActive,
textColor: theme.textSecondary,
textActiveColor: theme.textPrimary
};
// 只应用没有被自定义的颜色
Object.entries(themeColors).forEach(([key, value]) => {
const colorKey = key as keyof ButtonGroupColors;
if (!this.customColors.has(colorKey)) {
this.options[colorKey] = value;
}
});
this.applyStyles();
this.setPrimaryColor(theme.primary);
}
/**
* 直接设置颜色(强制覆盖)
* 设置的颜色会被标记为自定义,后续的 setTheme 不会覆盖它们
*/
public setColors(colors: ButtonGroupColors): void {
// 更新 options
this.options = { ...this.options, ...colors };
// 标记这些颜色为自定义
Object.keys(colors).forEach(key => {
this.customColors.add(key as keyof ButtonGroupColors);
});
this.applyStyles();
}
public async init(): Promise<void> {
this.render();
// 自动订阅语言变更
this.unsubscribeLocale = localeManager.subscribe(() => {
this.setLocales();
});
// 自动订阅主题变更
this.unsubscribeTheme = themeManager.subscribe((theme) => {
this.setTheme(theme);
});
}
public setLocales(): void {
this.render();
}
public addGroup(groupId: string, beforeGroupId?: string): void {
if (this.groups.some(g => g.id === groupId)) return;
const newGroup: ButtonGroup = { id: groupId, buttons: [] };
if (beforeGroupId) {
const index = this.groups.findIndex(g => g.id === beforeGroupId);
index !== -1 ? this.groups.splice(index, 0, newGroup) : this.groups.push(newGroup);
} else {
this.groups.push(newGroup);
}
}
public addButton(config: ButtonConfig): void {
const { groupId, parentId } = config;
const group = this.groups.find(g => g.id === groupId);
if (!group) return;
const button: OptButton = { ...config, children: config.children || [] };
if (parentId) {
const parentBtn = this.findButton(group.buttons, parentId);
if (parentBtn) {
if (!parentBtn.children) parentBtn.children = [];
parentBtn.children.push(button);
}
} else {
group.buttons.push(button);
}
}
private findButton(buttons: OptButton[], id: string): OptButton | undefined {
for (const btn of buttons) {
if (btn.id === id) return btn;
if (btn.children) {
const found = this.findButton(btn.children, id);
if (found) return found;
}
}
return undefined;
}
public render(): void {
this.container.innerHTML = '';
this.btnRefs.clear();
this.groups.forEach((group, index) => {
const groupElement = this.renderGroup(group, index, this.groups.length);
this.container.appendChild(groupElement);
});
}
private renderGroup(group: ButtonGroup, index: number, total: number): HTMLElement {
const groupEl = document.createElement('div');
groupEl.className = 'bim-btn-group-section';
if (index < total - 1) {
groupEl.classList.add('has-divider');
}
group.buttons.forEach(button => {
if (this.isVisible(button.id)) {
const btnWrapper = this.renderButton(button);
groupEl.appendChild(btnWrapper);
}
});
return groupEl;
}
private renderButton(button: OptButton): HTMLElement {
const wrapper = document.createElement('div');
wrapper.className = 'opt-btn-wrapper';
const btnEl = document.createElement('div');
btnEl.className = 'opt-btn';
// 初始化时根据 button 自身的属性同步 active 状态
if (button.isActive) {
this.activeBtnIds.add(button.id);
}
// 按钮优先使用自己的 align否则使用全局配置默认为 vertical
const align = button.align || this.options.align || 'vertical';
if (align === 'horizontal') {
btnEl.classList.add('align-horizontal');
} else {
btnEl.classList.add('align-vertical');
}
if (this.activeBtnIds.has(button.id)) btnEl.classList.add('active');
if (button.disabled) btnEl.classList.add('disabled');
// 判断是否显示 label
const hasLabel = this.options.showLabel && button.label;
if (!hasLabel) {
btnEl.classList.add('no-label');
// 当不显示 label 时,添加 title 属性作为 tooltip
if (button.label) {
btnEl.title = t(button.label);
}
}
// 应用按钮的自定义样式
const iconSize = button.iconSize || 32;
const minWidth = button.minWidth || 50;
btnEl.style.minWidth = `${minWidth}px`;
const icon = document.createElement('div');
icon.className = 'opt-btn-icon';
icon.style.width = `${iconSize}px`;
icon.style.height = `${iconSize}px`;
icon.innerHTML = this.getIcon(button.icon);
btnEl.appendChild(icon);
// 创建文字和箭头的容器,确保它们始终在一起(无论主轴是横是竖)
const textWrapper = document.createElement('div');
textWrapper.className = 'opt-btn-text-wrapper';
if (this.options.showLabel && button.label) {
const label = document.createElement('span');
label.className = 'opt-btn-label';
label.textContent = t(button.label);
textWrapper.appendChild(label);
}
if (button.children && button.children.length > 0) {
const arrow = document.createElement('span');
arrow.className = 'opt-btn-arrow';
arrow.textContent = '▼';
textWrapper.appendChild(arrow);
}
// 只有当有内容时才添加 wrapper
if (textWrapper.hasChildNodes()) {
btnEl.appendChild(textWrapper);
}
btnEl.addEventListener('click', () => this.handleClick(button));
btnEl.addEventListener('mouseenter', () => this.handleMouseEnter(button, btnEl));
btnEl.addEventListener('mouseleave', () => this.handleMouseLeave());
this.btnRefs.set(button.id, btnEl);
wrapper.appendChild(btnEl);
return wrapper;
}
/**
* 设置按钮的激活状态
* @param id 按钮 ID
* @param active 可选,如果不传则切换(toggle)当前状态
*/
public setBtnActive(id: string, active?: boolean): void {
const button = this.findButtonById(id);
if (!button) return;
// 确定最终状态
const newState = active !== undefined ? active : !this.activeBtnIds.has(id);
if (newState) {
this.activeBtnIds.add(id);
} else {
this.activeBtnIds.delete(id);
}
// 同步对象状态并更新 DOM
button.isActive = newState;
this.updateButtonState(id);
}
private handleClick(button: OptButton): void {
if (button.disabled) return;
if (!button.children || button.children.length === 0) {
if (button.keepActive) {
// 1) 先切换自身激活状态onClick 里通常会根据 isActive 决定“打开/关闭”逻辑)
const wasActive = this.activeBtnIds.has(button.id);
const newState = !wasActive;
this.setBtnActive(button.id, newState);
// 2) 互斥逻辑:仅在“本次切换为激活”时触发
// - 一级按钮:同 groupId 下其它一级按钮互斥
// - 二级按钮:同 groupId + 同 parentId 下其它二级按钮互斥
// - 被关闭的按钮需要触发 onClick用于执行关闭逻辑
if (newState && button.exclusive && button.groupId) {
this.deactivateExclusiveSiblings(button);
}
}
this.closeDropdown();
if (button.onClick) button.onClick(button);
}
}
/**
* 互斥关闭同范围内的其它已激活按钮,并触发它们的 onClick
* @param button 当前被激活的按钮
*/
private deactivateExclusiveSiblings(button: OptButton): void {
const group = this.groups.find(g => g.id === button.groupId);
if (!group) return;
// 二级按钮:同 groupId + 同 parentId
if (button.parentId) {
const parent = this.findButton(group.buttons, button.parentId);
const siblings = parent?.children || [];
for (const sib of siblings) {
if (!sib) continue;
if (sib.id === button.id) continue;
if (sib.parentId !== button.parentId) continue;
if (sib.groupId !== button.groupId) continue;
if (this.activeBtnIds.has(sib.id)) {
this.setBtnActive(sib.id, false);
// 触发被关闭按钮的 onClick此时 sib.isActive 已经同步为 false
if (sib.onClick) sib.onClick(sib);
}
}
return;
}
// 一级按钮:同 groupId 下其它一级按钮(不包含二级)
for (const sib of group.buttons) {
if (sib.id === button.id) continue;
if (sib.groupId !== button.groupId) continue;
if (sib.parentId) continue; // 只处理一级按钮
if (this.activeBtnIds.has(sib.id)) {
this.setBtnActive(sib.id, false);
if (sib.onClick) sib.onClick(sib);
}
}
}
private handleMouseEnter(button: OptButton, btnEl: HTMLElement): void {
if (this.hoverTimeout) clearTimeout(this.hoverTimeout);
if (button.children && button.children.length > 0) {
this.showDropdown(button, btnEl);
} else {
this.closeDropdown();
}
}
private handleMouseLeave(): void {
this.hoverTimeout = window.setTimeout(() => this.closeDropdown(), 200);
}
private showDropdown(button: OptButton, btnEl: HTMLElement): void {
this.closeDropdown();
if (!button.children) return;
const dropdown = document.createElement('div');
dropdown.className = 'opt-btn-dropdown';
if (this.options.backgroundColor) dropdown.style.setProperty('--bim-toolbar-bg', this.options.backgroundColor);
// 将主题CSS变量复制到dropdown元素上因为dropdown被添加到body无法继承容器的CSS变量
const dropdownStyle = dropdown.style;
if (this.options.iconColor) dropdownStyle.setProperty('--bim-icon-color', this.options.iconColor);
if (this.options.iconActiveColor) dropdownStyle.setProperty('--bim-icon-active-color', this.options.iconActiveColor);
if (this.options.textColor) dropdownStyle.setProperty('--bim-btn-text-color', this.options.textColor);
if (this.options.textActiveColor) dropdownStyle.setProperty('--bim-btn-text-active-color', this.options.textActiveColor);
if (this.options.btnBackgroundColor) dropdownStyle.setProperty('--bim-btn-bg', this.options.btnBackgroundColor);
if (this.options.btnHoverColor) dropdownStyle.setProperty('--bim-btn-hover-bg', this.options.btnHoverColor);
if (this.options.btnActiveColor) dropdownStyle.setProperty('--bim-btn-active-bg', this.options.btnActiveColor);
// 获取按钮的位置信息
const btnRect = btnEl.getBoundingClientRect();
const expand = this.options.expand || 'down';
// 根据主按钮组的方向设置下拉菜单的布局方向
if (this.options.direction === 'row') {
dropdown.style.flexDirection = 'column'; // 横向按钮组,菜单纵向排列
} else {
dropdown.style.flexDirection = 'row'; // 纵向按钮组,菜单横向排列
}
// 先添加到 DOM 以便计算尺寸
document.body.appendChild(dropdown);
// 添加事件拦截
this.setupEventInterception(dropdown);
// 添加菜单项
button.children.forEach(subBtn => {
if (this.isVisible(subBtn.id)) {
const item = this.renderDropdownItem(subBtn);
dropdown.appendChild(item);
}
});
// 获取下拉菜单的实际尺寸
const dropdownRect = dropdown.getBoundingClientRect();
if (expand === 'up') {
// 向上展开,与按钮水平居中对齐
dropdown.style.bottom = (window.innerHeight - btnRect.top + 8) + 'px';
dropdown.style.left = (btnRect.left + (btnRect.width - dropdownRect.width) / 2) + 'px';
} else if (expand === 'down') {
// 向下展开,与按钮水平居中对齐
dropdown.style.top = (btnRect.bottom + 8) + 'px';
dropdown.style.left = (btnRect.left + (btnRect.width - dropdownRect.width) / 2) + 'px';
} else if (expand === 'right') {
// 向右展开,与按钮垂直居中对齐
dropdown.style.top = (btnRect.top + (btnRect.height - dropdownRect.height) / 2) + 'px';
dropdown.style.left = (btnRect.right + 8) + 'px';
} else if (expand === 'left') {
// 向左展开,与按钮垂直居中对齐
dropdown.style.top = (btnRect.top + (btnRect.height - dropdownRect.height) / 2) + 'px';
dropdown.style.right = (window.innerWidth - btnRect.left + 8) + 'px';
}
dropdown.addEventListener('mouseenter', () => { if (this.hoverTimeout) clearTimeout(this.hoverTimeout); });
dropdown.addEventListener('mouseleave', () => this.handleMouseLeave());
this.dropdownElement = dropdown;
}
private renderDropdownItem(button: OptButton): HTMLElement {
const item = document.createElement('div');
item.className = 'opt-btn-dropdown-item';
// 应用按钮的 align 设置,默认为 horizontal图标在左
const align = button.align || 'horizontal';
if (align === 'horizontal') {
item.classList.add('align-horizontal');
} else {
item.classList.add('align-vertical');
}
// 二级菜单项的 active 状态渲染(修复 keepActive 在二级按钮“看起来不生效”的问题)
// 说明:
// - keepActive 的状态会记录在 activeBtnIds / button.isActive 上
// - 下拉菜单每次打开都会重新渲染,因此必须在这里同步一次 active 样式
if (this.activeBtnIds.has(button.id) || button.isActive) {
item.classList.add('active');
}
// 应用按钮的自定义样式
const iconSize = button.iconSize || 32; // 二级菜单默认图标更小
const minWidth = button.minWidth; // 不设置默认值,让下拉菜单项保持紧凑
if (minWidth) {
item.style.minWidth = `${minWidth}px`;
}
const icon = document.createElement('div');
icon.className = 'opt-btn-icon';
icon.style.width = `${iconSize}px`;
icon.style.height = `${iconSize}px`;
icon.innerHTML = this.getIcon(button.icon);
item.appendChild(icon);
// 只有在 showLabel 为 true 时才显示 label
if (this.options.showLabel && button.label) {
const label = document.createElement('span');
label.className = 'opt-btn-dropdown-label';
label.textContent = t(button.label);
item.appendChild(label);
} else if (button.label) {
// 当不显示 label 时,添加 title 属性作为 tooltip
item.title = t(button.label);
}
item.addEventListener('click', (e) => { e.stopPropagation(); this.handleClick(button); });
return item;
}
private closeDropdown(): void {
if (this.dropdownElement) {
this.dropdownElement.remove();
this.dropdownElement = null;
}
this.btnRefs.forEach(btnEl => {
const arrow = btnEl.querySelector('.opt-btn-arrow');
if (arrow) arrow.classList.remove('rotated');
});
}
private updateButtonState(buttonId: string): void {
const btnEl = this.btnRefs.get(buttonId);
if (btnEl) {
if (this.activeBtnIds.has(buttonId)) {
btnEl.classList.add('active');
} else {
btnEl.classList.remove('active');
}
}
}
private getIcon(icon?: string): string { return icon || this.DEFAULT_ICON; }
public updateButtonVisibility(id: string, visible: boolean): void {
if (!this.options.visibility) this.options.visibility = {};
this.options.visibility[id] = visible;
this.render();
}
public setShowLabel(show: boolean): void {
this.options.showLabel = show;
this.updateLabelsVisibility();
}
private updateLabelsVisibility(): void {
this.btnRefs.forEach((btnEl, buttonId) => {
// 查找按钮配置
const button = this.findButtonById(buttonId);
if (!button) return;
const hasLabel = this.options.showLabel && button.label;
// 更新 no-label 类和 title 属性
if (hasLabel) {
btnEl.classList.remove('no-label');
// 显示标签时,移除 title避免重复显示
btnEl.removeAttribute('title');
} else {
btnEl.classList.add('no-label');
// 隐藏标签时,添加 title 作为 tooltip
if (button.label) {
btnEl.title = t(button.label);
}
}
});
}
private findButtonById(id: string): OptButton | undefined {
for (const group of this.groups) {
const found = this.findButton(group.buttons, id);
if (found) return found;
}
return undefined;
}
public setBackgroundColor(color: string): void { this.setColors({ backgroundColor: color }); }
private isVisible(id: string): boolean { return this.options.visibility?.[id] !== false; }
public destroy(): void {
if (this.unsubscribeLocale) {
this.unsubscribeLocale();
this.unsubscribeLocale = null;
}
if (this.unsubscribeTheme) {
this.unsubscribeTheme();
this.unsubscribeTheme = null;
}
this.closeDropdown();
this.container.innerHTML = '';
this.btnRefs.clear();
}
}

View File

@@ -0,0 +1,100 @@
export type ButtonType = 'button' | 'menu';
/** 按钮配置 */
export interface ButtonConfig {
id: string;
type: ButtonType;
label: string;
icon?: string;
keepActive?: boolean;
/**
* 是否互斥(开关互斥)
*
* 行为说明:
* - 当按钮从“未激活”切换到“激活”时,如果该按钮开启了 exclusive
* 会自动关闭同互斥范围内的其它已激活按钮,并触发它们的 onClick用于执行关闭逻辑
* - 一级按钮:互斥范围 = 同 groupId 下的一级按钮
* - 二级按钮:互斥范围 = 同 groupId 且同 parentId 下的二级按钮
*
* 注意:该能力通常与 keepActive 搭配使用。
*/
exclusive?: boolean;
isActive?:boolean;
disabled?: boolean;
onClick?: (button: OptButton) => void;
children?: ButtonConfig[];
groupId?: string;
parentId?: string;
/** 按钮内部图标文字排列 (默认 vertical即图标在上) */
align?: ButtonAlign;
/** 图标大小 (正方形,单位 px默认 32) */
iconSize?: number;
/** 按钮最小宽度 (单位 px默认 50) */
minWidth?: number;
}
export interface OptButton extends ButtonConfig {
children?: OptButton[];
}
export interface ButtonGroup {
id: string;
buttons: OptButton[];
}
export interface ButtonGroupColors {
backgroundColor?: string;
btnBackgroundColor?: string;
btnHoverColor?: string;
btnActiveColor?: string;
iconColor?: string;
iconActiveColor?: string;
textColor?: string;
textActiveColor?: string;
}
// --- 新增布局类型 ---
/** 弹窗/按钮组位置 */
export type GroupPosition =
| 'center'
| 'top-left' | 'top-center' | 'top-right'
| 'left-center' | 'right-center'
| 'bottom-left' | 'bottom-center' | 'bottom-right'
| { x: number; y: number }
| 'static'; // static 表示不绝对定位,随文档流
/** 按钮组排列方向 (Flex-direction) */
export type GroupDirection = 'row' | 'column';
/** 按钮内部文字图标排列 */
export type ButtonAlign = 'vertical' /* 图标在上 */ | 'horizontal' /* 图标在左 */;
/** 二级菜单展开方向 */
export type ExpandDirection = 'up' | 'down' | 'left' | 'right';
export interface ButtonGroupOptions extends ButtonGroupColors {
container: HTMLElement | string;
/** 屏幕位置 (如 top-left) */
position?: GroupPosition;
/** 按钮组排列方向 (默认 row) */
direction?: GroupDirection;
/** 按钮内部图标文字排列 (默认 vertical) */
align?: ButtonAlign;
/** 菜单展开方向 */
expand?: ExpandDirection;
showLabel?: boolean;
visibility?: Record<string, boolean>;
className?: string;
}
export interface ClickPayload {
button: OptButton;
action: 'activate' | 'deactivate' | 'trigger';
isActive?: boolean;
}

View File

@@ -0,0 +1,96 @@
import type { ButtonGroupColors, ButtonConfig } from '../components/button-group/index.type';
import { Toolbar } from '../components/button-group/toolbar';
import type { ThemeConfig } from '../themes/types';
import { BimComponent } from '../core/component';
import type { BimEngine } from '../bim-engine';
/**
* 底部工具栏管理器 (ToolbarManager)
* 仅负责管理底部工具栏实例。
*/
export class ToolbarManager extends BimComponent {
private toolbar: Toolbar | null = null;
private toolbarContainer: HTMLElement | null = null;
private container: HTMLElement;
constructor(engine: BimEngine, container: HTMLElement) {
super(engine);
this.container = container;
this.init();
}
private init() {
// 创建底部工具栏专用容器
this.toolbarContainer = document.createElement('div');
this.toolbarContainer.id = 'opt-btn-groups';
this.toolbarContainer.className = 'bim-engine-opt-btn-container is-bottom-toolbar';
this.container.appendChild(this.toolbarContainer);
this.toolbar = new Toolbar({
container: this.toolbarContainer,
showLabel: true,
direction: 'row',
position: 'bottom-center', // 底部居中
align: 'vertical', // 图标在上
expand: 'up' // 向上展开
});
// 注入 engine 到 Toolbar
// @ts-ignore - Toolbar 还没更新类型,暂时忽略
this.toolbar.setEngine(this.engine);
this.toolbar.init();
}
public updateTheme(theme: ThemeConfig) {
this.toolbar?.setTheme(theme);
}
public refresh() {
this.toolbar?.render();
}
public destroy() {
this.toolbar?.destroy();
this.toolbar = null;
}
// --- 转发 API ---
public addGroup(groupId: string, beforeGroupId?: string) { this.toolbar?.addGroup(groupId, beforeGroupId); this.toolbar?.render(); }
public addButton(config: ButtonConfig) { this.toolbar?.addButton(config); this.toolbar?.render(); }
public setButtonVisibility(id: string, v: boolean) { this.toolbar?.updateButtonVisibility(id, v); }
public setShowLabel(show: boolean) { this.toolbar?.setShowLabel(show); }
public setBtnActive(id: string, active?: boolean) { this.toolbar?.setBtnActive(id, active); }
public setVisible(visible: boolean) {
if (this.toolbarContainer) {
this.toolbarContainer.style.visibility = visible ? 'visible' : 'hidden';
}
}
public setBackgroundColor(color: string) { this.toolbar?.setBackgroundColor(color); }
public setColors(colors: ButtonGroupColors) { this.toolbar?.setColors(colors); }
/**
* 隐藏工具栏
*/
public hide(): void {
if (this.toolbarContainer) {
this.toolbarContainer.style.display = 'none';
}
}
/**
* 显示工具栏
*/
public show(): void {
if (this.toolbarContainer) {
this.toolbarContainer.style.display = '';
}
}
/**
* 获取工具栏容器
*/
public getContainer(): HTMLElement | null {
return this.toolbarContainer;
}
}

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 528 B

After

Width:  |  Height:  |  Size: 528 B

View File

@@ -1,4 +1,4 @@
# BIM Engine SDK - AI 协作文档
# iFlow Engine - AI 协作文档
> 本文档用于向 AI 助手传递项目信息,帮助 AI 更好地理解和维护本项目。**每次代码改动后,请务必更新本文档的相关部分。**
@@ -18,7 +18,7 @@
### 1.1 项目描述
**BIM Engine SDK** 是一个通用的 3D BIM 引擎 SDK 开发框架,旨在通过一次编码,同时支持 Vue 2、Vue 3、React 和纯 HTML 环境。
**iFlow Engine** 是一个通用的 3D BIM 引擎 SDK 开发框架,旨在通过一次编码,同时支持 Vue 2、Vue 3、React 和纯 HTML 环境。
### 1.2 技术栈
@@ -26,7 +26,7 @@
- **构建工具**: Vite (Library Mode)
- **类型生成**: vite-plugin-dts
- **CSS 注入**: vite-plugin-css-injected-by-js
- **3D 引擎**: 基于第三方 SDK (bim-engine-sdk.es.js)
- **3D 引擎**: 基于第三方 SDK (iflow-engine-base)
### 1.3 项目结构
@@ -59,8 +59,8 @@ engine/
```bash
npm run build
# 生成 dist/ 目录,包含:
# - bim-engine-sdk.es.js (ESM 格式)
# - bim-engine-sdk.umd.js (UMD 格式)
# - iflow-engine.es.js (ESM 格式)
# - iflow-engine.umd.js (UMD 格式)
# - index.d.ts (TypeScript 类型定义)
# - *.map (Source Map 文件)
```
@@ -101,8 +101,8 @@ npm run dev:all
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/bim-engine-sdk.es.js",
"require": "./dist/bim-engine-sdk.umd.js"
"import": "./dist/iflow-engine.es.js",
"require": "./dist/iflow-engine.umd.js"
}
}
```
@@ -489,14 +489,14 @@ interface IBimComponent {
**❌ 错误方式 - 尝试直接导入组件:**
```typescript
// 错误BimDialog 类未导出,会导致编译错误
import { BimDialog } from 'bim-engine-sdk';
// Error: Module 'bim-engine-sdk' has no exported member 'BimDialog'.
import { BimDialog } from 'iflow-engine';
// Error: Module 'iflow-engine' has no exported member 'BimDialog'.
```
**✅ 正确方式 - 通过 Manager 使用:**
```typescript
// 正确:通过 BimEngine 的 Manager 使用组件
import { BimEngine } from 'bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
const engine = new BimEngine('container', {
locale: 'zh-CN',

View File

@@ -1,4 +1,4 @@
# BIM Engine SDK
# iFlow Engine
> 一个功能强大的 BIM建筑信息模型引擎 SDK提供 3D 可视化、构件管理、测量工具、剖切功能和漫游控制等完整功能。支持 Vue 2、Vue 3、React 和原生 HTML 等多种前端框架。
@@ -21,14 +21,14 @@
## 📦 安装
```bash
npm install bim-engine-sdk
npm install iflow-engine
```
或使用 yarn/pnpm:
```bash
yarn add bim-engine-sdk
pnpm add bim-engine-sdk
yarn add iflow-engine
pnpm add iflow-engine
```
## 🚀 快速开始
@@ -42,7 +42,7 @@ pnpm add bim-engine-sdk
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { BimEngine } from 'bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
const containerRef = ref<HTMLElement>();
let bimEngine: BimEngine | null = null;
@@ -93,7 +93,7 @@ onUnmounted(() => {
```tsx
import { useEffect, useRef } from 'react';
import { BimEngine } from 'bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
function App() {
const containerRef = useRef<HTMLDivElement>(null);
@@ -150,10 +150,10 @@ export default App;
<div id="container"></div>
<!-- 使用 UMD 版本 -->
<script src="./node_modules/bim-engine-sdk/dist/bim-engine-sdk.umd.js"></script>
<script src="./node_modules/iflow-engine/dist/iflow-engine.umd.js"></script>
<script>
const container = document.getElementById('container');
const bimEngine = new BimEngineSdk.BimEngine(container, {
const bimEngine = new IflowEngine.BimEngine(container, {
locale: 'zh-CN',
theme: 'dark'
});
@@ -229,7 +229,7 @@ BIM Engine SDK 采用 **管理器模式 (Manager Pattern)** 作为核心架构,
## 📁 项目结构
```
bim-engine-sdk/
iflow-engine/
├── src/ # 源代码
│ ├── bim-engine.ts # 主引擎类
│ ├── index.ts # 入口文件
@@ -271,8 +271,8 @@ bim-engine-sdk/
│ │ └── icon-manager.ts # 图标管理器
│ └── assets/ # 静态资源
├── dist/ # 构建产物
│ ├── bim-engine-sdk.es.js # ESM 格式
│ ├── bim-engine-sdk.umd.js # UMD 格式
│ ├── iflow-engine.es.js # ESM 格式
│ ├── iflow-engine.umd.js # UMD 格式
│ └── index.d.ts # TypeScript 类型定义
├── demo/ # HTML Demo
├── demo-vue/ # Vue Demo
@@ -437,8 +437,8 @@ npm run dev:demo-vue
运行 `npm run build` 后,会在 `dist/` 目录生成:
- `bim-engine-sdk.es.js` - ESM 格式 (用于现代打包工具)
- `bim-engine-sdk.umd.js` - UMD 格式 (用于浏览器直接引入)
- `iflow-engine.es.js` - ESM 格式 (用于现代打包工具)
- `iflow-engine.umd.js` - UMD 格式 (用于浏览器直接引入)
- `index.d.ts` - TypeScript 类型定义
- `*.css` - 样式文件 (已内联注入到 JS 中)
@@ -446,14 +446,14 @@ npm run dev:demo-vue
```json
{
"main": "./dist/bim-engine-sdk.umd.js",
"module": "./dist/bim-engine-sdk.es.js",
"main": "./dist/iflow-engine.umd.js",
"module": "./dist/iflow-engine.es.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/bim-engine-sdk.es.js",
"require": "./dist/bim-engine-sdk.umd.js"
"import": "./dist/iflow-engine.es.js",
"require": "./dist/iflow-engine.umd.js"
}
}
}
@@ -544,7 +544,7 @@ ISC License
如有问题或建议,请通过以下方式联系:
- 提交 [Issue](https://github.com/your-repo/bim-engine-sdk/issues)
- 提交 [Issue](https://github.com/your-repo/iflow-engine/issues)
- 发送邮件至 your-email@example.com
---

View File

@@ -1,6 +1,6 @@
# BIM Engine SDK Vue3 Demo
# iFlow Engine Vue3 Demo
这是一个使用 Vue3 + TypeScript 的演示项目,用于验证 BIM Engine SDK 在 Vue 环境下的兼容性。
这是一个使用 Vue3 + TypeScript 的演示项目,用于验证 iFlow Engine 在 Vue 环境下的兼容性。
## 前置要求
@@ -22,8 +22,8 @@
或者手动复制:
```bash
mkdir -p public/lib
cp ../dist/bim-engine-sdk.umd.js public/lib/
cp ../dist/bim-engine-sdk.umd.js.map public/lib/
cp ../dist/iflow-engine.umd.js public/lib/
cp ../dist/iflow-engine.umd.js.map public/lib/
```
## 运行
@@ -61,7 +61,7 @@ demo-vue/
│ └── vite-env.d.ts # TypeScript 类型声明
├── public/
│ ├── lib/ # SDK 文件目录
│ │ └── bim-engine-sdk.umd.js
│ │ └── iflow-engine.umd.js
│ └── model/ # 3D 模型文件
│ └── gujianzhu.glb
├── index.html # HTML 入口

View File

@@ -4,9 +4,9 @@
<meta charset="UTF-8">
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BIM Engine SDK Vue3 Demo</title>
<title>iFlow Engine Vue3 Demo</title>
<!-- 从 public/lib 目录加载 SDK 文件 -->
<script src="/lib/bim-engine-sdk.umd.js"></script>
<script src="/lib/iflow-engine.umd.js"></script>
</head>
<body>
<div id="app"></div>

View File

@@ -1,13 +1,13 @@
{
"name": "bim-engine-demo-vue",
"name": "iflow-engine-demo-vue",
"version": "1.0.0",
"description": "BIM Engine SDK Vue3 Demo",
"description": "iFlow Engine SDK Vue3 Demo",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"copy-sdk": "mkdir -p public/lib && cp ../dist/bim-engine-sdk.umd.js public/lib/ && cp ../dist/bim-engine-sdk.umd.js.map public/lib/ 2>/dev/null || true"
"copy-sdk": "mkdir -p public/lib && cp ../dist/iflow-engine.umd.js public/lib/ && cp ../dist/iflow-engine.umd.js.map public/lib/ 2>/dev/null || true"
},
"dependencies": {
"vue": "^3.4.21"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
<div class="app-container">
<!-- 左侧控制面板 -->
<aside class="sidebar">
<h1>BIM SDK Demo (Vue3)</h1>
<h1>iFlow Engine Demo (Vue3)</h1>
<!-- 1. 语言设置 -->
<div class="control-group">
@@ -84,8 +84,8 @@ const engineStatusColor = ref('#666');
// 初始化引擎
onMounted(() => {
if (window.LyzBimEngineSDK) {
const Engine = window.LyzBimEngineSDK.BimEngine;
if (window.IflowEngine) {
const Engine = window.IflowEngine.BimEngine;
try {
if (appContainer.value) {
engine.value = new Engine(appContainer.value, { locale: 'zh-CN' });

View File

@@ -9,7 +9,7 @@ declare module '*.vue' {
// 声明全局 SDK 类型
declare global {
interface Window {
LyzBimEngineSDK: {
IflowEngine: {
BimEngine: any;
};
}

View File

@@ -1,6 +1,6 @@
# BIM Engine SDK Demo
# iFlow Engine Demo
这是一个独立的演示项目,展示如何使用 BIM Engine SDK
这是一个独立的演示项目,展示如何使用 iFlow Engine。
## 前置要求
@@ -22,7 +22,7 @@
或者手动复制:
```bash
mkdir -p lib
cp ../dist/bim-engine-sdk.umd.js lib/
cp ../dist/iflow-engine.umd.js lib/
```
## 运行
@@ -57,7 +57,7 @@ demo/
├── model/ # 3D 模型文件
│ └── gujianzhu.glb
├── lib/ # SDK 文件目录
│ └── bim-engine-sdk.umd.js
│ └── iflow-engine.umd.js
├── package.json # 项目配置
├── vite.config.js # Vite 配置
└── README.md # 说明文档

View File

@@ -4,9 +4,9 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BIM Engine SDK Demo</title>
<title>iFlow Engine Demo</title>
<!-- 从本地 lib 目录加载 SDK 文件 -->
<script src="./lib/bim-engine-sdk.umd.js"></script>
<script src="./lib/iflow-engine.umd.js"></script>
<style>
* {
box-sizing: border-box;
@@ -195,8 +195,8 @@
// 初始化引擎
window.onload = () => {
if (window.LyzBimEngineSDK) {
const Engine = window.LyzBimEngineSDK.BimEngine;
if (window.IflowEngine) {
const Engine = window.IflowEngine.BimEngine;
try {
engine = new Engine('app', { locale: 'zh-CN' });
initEngine3D();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4808
demo/lib/iflow-engine.umd.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -7,8 +7,8 @@
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"copy-sdk": "mkdir -p lib && cp ../dist/bim-engine-sdk.umd.js lib/ && cp ../dist/bim-engine-sdk.umd.js.map lib/ 2>/dev/null || true",
"copy-draco": "mkdir -p static/js/draco && cp ../src/engine_base/draco/*.js ../src/engine_base/draco/*.wasm static/js/draco/ 2>/dev/null || true",
"copy-sdk": "mkdir -p lib && cp ../dist/iflow-engine.umd.js lib/ && cp ../dist/iflow-engine.umd.js.map lib/ 2>/dev/null || true",
"copy-draco": "mkdir -p static/js/draco && cp ../node_modules/iflow-engine-base/dist/draco/*.js ../node_modules/iflow-engine-base/dist/draco/*.wasm static/js/draco/ 2>/dev/null || true",
"copy-all": "npm run copy-sdk && npm run copy-draco"
},
"devDependencies": {

View File

@@ -4,9 +4,9 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BIM Engine Viewer</title>
<title>iFlow Engine Viewer</title>
<!-- 从本地 lib 目录加载 SDK 文件 -->
<script src="./lib/bim-engine-sdk.umd.js"></script>
<script src="./lib/iflow-engine.umd.js"></script>
<style>
* {
box-sizing: border-box;
@@ -148,12 +148,12 @@
async function initializeViewer() {
try {
// 检查 SDK 是否加载
if (!window.LyzBimEngineSDK) {
if (!window.IflowEngine) {
throw new Error('SDK not loaded');
}
// 创建引擎实例
const Engine = window.LyzBimEngineSDK.BimEngine;
const Engine = window.IflowEngine.BimEngine;
engine = new Engine('app', {
locale: 'zh-CN'
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

51
dist/index.d.ts vendored
View File

@@ -1328,6 +1328,44 @@ export declare interface ThemeConfig {
scrollbarThumb: ColorToken;
/** Scrollbar thumb on hover */
scrollbarThumbHover: ColorToken;
/** 浮动容器背景 (支持 rgba 实现毛玻璃效果) */
floatingBg: ColorToken;
/** 浮动容器边框 */
floatingBorder: ColorToken;
/** 浮动容器阴影 */
floatingShadow: ShadowToken;
/** 浮动按钮背景 */
floatingBtnBg: ColorToken;
/** 浮动按钮边框 */
floatingBtnBorder: ColorToken;
/** 浮动按钮阴影 */
floatingBtnShadow: ShadowToken;
/** 浮动按钮悬停背景 */
floatingBtnBgHover: ColorToken;
/** 浮动按钮悬停阴影 */
floatingBtnShadowHover: ShadowToken;
/** 浮动组件图标颜色 */
floatingIconColor: ColorToken;
/** 浮动组件图标悬停颜色 */
floatingIconColorHover: ColorToken;
/** 面板背景 (支持毛玻璃) */
panelBg: ColorToken;
/** 面板边框 */
panelBorder: ColorToken;
/** 面板 Header 背景 */
panelHeaderBg: ColorToken;
/** 面板圆角 */
panelRadius: string;
/** Tab 容器背景 */
tabBg: ColorToken;
/** Tab 项背景 */
tabItemBg: ColorToken;
/** Tab 项悬停背景 */
tabItemBgHover: ColorToken;
/** Tab 激活项背景 */
tabItemBgActive: ColorToken;
/** Tab 激活项文字颜色 */
tabItemTextActive: ColorToken;
/**
* Component-specific overrides
* Only define these when absolutely necessary
@@ -1351,19 +1389,6 @@ export declare interface ThemeConfig {
bgFocus?: ColorToken;
placeholder?: ColorToken;
};
/** Glass-pill button group specific colors */
glassPill?: {
sectionBg?: ColorToken;
sectionBorder?: ColorToken;
sectionShadow?: ShadowToken;
btnBg?: ColorToken;
btnBorder?: ColorToken;
btnShadow?: ShadowToken;
btnBgHover?: ColorToken;
btnShadowHover?: ShadowToken;
iconColor?: ColorToken;
iconColorHover?: ColorToken;
};
};
}

View File

@@ -1,6 +1,6 @@
# BIM Engine SDK 使用文档
# iFlow Engine 使用文档
BIM Engine SDK 是一个用于 3D BIM 模型展示的 JavaScript SDK支持原生 HTML、Vue 2/3 和 React 框架。
iFlow Engine 是一个用于 3D BIM 模型展示的 JavaScript SDK支持原生 HTML、Vue 2/3 和 React 框架。
## 目录
@@ -19,19 +19,19 @@ BIM Engine SDK 是一个用于 3D BIM 模型展示的 JavaScript SDK支持原
### NPM 安装(推荐)
```bash
npm install @fishdingding/bim-engine-sdk
npm install iflow-engine
```
### Yarn 安装
```bash
yarn add @fishdingding/bim-engine-sdk
yarn add iflow-engine
```
### PNPM 安装
```bash
pnpm add @fishdingding/bim-engine-sdk
pnpm add iflow-engine
```
### CDN / 本地文件引入
@@ -39,7 +39,7 @@ pnpm add @fishdingding/bim-engine-sdk
如果不使用包管理器,可以直接下载 JS 文件引入:
```html
<script src="./lib/bim-engine-sdk.umd.js"></script>
<script src="./lib/iflow-engine.umd.js"></script>
```
---
@@ -64,7 +64,7 @@ pnpm add @fishdingding/bim-engine-sdk
<div id="app"></div>
<script type="module">
import { BimEngine } from '@fishdingding/bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
// 1. 创建引擎实例
const engine = new BimEngine('app', {
@@ -101,7 +101,7 @@ pnpm add @fishdingding/bim-engine-sdk
<meta charset="UTF-8">
<title>BIM Engine Demo</title>
<!-- 引入 UMD 版本 -->
<script src="https://unpkg.com/@fishdingding/bim-engine-sdk/dist/bim-engine-sdk.umd.js"></script>
<script src="https://unpkg.com/iflow-engine/dist/iflow-engine.umd.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; }
@@ -200,7 +200,7 @@ window.onload = init;
### 1. 安装
```bash
npm install @fishdingding/bim-engine-sdk
npm install iflow-engine
```
### 2. 组件封装
@@ -213,7 +213,7 @@ npm install @fishdingding/bim-engine-sdk
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { BimEngine } from '@fishdingding/bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
// Props
const props = defineProps({
@@ -352,7 +352,7 @@ const stopMeasure = () => viewerRef.value?.deactivateMeasure();
### 1. 安装
```bash
npm install @fishdingding/bim-engine-sdk
npm install iflow-engine
```
### 2. 组件封装
@@ -364,7 +364,7 @@ npm install @fishdingding/bim-engine-sdk
</template>
<script>
import { BimEngine } from '@fishdingding/bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
export default {
name: 'BimViewer',
@@ -500,7 +500,7 @@ export default {
### 1. 安装
```bash
npm install @fishdingding/bim-engine-sdk
npm install iflow-engine
```
### 2. Hook 封装
@@ -508,7 +508,7 @@ npm install @fishdingding/bim-engine-sdk
```jsx
// hooks/useBimEngine.js
import { useEffect, useRef, useState, useCallback } from 'react';
import { BimEngine } from '@fishdingding/bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
export function useBimEngine(options = {}) {
const containerRef = useRef(null);
@@ -697,7 +697,7 @@ export default App;
#### 构造函数
```javascript
import { BimEngine } from '@fishdingding/bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
new BimEngine(container, options)
```
@@ -818,5 +818,5 @@ engine.on('modelLoaded', (data) => {
## 技术支持
- NPM 包地址https://www.npmjs.com/package/@fishdingding/bim-engine-sdk
- NPM 包地址https://www.npmjs.com/package/iflow-engine
- 如有问题,请联系技术支持

View File

@@ -20,7 +20,7 @@
- 采用延迟初始化模式,需要用户主动调用 `init()` 方法
### 1.3 第三方 SDK 依赖
- 依赖 `src/bim-engine-sdk.es.js` 中的 `createEngine` 函数
- 依赖 `iflow-engine-base` npm 包中的 `createEngine` 函数
- 通过依赖注入方式使用,不直接导入
---
@@ -396,7 +396,7 @@ public setTheme(theme: ThemeConfig): void {
### 9.1 基本使用(通过 EngineManager
```typescript
import { BimEngine } from 'bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
const engine = new BimEngine('container');
@@ -539,9 +539,9 @@ function updateEngineBackground(engine: any, color: number): void {
- 不抛出未捕获的异常
7. **第三方 SDK 依赖**:
- 依赖 `bim-engine-sdk.es.js` 文件
- 通过动态导入或全局变量访问
- 需要确保 SDK 文件已加载
- 依赖 `iflow-engine-base` npm 包
- 通过 npm 包导入
- 需要确保依赖已安装
---
@@ -579,7 +579,7 @@ interface ModelLoadOptions {
- `src/components/engine/index.ts` - 主组件类
- `src/components/engine/types.ts` - 类型定义
- `src/managers/engine-manager.ts` - 管理器类
- `src/bim-engine-sdk.es.js` - 第三方 SDK依赖
- `iflow-engine-base` - 第三方 SDKnpm 依赖)
### 12.2 依赖文件

View File

@@ -640,7 +640,7 @@ public setTheme(theme: ThemeConfig) {
### 9.1 基本使用(通过 Manager
```typescript
import { BimEngine } from 'bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
const engine = new BimEngine('container');

View File

@@ -921,7 +921,7 @@ label.textContent = t(button.label);
### 9.1 基本使用(通过 ButtonGroupManager
```typescript
import { BimEngine } from 'bim-engine-sdk';
import { BimEngine } from 'iflow-engine';
const engine = new BimEngine('container');

View File

@@ -116,7 +116,7 @@ new BimDescription({
**组件内部不进行翻译**。调用者应在传入 `label` 之前使用 `t()` 函数进行翻译。
```typescript
import { t } from 'bim-engine-sdk/services/locale';
import { t } from 'iflow-engine/services/locale';
new BimDescription({
// ...

473
package-lock.json generated
View File

@@ -1,14 +1,15 @@
{
"name": "bim-engine-sdk",
"version": "1.0.0",
"name": "@fishdingding/bim-engine-sdk",
"version": "1.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bim-engine-sdk",
"version": "1.0.0",
"license": "ISC",
"name": "@fishdingding/bim-engine-sdk",
"version": "1.0.3",
"license": "MIT",
"dependencies": {
"iflow-engine-base": "^1.0.1",
"three": "^0.182.0"
},
"devDependencies": {
@@ -69,6 +70,12 @@
"node": ">=6.9.0"
}
},
"node_modules/@dimforge/rapier3d-compat": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz",
"integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==",
"license": "Apache-2.0"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.12",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
@@ -1045,6 +1052,12 @@
"string-argv": "~0.3.1"
}
},
"node_modules/@tweenjs/tween.js": {
"version": "23.1.3",
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
"integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
"license": "MIT"
},
"node_modules/@types/argparse": {
"version": "1.0.38",
"resolved": "https://registry.npmmirror.com/@types/argparse/-/argparse-1.0.38.tgz",
@@ -1069,6 +1082,33 @@
"undici-types": "~7.16.0"
}
},
"node_modules/@types/stats.js": {
"version": "0.17.4",
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
"integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==",
"license": "MIT"
},
"node_modules/@types/three": {
"version": "0.181.0",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.181.0.tgz",
"integrity": "sha512-MLF1ks8yRM2k71D7RprFpDb9DOX0p22DbdPqT/uAkc6AtQXjxWCVDjCy23G9t1o8HcQPk7woD2NIyiaWcWPYmA==",
"license": "MIT",
"dependencies": {
"@dimforge/rapier3d-compat": "~0.12.0",
"@tweenjs/tween.js": "~23.1.3",
"@types/stats.js": "*",
"@types/webxr": "*",
"@webgpu/types": "*",
"fflate": "~0.8.2",
"meshoptimizer": "~0.22.0"
}
},
"node_modules/@types/webxr": {
"version": "0.5.24",
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz",
"integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==",
"license": "MIT"
},
"node_modules/@volar/language-core": {
"version": "2.4.26",
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.26.tgz",
@@ -1182,6 +1222,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/@webgpu/types": {
"version": "0.1.69",
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz",
"integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==",
"license": "BSD-3-Clause"
},
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
@@ -1262,6 +1308,23 @@
"sprintf-js": "~1.0.2"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1279,6 +1342,31 @@
"balanced-match": "^1.0.0"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/compare-versions": {
"version": "6.1.1",
"resolved": "https://registry.npmmirror.com/compare-versions/-/compare-versions-6.1.1.tgz",
@@ -1293,6 +1381,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
},
"node_modules/de-indent": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz",
@@ -1318,6 +1412,15 @@
}
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/diff": {
"version": "8.0.2",
"resolved": "https://registry.npmmirror.com/diff/-/diff-8.0.2.tgz",
@@ -1328,6 +1431,20 @@
"node": ">=0.3.1"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
@@ -1341,6 +1458,51 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": {
"version": "0.25.12",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.12.tgz",
@@ -1422,6 +1584,48 @@
}
}
},
"node_modules/fflate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
"license": "MIT"
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fs-extra": {
"version": "11.3.2",
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.2.tgz",
@@ -1456,12 +1660,60 @@
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -1479,11 +1731,37 @@
"node": ">=8"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -1502,6 +1780,32 @@
"he": "bin/he"
}
},
"node_modules/iflow-engine-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/iflow-engine-base/-/iflow-engine-base-1.0.1.tgz",
"integrity": "sha512-jrFn1bvisBA6jCn0+9gx9ZAkd1UHUoXo6bVkMsaM5tXIdABog/XYkJNADhdSrWzdB0u58M5ySZq3nqIpGq9LLQ==",
"license": "ISC",
"dependencies": {
"@types/three": "^0.181.0",
"axios": "^1.13.2",
"jszip": "^3.10.1",
"stats.js": "^0.17.0",
"three": "^0.181.2",
"three-bvh-csg": "^0.0.17"
}
},
"node_modules/iflow-engine-base/node_modules/three": {
"version": "0.181.2",
"resolved": "https://registry.npmjs.org/three/-/three-0.181.2.tgz",
"integrity": "sha512-k/CjiZ80bYss6Qs7/ex1TBlPD11whT9oKfT8oTGiHa34W4JRd1NiH/Tr1DbHWQ2/vMUypxksLnF2CfmlmM5XFQ==",
"license": "MIT"
},
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/import-lazy": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/import-lazy/-/import-lazy-4.0.0.tgz",
@@ -1512,6 +1816,12 @@
"node": ">=8"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/is-core-module": {
"version": "2.16.1",
"resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz",
@@ -1528,6 +1838,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"license": "MIT"
},
"node_modules/jju": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/jju/-/jju-1.4.0.tgz",
@@ -1555,6 +1871,18 @@
"graceful-fs": "^4.1.6"
}
},
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"license": "(MIT OR GPL-3.0-or-later)",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/kolorist": {
"version": "1.8.0",
"resolved": "https://registry.npmmirror.com/kolorist/-/kolorist-1.8.0.tgz",
@@ -1562,6 +1890,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/local-pkg": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.2.tgz",
@@ -1610,6 +1947,42 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/meshoptimizer": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.22.0.tgz",
"integrity": "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==",
"license": "MIT"
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "10.0.3",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-10.0.3.tgz",
@@ -1691,6 +2064,12 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/path-browserify": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
@@ -1773,6 +2152,18 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz",
@@ -1800,6 +2191,21 @@
],
"license": "MIT"
},
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz",
@@ -1873,6 +2279,12 @@
"fsevents": "~2.3.2"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz",
@@ -1889,6 +2301,12 @@
"node": ">=10"
}
},
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
"license": "MIT"
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@@ -1916,6 +2334,21 @@
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/stats.js": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz",
"integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==",
"license": "MIT"
},
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/string-argv": {
"version": "0.3.2",
"resolved": "https://registry.npmmirror.com/string-argv/-/string-argv-0.3.2.tgz",
@@ -1974,6 +2407,26 @@
"integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==",
"license": "MIT"
},
"node_modules/three-bvh-csg": {
"version": "0.0.17",
"resolved": "https://registry.npmjs.org/three-bvh-csg/-/three-bvh-csg-0.0.17.tgz",
"integrity": "sha512-iEkHDF8GRfGM6593Cuw8SnF1vfENCp46gIAtRzuL4nGXGWPcR1sbTBwM9ptDONb5twqlZp5WkAKya5aBKe2qcA==",
"license": "MIT",
"peerDependencies": {
"three": ">=0.151.0",
"three-mesh-bvh": ">=0.6.6"
}
},
"node_modules/three-mesh-bvh": {
"version": "0.9.7",
"resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.9.7.tgz",
"integrity": "sha512-EYSJbykeAjhVxwZjuUYq/kelIbqBoV9sbAgvZ+j1xCgZyNYSkr51WDJWS4WIfK2OX6YcjBGoTicX4RoOVQzx0g==",
"license": "MIT",
"peer": true,
"peerDependencies": {
"three": ">= 0.159.0"
}
},
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -2039,6 +2492,12 @@
"punycode": "^2.1.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/vite": {
"version": "7.2.6",
"resolved": "https://registry.npmmirror.com/vite/-/vite-7.2.6.tgz",

View File

@@ -1,15 +1,15 @@
{
"name": "@fishdingding/bim-engine-sdk",
"version": "1.0.3",
"description": "BIM Engine SDK for Vue2, Vue3, React and HTML",
"main": "./dist/bim-engine-sdk.umd.js",
"module": "./dist/bim-engine-sdk.es.js",
"name": "iflow-engine",
"version": "1.0.0",
"description": "iFlow Engine SDK for Vue2, Vue3, React and HTML",
"main": "./dist/iflow-engine.umd.js",
"module": "./dist/iflow-engine.es.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/bim-engine-sdk.es.js",
"require": "./dist/bim-engine-sdk.umd.js"
"import": "./dist/iflow-engine.es.js",
"require": "./dist/iflow-engine.umd.js"
}
},
"files": [
@@ -18,10 +18,10 @@
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"copy:demo": "mkdir -p demo/lib && cp dist/bim-engine-sdk.es.js dist/bim-engine-sdk.umd.js dist/bim-engine-sdk.umd.js.map demo/lib/",
"copy:demo-draco": "mkdir -p demo/static/js/draco && cp src/engine_base/draco/*.js src/engine_base/draco/*.wasm demo/static/js/draco/",
"copy:demo": "mkdir -p demo/lib && cp dist/iflow-engine.es.js dist/iflow-engine.umd.js dist/iflow-engine.umd.js.map demo/lib/",
"copy:demo-draco": "mkdir -p demo/static/js/draco && cp node_modules/iflow-engine-base/dist/draco/*.js node_modules/iflow-engine-base/dist/draco/*.wasm demo/static/js/draco/",
"copy:demo-all": "npm run copy:demo && npm run copy:demo-draco",
"copy:demo-vue": "mkdir -p demo-vue/public/lib && cp dist/bim-engine-sdk.es.js dist/bim-engine-sdk.umd.js dist/bim-engine-sdk.umd.js.map demo-vue/public/lib/",
"copy:demo-vue": "mkdir -p demo-vue/public/lib && cp dist/iflow-engine.es.js dist/iflow-engine.umd.js dist/iflow-engine.umd.js.map demo-vue/public/lib/",
"dev:demo": "npm run build && npm run copy:demo-all && cd demo && npm run dev",
"dev:demo-vue": "npm run build && npm run copy:demo-vue && cd demo-vue && npm run dev",
"dev:all": "npm run dev:demo & npm run dev:demo-vue",
@@ -59,6 +59,7 @@
"vite-plugin-dts": "^4.5.4"
},
"dependencies": {
"iflow-engine-base": "^1.0.1",
"three": "^0.182.0"
}
}

View File

@@ -1,10 +1,9 @@
/* Root Container */
.bim-collapse {
background-color: var(--bim-bg-color, #ffffff);
border: 1px solid var(--bim-border-color, #d9d9d9);
border-radius: 4px;
background-color: var(--bim-bg-elevated);
border: 1px solid var(--bim-border-default);
border-radius: 8px;
font-size: 14px;
color: var(--bim-text-color, rgba(0, 0, 0, 0.88));
color: var(--bim-text-primary);
}
.bim-collapse.is-ghost {
@@ -27,9 +26,8 @@
border-top: none;
}
/* Item */
.bim-collapse-item {
border-bottom: 1px solid var(--bim-border-color, #d9d9d9);
border-bottom: 1px solid var(--bim-border-subtle);
}
.bim-collapse-item:last-child {
@@ -37,23 +35,22 @@
}
.bim-collapse-item.is-disabled .bim-collapse-header {
color: var(--bim-disabled-color, rgba(0, 0, 0, 0.25));
color: var(--bim-text-disabled);
cursor: not-allowed;
}
/* Header */
.bim-collapse-header {
display: flex;
align-items: center;
padding: 12px 16px;
background-color: var(--bim-header-bg-color, rgba(0, 0, 0, 0.02));
background-color: var(--bim-component-bg);
cursor: pointer;
transition: all 0.3s;
transition: all 0.2s ease;
position: relative;
}
.bim-collapse-header:hover {
background-color: var(--bim-header-hover-bg-color, rgba(0, 0, 0, 0.05));
background-color: var(--bim-component-bg-hover);
}
/* Arrow Icon */
@@ -104,11 +101,10 @@
margin-left: auto;
}
/* Content */
.bim-collapse-content {
overflow: hidden;
background-color: var(--bim-content-bg-color, #ffffff);
border-top: 1px solid var(--bim-border-color, #d9d9d9);
background-color: var(--bim-bg-elevated);
border-top: 1px solid var(--bim-border-subtle);
transition: height 0.2s ease-in-out, opacity 0.2s ease-in-out;
}

View File

@@ -2,10 +2,8 @@
display: flex;
flex-direction: column;
width: 100%;
/* 默认字体大小和颜色 */
font-size: var(--bim-desc-font-size, 14px);
color: var(--bim-text-color, #333);
/* 严格移除容器本身的 padding */
font-size: 14px;
color: var(--bim-text-primary);
padding: 0;
}
@@ -23,31 +21,26 @@
}
.bim-description.is-bordered .bim-description-item {
border-bottom: 1px solid var(--bim-border-color, #eee);
border-bottom: 1px solid var(--bim-border-subtle);
}
/* 标签样式 */
.bim-description-label {
color: var(--bim-desc-label-color, var(--bim-label-color, #666));
color: var(--bim-text-secondary);
flex-shrink: 0;
/* 默认 padding: 0 4px */
padding: var(--bim-desc-label-padding, 4px 4px);
display: flex;
align-items: center; /* 垂直居中 */
}
/* 边框模式下的标签样式 */
.bim-description.is-bordered .bim-description-label {
border-right: 1px solid var(--bim-border-color, #eee);
}
/* 内容样式 */
.bim-description-value {
color: var(--bim-desc-value-color, var(--bim-value-color, #333));
flex: 1;
word-break: break-all;
/* 默认 padding: 0 4px */
padding: var(--bim-desc-value-padding, 4px 4px);
padding: 4px;
display: flex;
align-items: center;
}
.bim-description.is-bordered .bim-description-label {
border-right: 1px solid var(--bim-border-subtle);
}
.bim-description-value {
color: var(--bim-text-primary);
flex: 1;
word-break: break-all;
padding: 4px;
display: flex;
align-items: center;
}

View File

@@ -1,8 +1,8 @@
.bim-dialog {
position: absolute;
background-color: var(--bim-dialog-bg, var(--bim-bg-elevated));
border: 1px solid var(--bim-dialog-border-color, var(--bim-border-default));
border-radius: 6px;
background-color: var(--bim-bg-elevated);
border: 1px solid var(--bim-border-default);
border-radius: var(--bim-panel-radius, 12px);
box-shadow: var(--bim-shadow-lg);
display: flex;
flex-direction: column;
@@ -15,15 +15,15 @@
}
.bim-dialog-header {
height: 32px;
background-color: var(--bim-dialog-header-bg, var(--bim-bg-inset));
height: 40px;
background-color: var(--bim-bg-inset);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
padding: 0 12px;
cursor: default;
user-select: none;
border-bottom: 1px solid var(--bim-dialog-border-color, var(--bim-border-default));
border-bottom: 1px solid var(--bim-border-default);
flex-shrink: 0;
}

View File

@@ -3,8 +3,8 @@ import { IBimComponent } from '../../types/component';
import { themeManager } from '../../services/theme';
import type { EngineOptions, ModelLoadOptions } from './types';
import type { MeasureMode } from '../../types/measure';
// 导入第三方 SDK 的 createEngine 函数
import { createEngine as createEngineSDK } from '../../engine_base/bim-engine-sdk.es.js';
// 导入第三方 SDK 的 createEngine 函数(从 npm 包引入)
import { createEngine as createEngineSDK } from 'iflow-engine-base';
// 重新导出类型,方便外部引用
export type { EngineOptions, ModelLoadOptions };

View File

@@ -11,15 +11,13 @@
display: flex;
flex-direction: column;
box-sizing: border-box;
/* 面板内部颜色尽量复用 Dialog 的变量,保证整体一致 */
color: var(--bim-dialog-text-color, #ccc);
color: var(--bim-text-secondary);
}
.bim-measure-settings {
display: none;
box-sizing: border-box;
color: var(--bim-dialog-text-color, #ccc);
color: var(--bim-text-secondary);
}
.bim-measure-settings-title {
@@ -37,7 +35,7 @@
}
.bim-measure-settings-row .label {
color: var(--bim-measure-label-color, rgba(255, 255, 255, 0.70));
color: var(--bim-text-secondary);
font-size: 13px;
flex: 0 0 auto;
}
@@ -46,10 +44,10 @@
flex: 0 0 auto;
width: 120px;
height: 28px;
border-radius: 4px;
border: 1px solid var(--bim-measure-border, rgba(255, 255, 255, 0.12));
background: rgba(0, 0, 0, 0.12);
color: var(--bim-dialog-text-color, #ccc);
border-radius: 6px;
border: 1px solid var(--bim-border-default);
background: var(--bim-bg-inset);
color: var(--bim-text-primary);
padding: 0 8px;
box-sizing: border-box;
outline: none;
@@ -58,7 +56,7 @@
.bim-measure-settings-hint {
font-size: 12px;
line-height: 1.4;
color: var(--bim-measure-label-color, rgba(255, 255, 255, 0.70));
color: var(--bim-text-tertiary);
margin-top: -4px;
margin-bottom: 8px;
}
@@ -85,14 +83,14 @@
.bim-measure-settings-save {
border: none;
background: var(--bim-measure-primary, #0078d4);
color: #fff;
background: var(--bim-primary);
color: var(--bim-text-inverse);
}
.bim-measure-settings-cancel {
border: 1px solid var(--bim-measure-border, rgba(255, 255, 255, 0.12));
border: 1px solid var(--bim-border-default);
background: transparent;
color: var(--bim-dialog-text-color, #ccc);
color: var(--bim-text-secondary);
}
.bim-measure-settings-save:hover,
@@ -105,9 +103,8 @@
outline: none;
}
/* 保存按钮 hover 用主题 hover 色(轻微反馈,不改变布局) */
.bim-measure-settings-save:hover {
background: var(--bim-measure-primary-hover, #0063b1);
background: var(--bim-primary-hover);
}
/* 顶部:测量方式按钮区 */
@@ -127,24 +124,29 @@
width: 100%;
height: 42px;
border-radius: 6px;
border: 1px solid var(--bim-measure-border, rgba(255, 255, 255, 0.12));
background: var(--bim-measure-btn-bg, rgba(255, 255, 255, 0.06));
border: 1px solid var(--bim-border-default);
background: var(--bim-bg-inset);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.15s ease, border-color 0.15s ease;
transition: all 0.2s ease;
padding: 0;
box-sizing: border-box;
}
.bim-measure-tool-btn:hover {
background: var(--bim-measure-btn-hover-bg, rgba(255, 255, 255, 0.10));
background: var(--bim-component-bg-hover);
border-color: var(--bim-border-strong);
}
.bim-measure-tool-btn.is-active {
border-color: var(--bim-measure-active-border, rgba(255, 255, 255, 0.30));
background: var(--bim-measure-btn-active-bg, rgba(255, 255, 255, 0.14));
border-color: var(--bim-primary);
background: var(--bim-primary-subtle);
}
.bim-measure-tool-btn.is-active .bim-measure-tool-icon {
color: var(--bim-primary);
}
.bim-measure-tool-icon {
@@ -153,7 +155,7 @@
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--bim-measure-icon-color, #ddd);
color: var(--bim-icon-default);
}
.bim-measure-tool-icon svg {
@@ -170,16 +172,15 @@
}
.bim-measure-toggle-btn {
/* 你要求:更小,并带文字提示 */
height: 22px;
border-radius: 4px;
border: 1px solid var(--bim-measure-border, rgba(255, 255, 255, 0.12));
background: var(--bim-measure-btn-bg, rgba(255, 255, 255, 0.06));
border: 1px solid var(--bim-border-default);
background: var(--bim-bg-inset);
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
transition: background-color 0.15s ease;
transition: all 0.2s ease;
padding: 0 6px;
gap: 4px;
font-size: 12px;
@@ -187,18 +188,19 @@
}
.bim-measure-toggle-btn:hover {
background: var(--bim-measure-btn-hover-bg, rgba(255, 255, 255, 0.10));
background: var(--bim-component-bg-hover);
border-color: var(--bim-border-strong);
}
.bim-measure-toggle-text {
color: var(--bim-measure-label-color, rgba(255, 255, 255, 0.70));
color: var(--bim-text-secondary);
}
.bim-measure-toggle-icon svg {
width: 14px;
height: 14px;
fill: currentColor;
color: var(--bim-measure-icon-color, #ddd);
color: var(--bim-icon-default);
transition: transform 0.15s ease;
}
@@ -206,11 +208,10 @@
transform: rotate(180deg);
}
/* 中部:结果展示区 */
.bim-measure-result {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid var(--bim-measure-divider, rgba(255, 255, 255, 0.10));
border-top: 1px solid var(--bim-divider);
display: flex;
flex-direction: column;
gap: 10px;
@@ -225,12 +226,12 @@
}
.bim-measure-row .label {
color: var(--bim-measure-label-color, rgba(255, 255, 255, 0.70));
color: var(--bim-text-secondary);
min-width: 84px;
}
.bim-measure-row .value {
color: var(--bim-measure-value-color, rgba(255, 255, 255, 0.90));
color: var(--bim-text-primary);
flex: 1;
word-break: break-word;
}
@@ -241,12 +242,11 @@
}
.bim-measure-main-number.is-laser-text {
/* 激光测距:不使用黄色,回到默认文字颜色 */
color: var(--bim-measure-value-color, rgba(255, 255, 255, 0.90));
color: var(--bim-text-primary);
}
.bim-measure-main-unit {
color: var(--bim-measure-value-color, rgba(255, 255, 255, 0.90));
color: var(--bim-text-primary);
}
.bim-measure-xyz {
@@ -272,18 +272,37 @@
color: #1677ff !important;
}
/* 底部:操作区(删除全部 / 设置) */
.bim-measure-footer {
margin-top: 12px;
padding-top: 10px;
border-top: 1px solid var(--bim-measure-divider, rgba(255, 255, 255, 0.10));
border-top: 1px solid var(--bim-divider);
display: flex;
align-items: center;
/* 你要求:底部不要“占满”交互区域,按钮按自身尺寸布局 */
justify-content: flex-start;
gap: 10px;
}
.bim-measure-clear-btn {
background: transparent;
border: none;
color: var(--bim-danger);
cursor: pointer;
padding: 0;
font-size: 13px;
flex: 0 0 auto !important;
width: auto;
min-width: 0;
}
.bim-measure-clear-btn:hover,
.bim-measure-clear-btn:active,
.bim-measure-clear-btn:focus {
background: transparent;
border: none;
outline: none;
text-decoration: none;
}
.bim-measure-clear-btn {
background: transparent;
border: none;
@@ -339,7 +358,7 @@
width: 18px;
height: 18px;
fill: currentColor;
color: var(--bim-measure-icon-color, #ddd);
color: var(--bim-icon-default);
}

View File

@@ -146,24 +146,27 @@ export class MeasurePanel implements IBimComponent {
* @param theme 主题配置
*/
public setTheme(theme: ThemeConfig): void {
// 为了可读性:这里显式写出映射,不做过度抽象
const style = this.element.style;
// 这些变量不会强制覆盖外部Dialog已有变量只做兜底
style.setProperty('--bim-measure-border', theme.borderDefault ?? 'rgba(255, 255, 255, 0.12)');
style.setProperty('--bim-measure-divider', theme.borderDefault ?? 'rgba(255, 255, 255, 0.10)');
style.setProperty('--bim-measure-icon-color', theme.iconDefault ?? '#ddd');
style.setProperty('--bim-measure-label-color', theme.textSecondary ?? 'rgba(255, 255, 255, 0.70)');
style.setProperty('--bim-measure-value-color', theme.textPrimary ?? 'rgba(255, 255, 255, 0.90)');
style.setProperty('--bim-bg-inset', theme.bgInset ?? '#152232');
style.setProperty('--bim-bg-elevated', theme.bgElevated ?? '#1f2d3e');
style.setProperty('--bim-border-default', theme.borderDefault ?? '#334155');
style.setProperty('--bim-border-strong', theme.borderStrong ?? '#475569');
style.setProperty('--bim-divider', theme.divider ?? '#334155');
// “删除全部”颜色:截图中偏绿色,这里用 primary 做一个合理映射
style.setProperty('--bim-measure-danger', theme.primary ?? '#46d369');
// 设置面板“保存设置”按钮用主题色
style.setProperty('--bim-measure-primary', theme.primary ?? '#0078d4');
style.setProperty('--bim-measure-primary-hover', theme.primaryHover ?? '#0063b1');
style.setProperty('--bim-measure-btn-bg', theme.componentBg ?? 'rgba(255, 255, 255, 0.06)');
style.setProperty('--bim-measure-btn-hover-bg', theme.componentBgHover ?? 'rgba(255, 255, 255, 0.10)');
style.setProperty('--bim-measure-btn-active-bg', theme.componentBgActive ?? 'rgba(255, 255, 255, 0.14)');
style.setProperty('--bim-primary', theme.primary ?? '#3b82f6');
style.setProperty('--bim-primary-hover', theme.primaryHover ?? '#60a5fa');
style.setProperty('--bim-primary-subtle', theme.primarySubtle ?? 'rgba(59, 130, 246, 0.15)');
style.setProperty('--bim-danger', theme.danger ?? '#ef4444');
style.setProperty('--bim-text-primary', theme.textPrimary ?? '#ffffff');
style.setProperty('--bim-text-secondary', theme.textSecondary ?? '#94a3b8');
style.setProperty('--bim-text-tertiary', theme.textTertiary ?? '#64748b');
style.setProperty('--bim-text-inverse', theme.textInverse ?? '#152232');
style.setProperty('--bim-icon-default', theme.iconDefault ?? '#ffffff');
style.setProperty('--bim-component-bg-hover', theme.componentBgHover ?? 'rgba(248, 250, 252, 0.06)');
}
/**

View File

@@ -2,8 +2,9 @@
display: flex;
flex-direction: column;
background: var(--bim-bg-elevated);
border-radius: 4px;
padding: 4px 0;
border: 1px solid var(--bim-border-default);
border-radius: 8px;
padding: 6px;
margin: 0;
list-style: none;
min-width: 160px;
@@ -27,16 +28,18 @@
.bim-menu-item {
display: flex;
align-items: center;
padding: 6px 12px;
padding: 8px 12px;
cursor: pointer;
transition: background-color 0.2s;
transition: all 0.2s ease;
font-size: 13px;
position: relative;
color: var(--bim-text-primary);
border-radius: 6px;
}
.bim-menu-item:hover {
background-color: var(--bim-component-bg-hover);
background-color: var(--bim-floating-btn-bg);
transform: translateX(2px);
}
.bim-menu-item.disabled {

View File

@@ -10,12 +10,11 @@
box-sizing: border-box;
}
/* 第一行:隐藏、反向 */
.section-axis-row-1 {
display: flex;
gap: 8px;
padding-bottom: 8px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
border-bottom: 1px solid var(--bim-divider);
}
/* 第二行X、Y、Z */
@@ -25,7 +24,6 @@
padding-top: 8px;
}
/* 按钮基础样式 */
.section-axis-btn {
flex: 1;
display: flex;
@@ -34,35 +32,38 @@
justify-content: center;
gap: 4px;
padding: 8px;
background: var(--bim-section-axis-btn-bg, rgba(255, 255, 255, 0.06));
border: 1px solid transparent;
border-radius: 4px;
background: var(--bim-bg-inset);
border: 1px solid var(--bim-border-default);
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
transition: all 0.2s ease;
outline: none;
color: var(--bim-text-color, rgba(255, 255, 255, 0.90));
color: var(--bim-text-primary);
min-height: 48px;
}
.section-axis-btn:hover {
background: var(--bim-section-axis-btn-hover, rgba(255, 255, 255, 0.10));
background: var(--bim-component-bg-hover);
border-color: var(--bim-border-strong);
}
/* 激活状态 */
.section-axis-btn.active {
background: var(--bim-section-axis-btn-active, rgba(255, 255, 255, 0.14));
border-color: var(--bim-text-active-color, #fff);
color: var(--bim-text-active-color, #fff);
background: var(--bim-primary-subtle);
border-color: var(--bim-primary);
color: var(--bim-primary);
}
.section-axis-btn.active .section-axis-btn-icon {
color: var(--bim-primary);
}
/* 图标样式 */
.section-axis-btn-icon {
width: 24px;
height: 24px;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--bim-icon-color, #ccc);
color: var(--bim-icon-default);
}
.section-axis-btn-icon svg {

View File

@@ -69,13 +69,15 @@ export class SectionAxisPanel implements IBimComponent {
*/
public setTheme(theme: ThemeConfig): void {
const style = this.element.style;
style.setProperty('--bim-section-axis-btn-bg', theme.componentBg ?? 'rgba(255, 255, 255, 0.06)');
style.setProperty('--bim-section-axis-btn-hover', theme.componentBgHover ?? 'rgba(255, 255, 255, 0.10)');
style.setProperty('--bim-section-axis-btn-active', theme.componentBgActive ?? 'rgba(255, 255, 255, 0.14)');
style.setProperty('--bim-primary-color', theme.primary ?? '#1890ff');
style.setProperty('--bim-icon-color', theme.iconDefault ?? '#ccc');
style.setProperty('--bim-text-color', theme.textSecondary ?? 'rgba(255, 255, 255, 0.90)');
style.setProperty('--bim-text-active-color', theme.textPrimary ?? '#fff');
style.setProperty('--bim-bg-inset', theme.bgInset ?? '#152232');
style.setProperty('--bim-border-default', theme.borderDefault ?? '#334155');
style.setProperty('--bim-border-strong', theme.borderStrong ?? '#475569');
style.setProperty('--bim-divider', theme.divider ?? '#334155');
style.setProperty('--bim-primary', theme.primary ?? '#3b82f6');
style.setProperty('--bim-primary-subtle', theme.primarySubtle ?? 'rgba(59, 130, 246, 0.15)');
style.setProperty('--bim-icon-default', theme.iconDefault ?? '#ffffff');
style.setProperty('--bim-text-primary', theme.textPrimary ?? '#ffffff');
style.setProperty('--bim-component-bg-hover', theme.componentBgHover ?? 'rgba(248, 250, 252, 0.06)');
}
/**

View File

@@ -10,7 +10,7 @@
display: flex;
gap: 6px;
padding-bottom: 12px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
border-bottom: 1px solid var(--bim-divider);
}
.section-box-btn {
@@ -21,29 +21,34 @@
justify-content: center;
gap: 4px;
padding: 6px;
background: var(--bim-section-box-btn-bg);
border: 1px solid transparent;
border-radius: 4px;
background: var(--bim-bg-inset);
border: 1px solid var(--bim-border-default);
border-radius: 8px;
cursor: pointer;
color: var(--bim-text-color);
color: var(--bim-text-primary);
min-height: 44px;
transition: all 0.2s;
transition: all 0.2s ease;
}
.section-box-btn:hover {
background: var(--bim-section-box-btn-hover);
background: var(--bim-component-bg-hover);
border-color: var(--bim-border-strong);
}
.section-box-btn.active {
background: var(--bim-section-box-btn-active);
border-color: var(--bim-text-active-color);
color: var(--bim-text-active-color);
background: var(--bim-primary-subtle);
border-color: var(--bim-primary);
color: var(--bim-primary);
}
.section-box-btn.active .section-box-btn-icon {
color: var(--bim-primary);
}
.section-box-btn-icon {
width: 24px;
height: 24px;
color: var(--bim-icon-color);
color: var(--bim-icon-default);
}
.section-box-btn-icon svg {
@@ -81,7 +86,7 @@
.section-box-slider-label {
font-size: 13px;
font-weight: bold;
color: var(--bim-text-color);
color: var(--bim-text-primary);
min-width: 14px;
}
@@ -89,8 +94,7 @@
position: relative;
flex: 1;
height: 4px;
/* 轨道变细 */
background: rgba(255, 255, 255, 0.1);
background: var(--bim-border-default);
border-radius: 2px;
}
@@ -98,20 +102,18 @@
position: absolute;
top: 0;
height: 100%;
background: var(--bim-primary-color);
background: var(--bim-primary);
border-radius: 2px;
pointer-events: none;
/* 防止遮挡手柄点击 */
}
.section-box-slider-handle {
position: absolute;
top: 50%;
width: 14px;
/* 手柄变小 */
height: 14px;
background: #fff;
border: 2px solid var(--bim-primary-color);
background: var(--bim-bg-elevated);
border: 2px solid var(--bim-primary);
border-radius: 50%;
transform: translate(-50%, -50%);
cursor: grab;
@@ -122,12 +124,12 @@
.section-box-slider-handle:hover {
transform: translate(-50%, -50%) scale(1.2);
box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.2);
box-shadow: 0 0 0 4px var(--bim-primary-subtle);
}
.section-box-slider-handle.dragging {
cursor: grabbing;
transform: translate(-50%, -50%) scale(1.2);
background: var(--bim-primary-color);
background: var(--bim-primary);
}

View File

@@ -339,13 +339,16 @@ export class SectionBoxPanel implements IBimComponent {
public setTheme(theme: ThemeConfig): void {
if (!this.element) return;
const style = this.element.style;
style.setProperty('--bim-section-box-btn-bg', theme.componentBg ?? 'rgba(255, 255, 255, 0.06)');
style.setProperty('--bim-section-box-btn-hover', theme.componentBgHover ?? 'rgba(255, 255, 255, 0.10)');
style.setProperty('--bim-section-box-btn-active', theme.componentBgActive ?? 'rgba(255, 255, 255, 0.14)');
style.setProperty('--bim-primary-color', theme.primary ?? '#1890ff');
style.setProperty('--bim-icon-color', theme.iconDefault ?? '#ccc');
style.setProperty('--bim-text-color', theme.textSecondary ?? 'rgba(255, 255, 255, 0.90)');
style.setProperty('--bim-text-active-color', theme.textPrimary ?? '#fff');
style.setProperty('--bim-bg-inset', theme.bgInset ?? '#152232');
style.setProperty('--bim-bg-elevated', theme.bgElevated ?? '#1f2d3e');
style.setProperty('--bim-border-default', theme.borderDefault ?? '#334155');
style.setProperty('--bim-border-strong', theme.borderStrong ?? '#475569');
style.setProperty('--bim-divider', theme.divider ?? '#334155');
style.setProperty('--bim-primary', theme.primary ?? '#3b82f6');
style.setProperty('--bim-primary-subtle', theme.primarySubtle ?? 'rgba(59, 130, 246, 0.15)');
style.setProperty('--bim-icon-default', theme.iconDefault ?? '#ffffff');
style.setProperty('--bim-text-primary', theme.textPrimary ?? '#ffffff');
style.setProperty('--bim-component-bg-hover', theme.componentBgHover ?? 'rgba(248, 250, 252, 0.06)');
}
public destroy(): void {

View File

@@ -16,25 +16,35 @@
align-items: center;
justify-content: center;
gap: 4px;
padding: 8px;
border: 1px solid transparent;
background: var(--bim-section-btn-bg, rgba(255, 255, 255, 0.06));
border-radius: 4px;
padding: 10px;
border: 1px solid var(--bim-border-default);
background: var(--bim-bg-inset);
border-radius: 8px;
cursor: pointer;
transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
transition: all 0.2s ease;
min-width: 60px;
outline: none;
color: var(--bim-text-color, rgba(255, 255, 255, 0.90));
color: var(--bim-text-primary);
}
.section-plane-btn:hover {
background: var(--bim-section-btn-hover, rgba(255, 255, 255, 0.10));
background: var(--bim-component-bg-hover);
border-color: var(--bim-border-strong);
}
.section-plane-btn:active {
background: var(--bim-section-btn-active, rgba(255, 255, 255, 0.14));
border-color: var(--bim-text-active-color, #fff);
color: var(--bim-text-active-color, #fff);
background: var(--bim-primary-subtle);
border-color: var(--bim-primary);
}
.section-plane-btn.is-active {
background: var(--bim-primary-subtle);
border-color: var(--bim-primary);
color: var(--bim-primary);
}
.section-plane-btn.is-active .section-plane-btn-icon {
color: var(--bim-primary);
}
.section-plane-btn-icon {
@@ -43,7 +53,7 @@
display: flex;
align-items: center;
justify-content: center;
color: var(--bim-icon-color, #ccc);
color: var(--bim-icon-default);
}
.section-plane-btn-icon svg {

View File

@@ -55,13 +55,14 @@ export class SectionPlanePanel implements IBimComponent {
*/
public setTheme(theme: ThemeConfig): void {
const style = this.element.style;
style.setProperty('--bim-section-btn-bg', theme.componentBg ?? 'rgba(255, 255, 255, 0.06)');
style.setProperty('--bim-section-btn-hover', theme.componentBgHover ?? 'rgba(255, 255, 255, 0.10)');
style.setProperty('--bim-section-btn-active', theme.componentBgActive ?? 'rgba(255, 255, 255, 0.14)');
style.setProperty('--bim-primary-color', theme.primary ?? '#1890ff');
style.setProperty('--bim-icon-color', theme.iconDefault ?? '#ccc');
style.setProperty('--bim-text-color', theme.textSecondary ?? 'rgba(255, 255, 255, 0.90)');
style.setProperty('--bim-text-active-color', theme.textPrimary ?? '#fff');
style.setProperty('--bim-bg-inset', theme.bgInset ?? '#152232');
style.setProperty('--bim-border-default', theme.borderDefault ?? '#334155');
style.setProperty('--bim-border-strong', theme.borderStrong ?? '#475569');
style.setProperty('--bim-primary', theme.primary ?? '#3b82f6');
style.setProperty('--bim-primary-subtle', theme.primarySubtle ?? 'rgba(59, 130, 246, 0.15)');
style.setProperty('--bim-icon-default', theme.iconDefault ?? '#ffffff');
style.setProperty('--bim-text-primary', theme.textPrimary ?? '#ffffff');
style.setProperty('--bim-component-bg-hover', theme.componentBgHover ?? 'rgba(248, 250, 252, 0.06)');
}
/**

View File

@@ -4,14 +4,18 @@
width: 100%;
height: 100%;
background: transparent;
color: var(--bim-tab-text, #e6e6e6);
color: var(--bim-text-secondary);
}
.bim-tab__nav {
display: flex;
align-items: center;
justify-content: space-around;
background: transparent;
gap: 4px;
padding: 4px;
margin: 8px 12px;
background: var(--bim-bg-inset);
border-radius: 8px;
border: 1px solid var(--bim-border-subtle);
}
.bim-tab__item {
@@ -20,28 +24,26 @@
align-items: center;
justify-content: center;
gap: 6px;
/* 恢复原样式上下4px左右0 */
padding: 4px 0;
padding: 8px 12px;
border: none;
border-radius: 0; /* 恢复直角 */
border-radius: 6px;
background: transparent;
color: var(--bim-tab-text, #e6e6e6);
color: var(--bim-text-secondary);
cursor: pointer;
transition: all 0.2s ease;
font-size: 14px;
border-bottom: 4px solid transparent;
font-size: 13px;
font-weight: 500;
}
.bim-tab__item:hover {
color: var(--bim-tab-text, #e6e6e6);
background-color: var(--bim-tab-hover-bg, rgba(255, 255, 255, 0.05));
border-bottom-color: var(--bim-tab-hover-bg, rgba(255, 255, 255, 0.15));
color: var(--bim-text-primary);
background-color: var(--bim-component-bg-hover);
}
/* Active 状态 */
.bim-tab__item.is-active {
color: var(--bim-tab-text-active, #4da3ff);
border-bottom-color: var(--bim-tab-text-active, #4da3ff);
color: var(--bim-primary);
background-color: var(--bim-bg-elevated);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.bim-tab__item.is-disabled {

View File

@@ -1,19 +1,19 @@
/* 漫游控制面板 */
.walk-control-panel {
display: flex;
align-items: center;
gap: 20px;
padding: 8px 16px;
background: var(--bim-walk-control-bg, rgba(0, 0, 0, 0.8));
border-radius: 8px;
padding: 12px 20px;
background-color: var(--bim-bg-base, #152232);
border: 1px solid var(--bim-border-strong, #475569);
border-radius: 12px;
box-shadow: var(--bim-shadow-xl, 0 20px 40px rgba(0, 0, 0, 0.3));
user-select: none;
}
/* 分割线 */
.walk-divider {
width: 1px;
height: 40px;
background: var(--bim-divider-color, rgba(255, 255, 255, 0.2));
background: var(--bim-divider);
flex-shrink: 0;
}
@@ -29,21 +29,28 @@
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 2px solid transparent;
border-radius: 6px;
background: var(--bim-bg-inset);
border: 1px solid var(--bim-border-default);
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
color: var(--bim-icon-color, #ccc);
transition: all 0.2s ease;
color: var(--bim-icon-default);
padding: 8px;
}
.walk-icon-btn:hover {
background: var(--bim-walk-btn-hover, rgba(255, 255, 255, 0.15));
background: var(--bim-component-bg-hover);
border-color: var(--bim-border-strong);
}
.walk-icon-btn.active {
background: var(--bim-walk-btn-active, rgba(255, 255, 255, 0.3));
background: var(--bim-primary-subtle);
border-color: var(--bim-primary);
color: var(--bim-primary);
}
.walk-icon-btn.active svg {
fill: var(--bim-primary);
}
.walk-icon-btn svg {
@@ -67,7 +74,7 @@
}
.walk-speed-label {
color: var(--bim-text-color, #fff);
color: var(--bim-text-primary);
font-size: 14px;
white-space: nowrap;
}
@@ -76,25 +83,27 @@
display: flex;
align-items: center;
gap: 8px;
background: var(--bim-speed-group-bg, rgba(255, 255, 255, 0.1));
border-radius: 4px;
background: var(--bim-bg-inset);
border: 1px solid var(--bim-border-subtle);
border-radius: 6px;
padding: 4px;
}
.walk-speed-btn {
width: 32px;
height: 32px;
background: var(--bim-speed-btn-bg, rgba(255, 255, 255, 0.1));
border: none;
background: var(--bim-bg-elevated);
border: 1px solid var(--bim-border-subtle);
border-radius: 4px;
color: var(--bim-text-color, #fff);
color: var(--bim-text-primary);
font-size: 18px;
cursor: pointer;
transition: background 0.2s;
transition: all 0.2s ease;
}
.walk-speed-btn:hover {
background: var(--bim-speed-btn-hover, rgba(255, 255, 255, 0.2));
background: var(--bim-component-bg-hover);
border-color: var(--bim-border-strong);
}
.walk-speed-btn:disabled {
@@ -105,7 +114,7 @@
.walk-speed-display {
min-width: 40px;
text-align: center;
color: var(--bim-text-color, #fff);
color: var(--bim-text-primary);
font-size: 14px;
font-weight: bold;
}
@@ -130,7 +139,7 @@
}
.walk-checkbox-label {
color: var(--bim-text-color, #fff);
color: var(--bim-text-primary);
font-size: 14px;
white-space: nowrap;
}
@@ -147,41 +156,41 @@
}
.walk-select-label {
color: var(--bim-text-color, #fff);
color: var(--bim-text-primary);
font-size: 14px;
white-space: nowrap;
}
.walk-select {
padding: 6px 12px;
background: var(--bim-select-bg, rgba(255, 255, 255, 0.1));
border: 1px solid var(--bim-select-border, rgba(255, 255, 255, 0.2));
border-radius: 4px;
color: var(--bim-text-color, #fff);
background: var(--bim-bg-inset);
border: 1px solid var(--bim-border-default);
border-radius: 6px;
color: var(--bim-text-primary);
font-size: 14px;
cursor: pointer;
min-width: 120px;
}
.walk-select option {
background: var(--bim-select-option-bg, #333);
color: var(--bim-text-color, #fff);
background: var(--bim-bg-elevated);
color: var(--bim-text-primary);
}
/* 退出按钮 */
.walk-exit-btn {
padding: 10px 24px;
background: var(--bim-primary-color, #1890ff);
background: var(--bim-primary);
border: none;
border-radius: 6px;
color: #fff;
border-radius: 8px;
color: var(--bim-text-inverse);
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
transition: all 0.2s ease;
white-space: nowrap;
}
.walk-exit-btn:hover {
background: var(--bim-primary-hover, #40a9ff);
background: var(--bim-primary-hover);
transform: scale(1.02);
}

View File

@@ -434,20 +434,27 @@ export class WalkControlPanel implements IBimComponent {
public setTheme(theme: ThemeConfig): void {
if (!this.element) return;
const style = this.element.style;
style.setProperty('--bim-walk-control-bg', theme.bgElevated ?? 'rgba(0, 0, 0, 0.8)');
style.setProperty('--bim-walk-btn-hover', theme.componentBgHover ?? 'rgba(255, 255, 255, 0.15)');
style.setProperty('--bim-walk-btn-active', theme.componentBgActive ?? 'rgba(255, 255, 255, 0.3)');
style.setProperty('--bim-primary-color', theme.primary ?? '#1890ff');
style.setProperty('--bim-primary-hover', theme.primaryHover ?? '#40a9ff');
style.setProperty('--bim-icon-color', theme.iconDefault ?? '#ccc');
style.setProperty('--bim-text-color', theme.textPrimary ?? '#fff');
style.setProperty('--bim-divider-color', theme.borderDefault ?? 'rgba(255, 255, 255, 0.2)');
style.setProperty('--bim-speed-group-bg', theme.componentBgHover ?? 'rgba(255, 255, 255, 0.1)');
style.setProperty('--bim-speed-btn-bg', theme.componentBgHover ?? 'rgba(255, 255, 255, 0.1)');
style.setProperty('--bim-speed-btn-hover', theme.componentBgActive ?? 'rgba(255, 255, 255, 0.2)');
style.setProperty('--bim-select-bg', theme.componentBgHover ?? 'rgba(255, 255, 255, 0.1)');
style.setProperty('--bim-select-border', theme.borderDefault ?? 'rgba(255, 255, 255, 0.2)');
style.setProperty('--bim-select-option-bg', theme.bgElevated ?? '#333');
style.setProperty('--bim-bg-base', theme.bgBase ?? '#152232');
style.setProperty('--bim-bg-elevated', theme.bgElevated ?? '#1f2d3e');
style.setProperty('--bim-bg-inset', theme.bgInset ?? '#152232');
style.setProperty('--bim-border-default', theme.borderDefault ?? '#334155');
style.setProperty('--bim-border-strong', theme.borderStrong ?? '#475569');
style.setProperty('--bim-border-subtle', theme.borderSubtle ?? '#1e293b');
style.setProperty('--bim-divider', theme.divider ?? '#334155');
style.setProperty('--bim-shadow-xl', theme.shadowXl ?? '0 20px 40px rgba(0, 0, 0, 0.3)');
style.setProperty('--bim-primary', theme.primary ?? '#3b82f6');
style.setProperty('--bim-primary-hover', theme.primaryHover ?? '#60a5fa');
style.setProperty('--bim-primary-subtle', theme.primarySubtle ?? 'rgba(59, 130, 246, 0.15)');
style.setProperty('--bim-text-primary', theme.textPrimary ?? '#ffffff');
style.setProperty('--bim-text-inverse', theme.textInverse ?? '#152232');
style.setProperty('--bim-icon-default', theme.iconDefault ?? '#ffffff');
style.setProperty('--bim-component-bg-hover', theme.componentBgHover ?? 'rgba(248, 250, 252, 0.06)');
style.setProperty('--bim-component-bg-active', theme.componentBgActive ?? 'rgba(248, 250, 252, 0.1)');
}
public destroy(): void {

Some files were not shown because too many files have changed in this diff Show More