@groupviz/react 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/components/Canvas/ActionScene.d.ts +46 -0
- package/components/Canvas/Cayley3DScene.d.ts +35 -0
- package/components/Canvas/CayleyView.d.ts +36 -0
- package/components/Canvas/CosetStripScene.d.ts +41 -0
- package/components/Canvas/CycleView.d.ts +40 -0
- package/components/Canvas/HomomorphismScene.d.ts +24 -0
- package/components/Canvas/SceneWindow.d.ts +83 -0
- package/components/Canvas/SetView.d.ts +33 -0
- package/components/Canvas/SublatticeScene.d.ts +70 -0
- package/components/Canvas/SymmetryViewScene.d.ts +34 -0
- package/components/Canvas/TableView.d.ts +43 -0
- package/context/cayleyActions.d.ts +20 -0
- package/i18n/I18nContext.d.ts +11 -0
- package/i18n/translations.d.ts +5 -0
- package/i18n/useTranslation.d.ts +1 -0
- package/index.js +7674 -0
- package/index.js.map +1 -0
- package/package/react.d.ts +37 -0
- package/package.json +42 -0
- package/theme/ThemeContext.d.ts +13 -0
- package/theme/useTheme.d.ts +4 -0
- package/theme.css +186 -0
- package/utils/cayley3dControls.d.ts +18 -0
- package/utils/download.d.ts +9 -0
- package/utils/texify.d.ts +2 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rrCathy,LDK
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @groupviz/react
|
|
2
|
+
|
|
3
|
+
GroupViz 群论可视化的 **React 视图组件**。与 [@groupviz/core](../core) 配套:core 出数据,react 出图。
|
|
4
|
+
|
|
5
|
+
**包含**:10 个视图 Scene(`SetView` / `CycleView` / `CayleyView` / `TableView` / `CosetStripScene` /
|
|
6
|
+
`ActionScene` / `HomomorphismScene` / `SublatticeScene` / `Cayley3DScene` / `SymmetryViewScene`)、
|
|
7
|
+
窗口容器壳 `SceneWindow`、`I18nProvider`(内置中 / 英文语言包)、`theme.css`(深 / 浅色主题变量)。
|
|
8
|
+
|
|
9
|
+
**安装**(npm 自动解析 peer:react 19 / three / @react-three/fiber / @react-three/drei / katex)
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
npm i @groupviz/core @groupviz/react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**快速开始**
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { I18nProvider, SetView } from '@groupviz/react'
|
|
19
|
+
import '@groupviz/react/theme.css'
|
|
20
|
+
import { createGroupFromSymbol } from '@groupviz/core'
|
|
21
|
+
|
|
22
|
+
const group = createGroupFromSymbol('C_{6}')
|
|
23
|
+
|
|
24
|
+
export function App() {
|
|
25
|
+
return (
|
|
26
|
+
<I18nProvider>
|
|
27
|
+
<div style={{ width: 480, height: 360, background: '#0f1115' }}>
|
|
28
|
+
<SetView
|
|
29
|
+
group={group}
|
|
30
|
+
selectedElements={new Set()}
|
|
31
|
+
canvasTransform={{ x: 0, y: 0, scale: 1 }}
|
|
32
|
+
viewBoxSize={{ width: 480, height: 360 }}
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
</I18nProvider>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import '@groupviz/react/theme.css' // 主题样式(模块化工程可 import 到全局)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**交互约定**:Scene 是纯受控内核——标签显隐 / hover 气泡 / 选中高亮等由宿主通过 props
|
|
45
|
+
(`showLabels` / `onHover` / `onSelect`)注入;更多组合示例见仓库 `examples/host-minimal/`。
|
|
46
|
+
|
|
47
|
+
完整文档:[GroupViz 主仓库](https://github.com/rrCathy/GroupViz)(docs/VIEWS.md · docs/PRESENTATION.md)。
|
|
48
|
+
MIT License。
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Group, GroupActionArrow, GroupActionComputation, GroupActionKind, GroupElement, CanvasTransform } from '@groupviz/core';
|
|
2
|
+
import { type CustomArrowError } from '@groupviz/core';
|
|
3
|
+
export interface ActionSceneProps {
|
|
4
|
+
group: Group;
|
|
5
|
+
/** 作用来源;窗口范围 conjugation/regular/custom(sylow/coset 仅主画布壳会传) */
|
|
6
|
+
kind: GroupActionKind;
|
|
7
|
+
computation: GroupActionComputation | null;
|
|
8
|
+
/** custom 编辑模式(渲染 CustomActionEditor,不吃 canvasTransform) */
|
|
9
|
+
editing?: boolean;
|
|
10
|
+
/** 编辑模式 |X|(1..20) */
|
|
11
|
+
setSize?: number | null;
|
|
12
|
+
/** 编辑模式箭头列表 */
|
|
13
|
+
arrows?: GroupActionArrow[];
|
|
14
|
+
/** 编辑模式错误(画布内红字提示) */
|
|
15
|
+
error?: CustomArrowError | null;
|
|
16
|
+
onAddArrow?: (from: number, to: number, generatorId?: string | null) => void;
|
|
17
|
+
onBindArrow?: (from: number, to: number, generatorId: string) => void;
|
|
18
|
+
onRemoveArrow?: (from: number, generatorId?: string | null, to?: number) => void;
|
|
19
|
+
onReplaceGenArrows?: (generatorId: string | null, pairs: [number, number][]) => void;
|
|
20
|
+
/** 选中集合元素索引(OST 交互 + 底部 Stab box) */
|
|
21
|
+
selectedElement?: number | null;
|
|
22
|
+
onSelectedElementChange?: (x: number | null) => void;
|
|
23
|
+
/** 悬停群元素 id(金色箭头联动;主画布壳接 context) */
|
|
24
|
+
hoveredElement?: string | null;
|
|
25
|
+
onHoverElementChange?: (id: string | null) => void;
|
|
26
|
+
/** chips 群元素点击 → 主画布全局选中;窗口不传 */
|
|
27
|
+
onSetElementSelect?: (id: string) => void;
|
|
28
|
+
/** 节点常驻标签 + 顶部轨道 chips 区;缺省 true(主画布观感)。窗口传 false:
|
|
29
|
+
* 节点空圈 + chips 区隐藏 + conjugation/regular 节点悬停就地气泡 */
|
|
30
|
+
showLabels?: boolean;
|
|
31
|
+
/** 悬停就地气泡回调(窗口接 handleHover) */
|
|
32
|
+
onHover?: (el: GroupElement | null, anchor?: {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
} | null) => void;
|
|
36
|
+
/** 内容平移缩放(主画布壳接 canvasTransform,窗口接窗口 ct);编辑模式不吃 */
|
|
37
|
+
canvasTransform?: CanvasTransform;
|
|
38
|
+
/** 视口尺寸;fitVB 自适应时作为兜底 */
|
|
39
|
+
viewBoxSize?: {
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
};
|
|
43
|
+
/** sylow 作用的素数(banner 标题用);窗口不传 */
|
|
44
|
+
prime?: number | null;
|
|
45
|
+
}
|
|
46
|
+
export declare function ActionScene({ group, kind, computation, editing, setSize, arrows, error, onAddArrow, onBindArrow, onRemoveArrow, onReplaceGenArrows, selectedElement, onSelectedElementChange, hoveredElement, onHoverElementChange, onSetElementSelect, showLabels, onHover, canvasTransform, viewBoxSize, prime, }: ActionSceneProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Group, MultiplyType, Layout3D } from '@groupviz/core';
|
|
2
|
+
import type { CayleyActionParam } from '@groupviz/core';
|
|
3
|
+
export interface Cayley3DSceneProps {
|
|
4
|
+
/** 群;null → .view-empty 占位 */
|
|
5
|
+
group: Group | null;
|
|
6
|
+
/** 选中元素集合(调用方自持会话态) */
|
|
7
|
+
selectedElements: Set<string>;
|
|
8
|
+
/** 节点点击选中回调;缺省 no-op */
|
|
9
|
+
onSelectElement?: (id: string, additive: boolean) => void;
|
|
10
|
+
/** 作用边元素集合;缺省 = 群生成元(normalizeCayleyActions 归一化) */
|
|
11
|
+
actions?: CayleyActionParam[];
|
|
12
|
+
/** 边的乘法方向;缺省 'right' */
|
|
13
|
+
multiplyType?: MultiplyType;
|
|
14
|
+
/** 3D 布局形状;缺省 getDefaultLayout3D(group) */
|
|
15
|
+
layout3D?: Layout3D;
|
|
16
|
+
/** 节点球缩放 0.5–2.0;缺省 1 */
|
|
17
|
+
nodeScale?: number;
|
|
18
|
+
/** 自动旋转;缺省 false。prop 优先,未设置时内部 ▶ 按钮本地态兜底 */
|
|
19
|
+
autoRotate?: boolean;
|
|
20
|
+
/** 是否显示 hover/选中 Html 标签;缺省 true */
|
|
21
|
+
showLabels?: boolean;
|
|
22
|
+
/** 锁定相机交互(轨道拖拽/滚轮缩放/右键平移);保留点击选中与双击复位 */
|
|
23
|
+
locked?: boolean;
|
|
24
|
+
/** 子集高亮(元素 id → 颜色);context subsets 的同构映射 */
|
|
25
|
+
subsetHighlights?: {
|
|
26
|
+
elementIds: string[];
|
|
27
|
+
color: string;
|
|
28
|
+
}[];
|
|
29
|
+
/** 渲染主题(canvas 背景 / label 阴影)。缺省回落到 ThemeContext(无 Provider 时 'dark');
|
|
30
|
+
* 主应用壳不传即保持现状(读全局主题),包消费端显式传以与容器主题解耦 */
|
|
31
|
+
theme?: 'dark' | 'light';
|
|
32
|
+
}
|
|
33
|
+
/** 受控 3D 凯莱图(props 驱动;ViewWindow 与测试用)。空群渲染占位,非空渲染 R3F 场景。 */
|
|
34
|
+
export declare function Cayley3DScene(props: Cayley3DSceneProps): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
/** 主应用入口(context 组装壳):从全局 Provider 组装 Cayley3DScene 所需 props(保留原行为) */
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CanvasTransform, CayleyShape2D, Group, GroupElement, MultiplyType } from '@groupviz/core';
|
|
2
|
+
import type { CayleyActionParam } from '@groupviz/core';
|
|
3
|
+
export interface CayleyViewProps {
|
|
4
|
+
group: Group | null;
|
|
5
|
+
selectedElements: Set<string>;
|
|
6
|
+
canvasTransform: CanvasTransform;
|
|
7
|
+
viewBoxSize: {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
};
|
|
11
|
+
/** 缺省 getDefaultShape2D(group) */
|
|
12
|
+
shape2D?: CayleyShape2D;
|
|
13
|
+
/** 缺省 'right'(右乘 a·c) */
|
|
14
|
+
multiplyType?: MultiplyType;
|
|
15
|
+
/** 缺省 = 群生成元集合;条目缺省 enabled=true、color=COLOR_PALETTE 按序 */
|
|
16
|
+
actions?: CayleyActionParam[];
|
|
17
|
+
/** 缺省 28(与主视图非复合节点一致) */
|
|
18
|
+
nodeRadius?: number;
|
|
19
|
+
/** 缺省 true;>60 阶沿用主视图自适应规则(选中后仅选中节点显示标签)。嵌入小窗(ViewWindow)传 false 彻底不显示节点标签、读元素靠悬停就地气泡 */
|
|
20
|
+
showLabels?: boolean;
|
|
21
|
+
/** 缺省 false;true 时禁用节点拖拽(供 ViewWindow 锁定状态使用,点击选中仍保留) */
|
|
22
|
+
locked?: boolean;
|
|
23
|
+
onSelect?: (elId: string, additive: boolean) => void;
|
|
24
|
+
/**
|
|
25
|
+
* 悬停回调:第一个参数是元素,第二个是节点在 viewport 内的屏幕锚点
|
|
26
|
+
* (viewBox 坐标经 canvasTransform 映射,供上层渲染"就地气泡"tooltip)。
|
|
27
|
+
*/
|
|
28
|
+
onHover?: (el: GroupElement | null, anchor?: {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
} | null) => void;
|
|
32
|
+
/** 当前悬停元素 id;用于在该节点外圈绘制高亮环(让"悬停→信息"在视觉上立得住) */
|
|
33
|
+
hoveredElementId?: string | null;
|
|
34
|
+
noGroupText?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function CayleyView({ group, selectedElements, canvasTransform, viewBoxSize, shape2D: shapeProp, multiplyType: multiplyProp, actions: actionsProp, nodeRadius: nodeRadiusProp, showLabels: showLabelsProp, locked, onSelect, onHover, hoveredElementId, noGroupText, }: CayleyViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Group, GroupElement } from '@groupviz/core';
|
|
2
|
+
export interface CosetStripSceneProps {
|
|
3
|
+
group: Group | null;
|
|
4
|
+
selectedElements?: Set<string>;
|
|
5
|
+
canvasTransform?: {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
scale: number;
|
|
9
|
+
};
|
|
10
|
+
viewBoxSize: {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
14
|
+
/** 元素 → 陪集下标(与 SetView 同约定)。缺省空 Map 显示空态文案 */
|
|
15
|
+
cosetElementMap?: Map<string, number> | null;
|
|
16
|
+
/** 每条陪集的条带颜色 */
|
|
17
|
+
cosetColors?: string[];
|
|
18
|
+
/** 被高亮的陪集下标集合(点击选中元素 → 其所在陪集) */
|
|
19
|
+
cosetHighlightSet?: Set<number>;
|
|
20
|
+
/** 已保存子集(元素集合 + 颜色),命中元素描边用子集色 */
|
|
21
|
+
subsets?: Array<{
|
|
22
|
+
elementIds: string[];
|
|
23
|
+
color: string;
|
|
24
|
+
}>;
|
|
25
|
+
/** 节点常驻标签;缺省 true(主画布行为);嵌入窗口默认关,读元素靠 hover */
|
|
26
|
+
showLabels?: boolean;
|
|
27
|
+
/** H 条带上方的 H-Cayley 小圈;缺省 true(主画布行为),嵌入窗口默认关省空间 */
|
|
28
|
+
showSubgroupCayley?: boolean;
|
|
29
|
+
/** 点击节点:缺省无操作(主画布壳接全局选中,窗口引擎自己维护会话态) */
|
|
30
|
+
onSelect?: (elId: string, additive: boolean) => void;
|
|
31
|
+
/** 悬停节点:主画布走全局 Hover,窗口经 anchor 就地气泡 */
|
|
32
|
+
onHover?: (el: GroupElement | null, anchor?: {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
} | null) => void;
|
|
36
|
+
noGroupText?: string;
|
|
37
|
+
/** 有群但无陪集数据时的文案(缺省 i18n canvas.cosetStripNoCosets,主应用语境);
|
|
38
|
+
* 窗口引擎可传自定义提示(如本地枚举上限) */
|
|
39
|
+
noCosetsText?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function CosetStripScene({ group, selectedElements, canvasTransform, viewBoxSize, cosetElementMap, cosetColors, cosetHighlightSet, subsets, showLabels, showSubgroupCayley, onSelect, onHover, noGroupText, noCosetsText, }: CosetStripSceneProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CanvasTransform, Group, GroupElement, NodePosition } from '@groupviz/core';
|
|
2
|
+
export interface CycleViewProps {
|
|
3
|
+
group: Group | null;
|
|
4
|
+
selectedElements: Set<string>;
|
|
5
|
+
canvasTransform: CanvasTransform;
|
|
6
|
+
viewBoxSize: {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
};
|
|
10
|
+
/** 缺省 false(显示全部循环子群);true 时仅显示极大循环并启用 planar 布局 */
|
|
11
|
+
showMaximalCycles?: boolean;
|
|
12
|
+
/** 节点半径;缺省 24 */
|
|
13
|
+
nodeRadius?: number;
|
|
14
|
+
/** 是否显示节点标签;缺省 true(>60 阶自适应) */
|
|
15
|
+
showLabels?: boolean;
|
|
16
|
+
/** 是否显示每个循环的 ⟨g⟩ ≅ Z_n 标注;缺省 true */
|
|
17
|
+
showCycleLabels?: boolean;
|
|
18
|
+
/** 缺省 false;true 时禁用节点拖拽(供 ViewWindow 锁定状态使用,点击选中仍保留) */
|
|
19
|
+
locked?: boolean;
|
|
20
|
+
/** 子集着色(子集→元素映射);缺省空 */
|
|
21
|
+
subsets?: Array<{
|
|
22
|
+
elementIds: string[];
|
|
23
|
+
color: string;
|
|
24
|
+
}>;
|
|
25
|
+
selfInverseElementId?: string | null;
|
|
26
|
+
cosetElementMap?: Map<string, number>;
|
|
27
|
+
cosetHighlightSet?: Set<number>;
|
|
28
|
+
cosetColors?: string[];
|
|
29
|
+
/** 外部持久化节点位置(主画布共享位置);缺省使用本地拖拽态 */
|
|
30
|
+
getNodePosition?: (elId: string) => NodePosition | undefined;
|
|
31
|
+
/** 拖拽回写节点位置;缺省写入本地拖拽态 */
|
|
32
|
+
onNodePositionChange?: (elId: string, x: number, y: number) => void;
|
|
33
|
+
onSelect?: (elId: string, additive: boolean) => void;
|
|
34
|
+
onHover?: (el: GroupElement | null, anchor?: {
|
|
35
|
+
x: number;
|
|
36
|
+
y: number;
|
|
37
|
+
} | null) => void;
|
|
38
|
+
noGroupText?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function CycleView({ group, selectedElements, canvasTransform, viewBoxSize, showMaximalCycles, nodeRadius, showLabels, showCycleLabels, locked, subsets, selfInverseElementId, cosetElementMap, cosetHighlightSet, cosetColors, getNodePosition, onNodePositionChange, onSelect, onHover, noGroupText, }: CycleViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { Group, GroupElement, HomomorphismResult } from '@groupviz/core';
|
|
3
|
+
export interface HomomorphismSceneProps {
|
|
4
|
+
source: Group | null;
|
|
5
|
+
target: Group | null;
|
|
6
|
+
mapping: Map<string, string>;
|
|
7
|
+
/** 预计算结果(null=源/目标缺失或 mapping 为空)。缺省(undefined)由 Scene 内部 verifyHomomorphism 推导 */
|
|
8
|
+
result?: HomomorphismResult | null;
|
|
9
|
+
/** 映射显示名(TeX 或纯文本);缺省 `${source.symbol} → ${target.symbol}` */
|
|
10
|
+
name?: string;
|
|
11
|
+
/** 定理模式(第一同构定理动画);缺省 false。动画内容由 theoremAnimation 注入 */
|
|
12
|
+
theoremMode?: boolean;
|
|
13
|
+
onTheoremModeChange?: (v: boolean) => void;
|
|
14
|
+
/** 定理动画内容(主画布壳注入 <FirstIsomorphismAnimation>);窗口不传 */
|
|
15
|
+
theoremAnimation?: ReactNode;
|
|
16
|
+
/** 节点常驻标签;缺省 true(主画布行为);嵌入窗口默认关,读元素靠悬停就地气泡 */
|
|
17
|
+
showLabels?: boolean;
|
|
18
|
+
/** 悬停节点(源/目标元素 + 视口内屏幕锚点);主画布壳不传(内部高亮即可),窗口接就地气泡 */
|
|
19
|
+
onHover?: (el: GroupElement | null, anchor?: {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
} | null) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function HomomorphismScene({ source, target, mapping, result, name, theoremMode, onTheoremModeChange, theoremAnimation, showLabels, onHover, }: HomomorphismSceneProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SceneWindow — @groupviz/react 通用窗口壳容器(FGVE「壳能力参数化」)。
|
|
3
|
+
*
|
|
4
|
+
* 定位:ViewWindow(主应用浮动窗壳)与「裸 Scene 直渲」之间的中间形态。壳只管
|
|
5
|
+
* 窗口 chrome,children 渲任意 packaged Scene(消费端自持 Scene props,本组件
|
|
6
|
+
* 零 Scene 耦合)。两个层次控制壳能力:
|
|
7
|
+
*
|
|
8
|
+
* shell: 'none' → 裸内容容器(等同 Frame 直嵌,不带任何 chrome)
|
|
9
|
+
* 'chrome' → 标题栏 + 能力按钮 + 拖拽/resize + ⚙ View Config 面板 + persist
|
|
10
|
+
* capabilities: chrome 形态下逐项露/藏内容;不传 = 全开,显式 false 关闭该项。
|
|
11
|
+
*
|
|
12
|
+
* 零 context / i18n / zod 依赖:主题用 theme prop(颜色自含 hex,不读 CSS 变量),
|
|
13
|
+
* 按钮图标 + 英文 title(与主应用 FloatingViewWindow 一致),持久化 minimal
|
|
14
|
+
* localStorage(try/catch 宽容,不引 utils/persistence 的 zod 校验链)。
|
|
15
|
+
*
|
|
16
|
+
* 约定:parent 需 position:relative;chrome 窗口 absolute 定位可拖可缩;shell:'none'
|
|
17
|
+
* 时返回普通块级容器(不脱离文档流)。
|
|
18
|
+
*/
|
|
19
|
+
import { type ReactNode } from 'react';
|
|
20
|
+
import type { Group } from '@groupviz/core';
|
|
21
|
+
export type SceneWindowTheme = 'dark' | 'light';
|
|
22
|
+
/** 窗口级 config(行为开关;Scene 级参数由消费端以 Scene props 直传,不经此壳) */
|
|
23
|
+
export interface SceneWindowConfig {
|
|
24
|
+
/** 📌 锁定窗口移动(拖拽禁用) */
|
|
25
|
+
locked?: boolean;
|
|
26
|
+
/** 标题栏 info 区显示群符号/阶/名 */
|
|
27
|
+
showInfo?: boolean;
|
|
28
|
+
/** 8 向 resize 手柄 */
|
|
29
|
+
resizable?: boolean;
|
|
30
|
+
/** 定位用 fixed(视口固定)而非 absolute */
|
|
31
|
+
viewportFixed?: boolean;
|
|
32
|
+
/** 标题栏整组隐藏(插图等专注阅读场景) */
|
|
33
|
+
showControls?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** chrome 内容裁剪位;缺省全开。false 关某项 */
|
|
36
|
+
export interface SceneWindowCaps {
|
|
37
|
+
/** 标题栏本体(含 info 区) */
|
|
38
|
+
titlebar?: boolean;
|
|
39
|
+
/** 标题栏拖拽移动(需 titlebar 且 locked=false) */
|
|
40
|
+
drag?: boolean;
|
|
41
|
+
/** resize 手柄(8 向) */
|
|
42
|
+
resize?: boolean;
|
|
43
|
+
/** 📌 锁定移动按钮 */
|
|
44
|
+
lockMove?: boolean;
|
|
45
|
+
/** i 信息开关按钮 */
|
|
46
|
+
toggleInfo?: boolean;
|
|
47
|
+
/** ⚙ View Config 面板(窗口 config 编辑) */
|
|
48
|
+
params?: boolean;
|
|
49
|
+
/** × 关闭按钮(触发 onClose) */
|
|
50
|
+
close?: boolean;
|
|
51
|
+
/** storageKey 持久化(位置/尺寸/config) */
|
|
52
|
+
persist?: boolean;
|
|
53
|
+
}
|
|
54
|
+
interface SceneWindowProps {
|
|
55
|
+
/** 标题栏主文案;缺省回退 group.symbol */
|
|
56
|
+
title?: string;
|
|
57
|
+
/** 标题/信息兜底源 */
|
|
58
|
+
group?: Group | null;
|
|
59
|
+
/** 窗口主题(背景/边框/文字配色);缺省 'dark' */
|
|
60
|
+
theme?: SceneWindowTheme;
|
|
61
|
+
/** 'chrome' 浮动窗壳(缺省)/ 'none' 裸内容容器 */
|
|
62
|
+
shell?: 'none' | 'chrome';
|
|
63
|
+
/** chrome 内容裁剪;不传全开 */
|
|
64
|
+
capabilities?: SceneWindowCaps;
|
|
65
|
+
/** 窗口 config(受控传入或非受控初值) */
|
|
66
|
+
config?: SceneWindowConfig;
|
|
67
|
+
onConfigChange?: (c: SceneWindowConfig) => void;
|
|
68
|
+
/** 持久化键(cap.persist 且给键才读写 localStorage,键空间 gv-sw-*) */
|
|
69
|
+
storageKey?: string;
|
|
70
|
+
defaultPosition?: {
|
|
71
|
+
x: number;
|
|
72
|
+
y: number;
|
|
73
|
+
};
|
|
74
|
+
defaultSize?: {
|
|
75
|
+
width: number;
|
|
76
|
+
height: number;
|
|
77
|
+
};
|
|
78
|
+
onClose?: () => void;
|
|
79
|
+
/** 任意 packaged Scene(或任意内容) */
|
|
80
|
+
children: ReactNode;
|
|
81
|
+
}
|
|
82
|
+
export declare function SceneWindow({ title, group, theme, shell, capabilities, config: configProp, onConfigChange, storageKey, defaultPosition, defaultSize, onClose, children, }: SceneWindowProps): import("react/jsx-runtime").JSX.Element;
|
|
83
|
+
export type { SceneWindowProps };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Group } from '@groupviz/core';
|
|
2
|
+
export interface SetViewProps {
|
|
3
|
+
group: Group | null;
|
|
4
|
+
selectedElements: Set<string>;
|
|
5
|
+
canvasTransform: {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
scale: number;
|
|
9
|
+
};
|
|
10
|
+
viewBoxSize: {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
14
|
+
subsets?: Array<{
|
|
15
|
+
elementIds: string[];
|
|
16
|
+
color: string;
|
|
17
|
+
}>;
|
|
18
|
+
selfInverseElementId?: string | null;
|
|
19
|
+
cosetElementMap?: Map<string, number>;
|
|
20
|
+
cosetHighlightSet?: Set<number>;
|
|
21
|
+
cosetColors?: string[];
|
|
22
|
+
onSelect?: (elId: string, additive: boolean) => void;
|
|
23
|
+
onHover?: (el: Group['elements'][number] | null, anchor?: {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
} | null) => void;
|
|
27
|
+
noGroupText?: string;
|
|
28
|
+
nodeRadius?: number;
|
|
29
|
+
gap?: number;
|
|
30
|
+
columns?: number;
|
|
31
|
+
showLabels?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare function SetView({ group, selectedElements, canvasTransform, viewBoxSize, subsets, selfInverseElementId, cosetElementMap, cosetHighlightSet, cosetColors, onSelect, onHover, noGroupText, nodeRadius: nodeRadiusOverride, gap: gapOverride, columns: columnsOverride, showLabels: showLabelsOverride, }: SetViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type SubgroupLatticeNode, type SubgroupLatticeEdge } from '@groupviz/core';
|
|
2
|
+
import type { SeriesType, SeriesFactor } from '@groupviz/core';
|
|
3
|
+
import type { CanvasTransform, Group, GroupElement, LatticeLabelDetail, Subset } from '@groupviz/core';
|
|
4
|
+
export interface LatticeData {
|
|
5
|
+
nodes: SubgroupLatticeNode[];
|
|
6
|
+
edges: SubgroupLatticeEdge[];
|
|
7
|
+
}
|
|
8
|
+
/** 子群列(Series)状态:由宿主组装后传入,内核只负责高亮与面板呈现 */
|
|
9
|
+
export interface SublatticeSeriesState {
|
|
10
|
+
type: SeriesType;
|
|
11
|
+
/** 系列项的元素集合;null 表示后端仍在计算 / 超过守卫 */
|
|
12
|
+
terms: GroupElement[][] | null;
|
|
13
|
+
factors?: SeriesFactor[] | null;
|
|
14
|
+
solvable?: boolean;
|
|
15
|
+
nilpotent?: boolean;
|
|
16
|
+
chainCount?: number;
|
|
17
|
+
truncated?: boolean;
|
|
18
|
+
loading?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface SublatticeSceneProps {
|
|
21
|
+
group: Group | null;
|
|
22
|
+
/** 外部提供则优先(大群后端通路);缺省内核对 order ≤ 60 自行枚举 */
|
|
23
|
+
lattice?: LatticeData | null;
|
|
24
|
+
canvasTransform?: CanvasTransform;
|
|
25
|
+
/** 宿主可用像素尺寸;缺省由 ResizeObserver 实测自身容器 */
|
|
26
|
+
availableSize?: {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
/** 名片细节档,缺省 'auto'(按槽位屏幕宽度自动降级) */
|
|
31
|
+
labelDetail?: LatticeLabelDetail;
|
|
32
|
+
/** 共轭子群合并为轨道节点,缺省 false */
|
|
33
|
+
mergeConjugates?: boolean;
|
|
34
|
+
/** 名片与层距的世界单位乘子,缺省 1 */
|
|
35
|
+
nodeScale?: number;
|
|
36
|
+
/** 底部子群列面板,缺省 true */
|
|
37
|
+
showSeriesPanel?: boolean;
|
|
38
|
+
series?: SublatticeSeriesState | null;
|
|
39
|
+
/** 群中心元素 id 列表(宿主已算好时传入,省一次本地计算) */
|
|
40
|
+
centerIds?: string[];
|
|
41
|
+
subsets?: Subset[];
|
|
42
|
+
activeNodeIdx?: number | null;
|
|
43
|
+
onActivateNode?: (idx: number | null, node: SubgroupLatticeNode | null) => void;
|
|
44
|
+
noGroupText?: string;
|
|
45
|
+
/** 渲染主题(格取色 palette)。缺省回落到 ThemeContext(无 Provider 时 'dark');
|
|
46
|
+
* 主应用壳不传即保持现状(读全局主题),包消费端显式传以与容器主题解耦 */
|
|
47
|
+
theme?: 'dark' | 'light';
|
|
48
|
+
}
|
|
49
|
+
interface SeriesPanelProps {
|
|
50
|
+
group: Group;
|
|
51
|
+
series: SublatticeSeriesState;
|
|
52
|
+
color: string | null;
|
|
53
|
+
/** 渲染主题(徽标深浅色)。缺省回落到 ThemeContext */
|
|
54
|
+
theme?: 'dark' | 'light';
|
|
55
|
+
}
|
|
56
|
+
/** 子群列链式展示:N₀ ⊵ N₁ ⊵ … + 各级阶 + 因子 + 可解/幂零徽标(由原视图内联 JSX 迁出) */
|
|
57
|
+
export declare function SeriesPanel({ group, series, color, theme: themeProp }: SeriesPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
58
|
+
/**
|
|
59
|
+
* 子群格受控内核(FGVE 阶段 2 批次三)。
|
|
60
|
+
*
|
|
61
|
+
* 小窗口里的可读性靠三件事:
|
|
62
|
+
* 1. 布局世界坐标紧贴内容(`computeLatticeLayout`,无 1000×600 下限),适配缩放
|
|
63
|
+
* 钳 ≤ 1,故主画布不会被撑大、小窗也不会被 letterbox 到不可读;
|
|
64
|
+
* 2. 名片按"槽位屏幕宽度"自动降级 full → compact → dots;compact/dots 的几何按
|
|
65
|
+
* `1/eff` 反算为屏幕恒定大小,同时被槽位宽封顶,所以在任何密度下都不重叠;
|
|
66
|
+
* 3. 省掉的文字不丢——底部 caption 行按 hover ?? 选中给出完整名片;密度真的高时
|
|
67
|
+
* 用 `mergeConjugates` 把共轭子群合成一个轨道节点(×n,n = |G : N_G(H)|)。
|
|
68
|
+
*/
|
|
69
|
+
export declare function SublatticeScene({ group, lattice, canvasTransform, availableSize, labelDetail, mergeConjugates, nodeScale, showSeriesPanel, series, centerIds, subsets, activeNodeIdx: activeNodeIdxProp, onActivateNode, noGroupText, theme: themeProp, }: SublatticeSceneProps): import("react/jsx-runtime").JSX.Element;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Group } from '@groupviz/core';
|
|
2
|
+
import type { SymmetryType } from '@groupviz/core';
|
|
3
|
+
export interface SymmetryViewSceneProps {
|
|
4
|
+
/** 展示群(null 由调用方自行占位,本组件要求非空) */
|
|
5
|
+
group: Group;
|
|
6
|
+
/** 对称类型;缺省按 getSymmetryType(group) 推导(unsupported 群渲染提示 overlay) */
|
|
7
|
+
symmetryType?: SymmetryType;
|
|
8
|
+
/** 深色场景配色(背景 + 顶部标注文字);主画布传主主题,ViewWindow 传窗口主题(解耦) */
|
|
9
|
+
dark?: boolean;
|
|
10
|
+
/** 对偶多面体(cube↔octahedron / icosahedron↔dodecahedron):受控形态(false=主形 / true=对偶形)。
|
|
11
|
+
* 切换入口由宿主提供(ViewWindow ⚙ 面板 / 主画布 ViewPanel 的 Shape 选项),场景内不再悬浮切换按钮 */
|
|
12
|
+
variant?: boolean;
|
|
13
|
+
/** 元素作用演示开关;缺省 false */
|
|
14
|
+
showAction?: boolean;
|
|
15
|
+
/** 演示元素 id(受控,toggle 语义:点活跃元素回到恒等姿态);缺省 null */
|
|
16
|
+
actionElementId?: string | null;
|
|
17
|
+
/** 动画倍速 0.2–5;缺省 1 */
|
|
18
|
+
rotateSpeed?: number;
|
|
19
|
+
/** 顶部群名 + 几何描述标注;缺省 true(小窗可关) */
|
|
20
|
+
showFigureTitle?: boolean;
|
|
21
|
+
/** 锁定相机交互(拖拽旋转/平移/缩放);演示动画期间本就禁用 */
|
|
22
|
+
locked?: boolean;
|
|
23
|
+
/** 演示状态提示回调(主画布接 hint bar,ViewWindow 显示为内容区底部唯一浮条);缺省无 */
|
|
24
|
+
onHint?: (msg: string) => void;
|
|
25
|
+
/** 演示开启但当前元素无可旋转作用(恒等/未选)时,是否上抛 clickHint 引导;
|
|
26
|
+
* 主画布缺省 true(提示去其它视图点元素);ViewWindow 传 false(引导文案写在参数面板,浮条只显示真实状态) */
|
|
27
|
+
hintOnIdle?: boolean;
|
|
28
|
+
/** 重放信号:宿主自增该值即对当前演示元素重播一次动画(姿态不改变目标,
|
|
29
|
+
* 解决同元素动画播完一次后无入口重看的缺口);缺省 0 */
|
|
30
|
+
replaySignal?: number;
|
|
31
|
+
}
|
|
32
|
+
/** 对称性视图纯渲染核(props 化、主题解耦):Canvas + 场景 + 顶部标注 + 演示动画。
|
|
33
|
+
* 主画布经 SymmetryView 适配器接入全局 context;ViewWindow(FGVE 引擎)受控直接使用。 */
|
|
34
|
+
export declare function SymmetryViewScene({ group, symmetryType: symmetryTypeProp, dark, variant, showAction, actionElementId, rotateSpeed, showFigureTitle, locked, onHint, hintOnIdle, replaySignal, }: SymmetryViewSceneProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CanvasTransform, Group, GroupElement, Subset } from '@groupviz/core';
|
|
2
|
+
import type { CosetInfo } from '@groupviz/core';
|
|
3
|
+
import type { TableStrategy } from '@groupviz/core';
|
|
4
|
+
export declare const TABLE_PAD_W = 44;
|
|
5
|
+
export declare const TABLE_PAD_H = 74;
|
|
6
|
+
export interface TableViewProps {
|
|
7
|
+
group: Group | null;
|
|
8
|
+
selectedElements: Set<string>;
|
|
9
|
+
canvasTransform: CanvasTransform;
|
|
10
|
+
viewBoxSize: {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
14
|
+
/** 子集(含子群标记),用于子群/非子群着色;缺省空 */
|
|
15
|
+
subsets?: Subset[];
|
|
16
|
+
cosetElementMap?: Map<string, number>;
|
|
17
|
+
cosetColors?: string[];
|
|
18
|
+
cosetData?: CosetInfo | null;
|
|
19
|
+
cosetType?: 'left' | 'right';
|
|
20
|
+
showAllCosets?: boolean;
|
|
21
|
+
/** 大群告警已解除(对应主画布 forceShowLargeGroupViews.has('table'));缺省 false */
|
|
22
|
+
forceShowLargeGroup?: boolean;
|
|
23
|
+
/** 解除大群告警回调;缺省使用本地状态 */
|
|
24
|
+
onForceShowLargeGroup?: (allow: boolean) => void;
|
|
25
|
+
/** 大群(>16 阶)展示策略;缺省 'subgroup' */
|
|
26
|
+
strategy?: TableStrategy;
|
|
27
|
+
/** 单元格尺寸;缺省 50 */
|
|
28
|
+
cellSize?: number;
|
|
29
|
+
/** 热力图模式:只显示颜色,不显示元素和行/列表头;缺省 false */
|
|
30
|
+
showHeatmap?: boolean;
|
|
31
|
+
/** 策略被内部 UI 切换时回传(供外部 viewParams 同步) */
|
|
32
|
+
onStrategyChange?: (s: TableStrategy) => void;
|
|
33
|
+
/** 实际渲染的表格内容尺寸回传(行数×cellSize + 表头/页脚),用于 ViewWindow 设定最小窗口尺寸;
|
|
34
|
+
* 大群告警/全屏占位时回传 null(无表格可显示) */
|
|
35
|
+
onLayoutSize?: (size: {
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
} | null) => void;
|
|
39
|
+
onSelect?: (elId: string, additive: boolean) => void;
|
|
40
|
+
onHover?: (el: GroupElement | null) => void;
|
|
41
|
+
noGroupText?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function TableView({ group, selectedElements, viewBoxSize, canvasTransform, subsets: subsetsProp, cosetElementMap, cosetColors, cosetData: cosetDataProp, cosetType: cosetTypeProp, showAllCosets: showAllCosetsProp, forceShowLargeGroup, onForceShowLargeGroup, strategy: strategyProp, cellSize: cellSizeProp, showHeatmap, onStrategyChange, onLayoutSize, onSelect, onHover, noGroupText, }: TableViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Group, ViewMode, CayleyAction, Layout3D } from '@groupviz/core';
|
|
2
|
+
import { type CayleyShape2D } from '@groupviz/core';
|
|
3
|
+
import type { CayleyActionParam } from '@groupviz/core';
|
|
4
|
+
export declare function getInitialCayleyActions(group: Group): CayleyAction[];
|
|
5
|
+
/**
|
|
6
|
+
* 归一化凯莱视图作用边参数:过滤群中不存在的 elementId,补全 enabled(默认 true)与
|
|
7
|
+
* color(默认 COLOR_PALETTE 按序)。actions 未提供时返回群生成元集合。
|
|
8
|
+
* ViewWindow 参数面板与 CayleyView 渲染共用,保证两边对「当前边集合」的判定一致。
|
|
9
|
+
*/
|
|
10
|
+
export declare function normalizeCayleyActions(group: Group, actions?: CayleyActionParam[]): CayleyAction[];
|
|
11
|
+
export interface CayleyShapeConfig {
|
|
12
|
+
defaultShape3D: Layout3D;
|
|
13
|
+
availableShapes3D: Layout3D[];
|
|
14
|
+
defaultShape2D: CayleyShape2D;
|
|
15
|
+
availableShapes2D: CayleyShape2D[];
|
|
16
|
+
}
|
|
17
|
+
export declare function getCayleyShapeConfig(group: Group): CayleyShapeConfig;
|
|
18
|
+
export declare function getSpecialCayleyActions(group: Group, shape: Layout3D): CayleyAction[] | null;
|
|
19
|
+
export declare function toggleCayleyActionReducer(prev: CayleyAction[], elementId: string): CayleyAction[];
|
|
20
|
+
export declare function addAllCayleyActionsHelper(group: Group, currentView: ViewMode, cayleyShape3D: Layout3D, existingActions: CayleyAction[]): CayleyAction[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type Lang } from './translations.js';
|
|
3
|
+
export interface I18nContextValue {
|
|
4
|
+
lang: Lang;
|
|
5
|
+
setLang: (lang: Lang) => void;
|
|
6
|
+
t: (key: string, params?: Record<string, string | number>) => string;
|
|
7
|
+
}
|
|
8
|
+
export declare const I18nContext: import("react").Context<I18nContextValue>;
|
|
9
|
+
export declare function I18nProvider({ children }: {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useTranslation(): import("./I18nContext").I18nContextValue;
|