@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.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @groupviz/react 门面 — FGVE 阶段 3 双包产物(vite lib 构建入口)。
3
+ *
4
+ * 导出清单(随视图入包批次扩充):
5
+ * - 视图 Scene:SetView / CycleView / CayleyView / CosetStripScene 等纯渲染内核。
6
+ * Scene 仅依赖 i18n context(文案 key)+ core;不读 useGroup/useHover/useTheme
7
+ * —— context 组装壳(*View/*FromContext)留在主应用,不入包。
8
+ * - I18nProvider:react 包自带中文/英文语言包(translations.ts 全量打包),
9
+ * Scene 文案消费方需以 <I18nProvider> 包裹(缺省 Provider 时 t() 回落 key)。
10
+ *
11
+ * 注意:本文件内不要直接 import '../../core/...' —— core 由宿主安装的
12
+ * @groupviz/core 包供给(构建期 coreToPackage 插件把相对 core 引用 external)。
13
+ */
14
+ export { SetView } from '../components/Canvas/SetView.js';
15
+ export type { SetViewProps } from '../components/Canvas/SetView.js';
16
+ export { CycleView } from '../components/Canvas/CycleView.js';
17
+ export type { CycleViewProps } from '../components/Canvas/CycleView.js';
18
+ export { CayleyView } from '../components/Canvas/CayleyView.js';
19
+ export type { CayleyViewProps } from '../components/Canvas/CayleyView.js';
20
+ export { CosetStripScene } from '../components/Canvas/CosetStripScene.js';
21
+ export type { CosetStripSceneProps } from '../components/Canvas/CosetStripScene.js';
22
+ export { TableView } from '../components/Canvas/TableView.js';
23
+ export type { TableViewProps } from '../components/Canvas/TableView.js';
24
+ export { ActionScene } from '../components/Canvas/ActionScene.js';
25
+ export type { ActionSceneProps } from '../components/Canvas/ActionScene.js';
26
+ export { HomomorphismScene } from '../components/Canvas/HomomorphismScene.js';
27
+ export type { HomomorphismSceneProps } from '../components/Canvas/HomomorphismScene.js';
28
+ export { SymmetryViewScene } from '../components/Canvas/SymmetryViewScene.js';
29
+ export type { SymmetryViewSceneProps } from '../components/Canvas/SymmetryViewScene.js';
30
+ export { Cayley3DScene } from '../components/Canvas/Cayley3DScene.js';
31
+ export type { Cayley3DSceneProps } from '../components/Canvas/Cayley3DScene.js';
32
+ export { SublatticeScene } from '../components/Canvas/SublatticeScene.js';
33
+ export type { SublatticeSceneProps } from '../components/Canvas/SublatticeScene.js';
34
+ export { SceneWindow } from '../components/Canvas/SceneWindow.js';
35
+ export type { SceneWindowProps, SceneWindowConfig, SceneWindowCaps, SceneWindowTheme } from '../components/Canvas/SceneWindow.js';
36
+ export { I18nProvider } from '../i18n/I18nContext.js';
37
+ export type { Group, GroupElement } from '@groupviz/core';
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@groupviz/react",
3
+ "version": "2.0.0",
4
+ "description": "GroupViz 群论可视化 React 视图组件",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/rrCathy/GroupViz.git"
9
+ },
10
+ "keywords": [
11
+ "group-theory",
12
+ "abstract-algebra",
13
+ "mathematics",
14
+ "visualization",
15
+ "cayley-graph",
16
+ "react",
17
+ "svg",
18
+ "threejs"
19
+ ],
20
+ "type": "module",
21
+ "main": "./index.js",
22
+ "types": "./package/react.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./package/react.d.ts",
26
+ "import": "./index.js"
27
+ },
28
+ "./theme.css": "./theme.css"
29
+ },
30
+ "peerDependencies": {
31
+ "@groupviz/core": "^2.0.0",
32
+ "react": "^19.0.0",
33
+ "react-dom": "^19.0.0",
34
+ "three": ">=0.184.0 <0.186.0",
35
+ "@react-three/fiber": "^9.0.0",
36
+ "@react-three/drei": "^10.0.0",
37
+ "katex": "^0.16.0"
38
+ },
39
+ "sideEffects": [
40
+ "**/*.css"
41
+ ]
42
+ }
@@ -0,0 +1,13 @@
1
+ import { type ReactNode } from 'react';
2
+ export type Theme = 'dark' | 'light';
3
+ export interface ThemeContextValue {
4
+ theme: Theme;
5
+ toggleTheme: () => void;
6
+ /** 视图窗口(浮动窗/ViewWindow)独立的深浅色主题,与主界面 theme 解耦 */
7
+ viewWindowTheme: Theme;
8
+ toggleViewWindowTheme: () => void;
9
+ }
10
+ export declare const ThemeContext: import("react").Context<ThemeContextValue>;
11
+ export declare function ThemeProvider({ children }: {
12
+ children: ReactNode;
13
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { ThemeProvider } from './ThemeContext.js';
2
+ export declare function useTheme(): import("./ThemeContext").ThemeContextValue;
3
+ export { ThemeProvider };
4
+ export type { Theme } from './ThemeContext.js';
package/theme.css ADDED
@@ -0,0 +1,186 @@
1
+ /**
2
+ * @groupviz/react 主题 CSS — 由 scripts/pkg/finalize-pkg.mjs 自动提取自 src/index.css。
3
+ * 消费者入口:import '@groupviz/react/theme.css'
4
+ */
5
+ /* ===== 深色(默认)===== */
6
+ :root,
7
+ [data-theme="dark"] {
8
+ --bg-primary: #0f0f1a;
9
+ --bg-secondary: #151525;
10
+ --bg-canvas: #0a0a14;
11
+ --bg-canvas-gradient: #12121f;
12
+ --bg-interactive: #1a1a2e;
13
+ --bg-interactive-hover: #1e1e36;
14
+ --bg-input: #1a1a2e;
15
+ --bg-header-start: #1a1a2e;
16
+ --bg-header-end: #0f0f1a;
17
+ --bg-tooltip: rgba(21, 21, 37, 0.95);
18
+ --bg-hint: rgba(16, 16, 30, 0.96);
19
+ --bg-dark-chip: #111111;
20
+ --bg-preview-circle: #0c0c1a;
21
+ --bg-element-chip: #1a1a2e;
22
+ --bg-chart: rgba(12, 12, 26, 0.95);
23
+
24
+ --text-primary: #e0e0e0;
25
+ --text-heading: #ffffff;
26
+ --text-secondary: #cccccc;
27
+ --text-muted: #aaaaaa;
28
+ --text-dim: #888888;
29
+ --text-subtle: #666666;
30
+ --text-meta: #999999;
31
+ --text-special: #a0a0c0;
32
+ --text-welcome-label: #8a8abb;
33
+
34
+ --text-welcome-tagline: #8888aa;
35
+
36
+ --text-welcome-feature: #c0c0e0;
37
+ --text-lang-hover: #d0d0f0;
38
+ --text-active: #e0e0f0;
39
+ --text-chip-hover: #ffffff;
40
+
41
+ --border-primary: #2d2d4a;
42
+ --border-subtle: #1e1e36;
43
+ --border-hover: #4a4a7a;
44
+
45
+ --accent-teal: #4ecdc4;
46
+ --accent-teal-hover: #5eddd4;
47
+ --accent-indigo: #6366f1;
48
+ --accent-purple: #a78bfa;
49
+ --accent-yellow: #ffd93d;
50
+ --accent-yellow-text: #ffd93d;
51
+ --accent-normal: #9b59b6;
52
+ --accent-simple-end: #8e44ad;
53
+ --accent-danger: #ff6666;
54
+ --accent-danger-hover: #ff3333;
55
+ --accent-sponsor: #f5576c;
56
+ --accent-sponsor-hover: #ff8a95;
57
+ --accent-blue: #3b82f6;
58
+ --accent-green: #22c55e;
59
+ --accent-red: #ff6b6b;
60
+ --accent-orange: #f97316;
61
+ --btn-on-accent: #0f0f1a;
62
+ --text-accent: #4ecdc4;
63
+
64
+ --bg-elevated: var(--bg-interactive-hover);
65
+ --bg-muted: var(--bg-secondary);
66
+ --bg-panel: var(--bg-secondary);
67
+ --bg-hover: var(--bg-interactive-hover);
68
+ --border-color: var(--border-primary);
69
+ --canvas-bg: var(--bg-canvas);
70
+ --input-bg: var(--bg-input);
71
+ --panel-bg: var(--bg-secondary);
72
+ --panel-border: var(--border-primary);
73
+ --text: var(--text-primary);
74
+
75
+ --gradient-header: linear-gradient(180deg, var(--bg-header-start) 0%, var(--bg-header-end) 100%);
76
+ --gradient-canvas: radial-gradient(circle at center, var(--bg-canvas-gradient) 0%, var(--bg-canvas) 100%);
77
+
78
+ --shadow-hint: 0 4px 16px rgba(0, 0, 0, 0.5);
79
+ --shadow-preview: 0 0 40px rgba(99, 102, 241, 0.2), 0 8px 32px rgba(0, 0, 0, 0.6);
80
+
81
+ --table-cell-bg: #ffffff0e;
82
+ --table-cell-border: #ffffff44;
83
+
84
+ --node-fill: #1e2a3e;
85
+ --node-stroke: white;
86
+ --node-fill-selected: #2a3a56;
87
+ --node-text: white;
88
+
89
+ --preview-bg-center: #1e2040;
90
+ --preview-bg-edge: #0c0c1a;
91
+ --preview-pointer-color: #1e2040;
92
+ --preview-node-fill: #1a1a2e;
93
+ --preview-node-stroke: #4a4a7a;
94
+ --preview-text: #d0d0f0;
95
+ }
96
+
97
+
98
+ /* ===== 浅色 ===== */
99
+ [data-theme="light"] {
100
+ --bg-primary: #ffffff;
101
+ --bg-secondary: #f9f9fb;
102
+ --bg-canvas: #f4f4f7;
103
+ --bg-canvas-gradient: #eeeef2;
104
+ --bg-interactive: #edeef2;
105
+ --bg-interactive-hover: #e2e4ea;
106
+ --bg-input: #f5f5f8;
107
+ --bg-header-start: #f9f9fb;
108
+ --bg-header-end: #ffffff;
109
+ --bg-tooltip: rgba(255, 255, 255, 0.97);
110
+ --bg-hint: rgba(252, 252, 255, 0.97);
111
+ --bg-dark-chip: #eeeef3;
112
+ --bg-preview-circle: #ffffff;
113
+ --bg-element-chip: #edeef2;
114
+ --bg-chart: rgba(255, 255, 255, 0.97);
115
+
116
+ --text-primary: #1c1c28;
117
+ --text-heading: #0f0f1a;
118
+ --text-secondary: #4a4a5a;
119
+ --text-muted: #6e6e7e;
120
+ --text-dim: #828294;
121
+ --text-subtle: #9c9cac;
122
+ --text-meta: #8e8ea0;
123
+ --text-special: #56569e;
124
+ --text-welcome-label: #434380;
125
+
126
+ --text-welcome-tagline: #5353a0;
127
+
128
+ --text-welcome-feature: #585868;
129
+ --text-lang-hover: #4a4a5a;
130
+ --text-active: #383848;
131
+ --text-chip-hover: #141420;
132
+
133
+ --border-primary: #e2e3e9;
134
+ --border-subtle: #edeef3;
135
+ --border-hover: #c8cad5;
136
+
137
+ --accent-teal: #0ea5a0;
138
+ --accent-teal-hover: #0d8d88;
139
+ --accent-indigo: #4f46e5;
140
+ --accent-yellow-text: #92400e;
141
+ --accent-blue: #2563eb;
142
+ --accent-green: #16a34a;
143
+ --accent-red: #d64545;
144
+ --accent-orange: #ea580c;
145
+ --accent-danger: #d64545;
146
+ --accent-danger-hover: #b91c1c;
147
+ --btn-on-accent: #ffffff;
148
+ --text-accent: #0ea5a0;
149
+
150
+ --shadow-hint: 0 4px 16px rgba(0, 0, 0, 0.06);
151
+ --shadow-preview: 0 0 40px rgba(99, 102, 241, 0.10), 0 8px 32px rgba(0, 0, 0, 0.08);
152
+
153
+ --table-cell-bg: #00000008;
154
+ --table-cell-border: #00000022;
155
+
156
+ --node-fill: #e0e3ea;
157
+ --node-stroke: #3a3a4e;
158
+ --node-fill-selected: #cdd2dc;
159
+ --node-text: #1c1c28;
160
+
161
+ --preview-bg-center: #f0f1f6;
162
+ --preview-bg-edge: #fafbfe;
163
+ --preview-pointer-color: #f0f1f6;
164
+ --preview-node-fill: #d4d7de;
165
+ --preview-node-stroke: #c5c8d2;
166
+ --preview-text: #4a4a5e;
167
+ }
168
+
169
+
170
+ /* ===== 视图基础类 ===== */
171
+ .view-svg {
172
+ width: 100%;
173
+ height: 100%;
174
+ }
175
+ .view-svg text {
176
+ user-select: none;
177
+ -webkit-user-select: none;
178
+ }
179
+ .view-empty {
180
+ width: 100%;
181
+ height: 100%;
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: center;
185
+ color: var(--text-subtle);
186
+ }
@@ -0,0 +1,18 @@
1
+ import type * as THREE from 'three';
2
+ export interface Cayley3DOrbitSnapshot {
3
+ theta: number;
4
+ phi: number;
5
+ radius: number;
6
+ target: THREE.Vector3;
7
+ }
8
+ export interface Cayley3DControlAPI {
9
+ isReady: () => boolean;
10
+ snapshotOrbit: () => Cayley3DOrbitSnapshot;
11
+ beginRotation: (radPerSec: number) => void;
12
+ endRotation: (snapshot?: Cayley3DOrbitSnapshot | null) => void;
13
+ displayAngVel: () => number;
14
+ frameAt: (index: number, frameDelayMs: number) => HTMLCanvasElement | null;
15
+ }
16
+ export declare function registerCayley3DControls(api: Cayley3DControlAPI): void;
17
+ export declare function unregisterCayley3DControls(api: Cayley3DControlAPI): void;
18
+ export declare function getCayley3DControls(): Cayley3DControlAPI | null;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 通用 Blob 下载触发 —— 与导出链(gifenc/渲染收集)解耦的纯 DOM 工具。
3
+ *
4
+ * 独立成模块的动机(FGVE 阶段 3 入包):TableView 等纯内核 Scene 需要
5
+ * "导出当前 SVG" 能力,但 utils/export.ts 整模块顶层依赖 gifenc(GIF 编码,
6
+ * 无 sideEffects 声明时会被打包器保守内嵌)。把 triggerDownload 抽到零依赖
7
+ * 模块后,react 包的程序图不再触及 export.ts,gifenc 不会进入包产物。
8
+ */
9
+ export declare function triggerDownload(blob: Blob, filename: string): void;
@@ -0,0 +1,2 @@
1
+ export declare function texify(text: string): string;
2
+ export declare function renderTex(math: string, displayMode?: boolean): string;