@xpyjs/gantt-react 0.0.1-alpha.1

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jeremy Jone
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,219 @@
1
+ # @xpyjs/gantt-react
2
+
3
+ 基于 [@xpyjs/gantt-core](../core/README.md) 的 React 甘特图组件。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @xpyjs/gantt-react
9
+ # 或
10
+ yarn add @xpyjs/gantt-react
11
+ # 或
12
+ pnpm add @xpyjs/gantt-react
13
+ ```
14
+
15
+ ## 基本使用
16
+
17
+ ```tsx
18
+ import React, { useRef } from 'react';
19
+ import { XGanttReact } from '@xpyjs/gantt-react';
20
+ import type { XGanttReactRef } from '@xpyjs/gantt-react';
21
+
22
+ function App() {
23
+ const ganttRef = useRef<XGanttReactRef>(null);
24
+
25
+ const data = [
26
+ {
27
+ id: '1',
28
+ name: '任务1',
29
+ startTime: '2024-01-01',
30
+ endTime: '2024-01-10',
31
+ progress: 50
32
+ },
33
+ {
34
+ id: '2',
35
+ name: '任务2',
36
+ startTime: '2024-01-05',
37
+ endTime: '2024-01-15',
38
+ progress: 30
39
+ }
40
+ ];
41
+
42
+ const handleTaskSelect = (data: any[], checked: boolean, all: any[]) => {
43
+ console.log('选择的任务:', data);
44
+ };
45
+
46
+ const jumpToToday = () => {
47
+ ganttRef.current?.jumpTo();
48
+ };
49
+
50
+ return (
51
+ <div>
52
+ <button onClick={jumpToToday}>跳转到今天</button>
53
+ <XGanttReact
54
+ ref={ganttRef}
55
+ style={{ height: '500px', width: '100%' }}
56
+ options={{
57
+ data,
58
+ table: {
59
+ width: 300,
60
+ columns: [
61
+ { field: 'name', label: '任务名称', width: 200 },
62
+ { field: 'progress', label: '进度', width: 100 }
63
+ ]
64
+ }
65
+ }}
66
+ onSelect={handleTaskSelect}
67
+ />
68
+ </div>
69
+ );
70
+ }
71
+
72
+ export default App;
73
+ ```
74
+
75
+ ## 使用 Hooks
76
+
77
+ ```tsx
78
+ import React from 'react';
79
+ import { XGanttReact, useXGantt, useGanttEvents } from '@xpyjs/gantt-react';
80
+
81
+ function MyGantt() {
82
+ const { ganttRef, jumpToToday, updateGanttOptions } = useXGantt();
83
+ const { onSelect, onClickRow, selectedTasks } = useGanttEvents();
84
+
85
+ const handleChangeUnit = () => {
86
+ updateGanttOptions({ unit: 'week' });
87
+ };
88
+
89
+ return (
90
+ <div>
91
+ <div>
92
+ <button onClick={jumpToToday}>跳转到今天</button>
93
+ <button onClick={handleChangeUnit}>切换到周视图</button>
94
+ <span>已选择 {selectedTasks.length} 个任务</span>
95
+ </div>
96
+ <XGanttReact
97
+ ref={ganttRef}
98
+ style={{ height: '500px' }}
99
+ options={{ data: [] }}
100
+ onSelect={onSelect}
101
+ onClickRow={onClickRow}
102
+ />
103
+ </div>
104
+ );
105
+ }
106
+ ```
107
+
108
+ ## API
109
+
110
+ ### XGanttReact Props
111
+
112
+ | 属性 | 类型 | 必填 | 说明 |
113
+ |------|------|------|------|
114
+ | options | `IOptions` | ✓ | 甘特图配置选项,变化时自动更新甘特图 |
115
+ | className | `string` | - | 容器类名 |
116
+ | style | `React.CSSProperties` | - | 容器样式 |
117
+ | onError | `EventMap['error']` | - | 错误事件回调 |
118
+ | onUpdateLink | `EventMap['update:link']` | - | 关联线更新事件回调 |
119
+ | onCreateLink | `EventMap['create:link']` | - | 关联线创建事件回调 |
120
+ | onSelectLink | `EventMap['select:link']` | - | 关联线选择事件回调 |
121
+ | onSelect | `EventMap['select']` | - | 任务选择事件回调 |
122
+ | onClickRow | `EventMap['click:row']` | - | 行点击事件回调 |
123
+ | onDoubleClickRow | `EventMap['dblclick:row']` | - | 行双击事件回调 |
124
+ | onContextMenuRow | `EventMap['contextmenu:row']` | - | 行右键菜单事件回调 |
125
+ | onClickSlider | `EventMap['click:slider']` | - | 任务条点击事件回调 |
126
+ | onDoubleClickSlider | `EventMap['dblclick:slider']` | - | 任务条双击事件回调 |
127
+ | onContextMenuSlider | `EventMap['contextmenu:slider']` | - | 任务条右键菜单事件回调 |
128
+ | onMove | `EventMap['move']` | - | 任务移动事件回调 |
129
+
130
+ ### XGanttReactRef 方法
131
+
132
+ | 方法 | 参数 | 返回值 | 说明 |
133
+ |------|------|--------|------|
134
+ | getInstance | - | `XGantt \| null` | 获取甘特图核心实例,通过实例可调用所有核心方法 |
135
+ | jumpTo | `date?: any` | `boolean` | 跳转到指定日期(不传参数跳转到今天) |
136
+
137
+ > **注意**:为了简化API,`updateOptions` 和 `render` 方法已移除。options变化时会自动更新,其他操作请通过 `getInstance()` 获取核心实例进行操作。
138
+
139
+ ### Hooks
140
+
141
+ #### useXGantt()
142
+
143
+ 提供甘特图操作的便捷方法:
144
+
145
+ - `ganttRef`: 甘特图组件引用
146
+ - `getInstance()`: 获取核心实例
147
+ - `jumpToToday()`: 跳转到今天
148
+ - `jumpTo(date)`: 跳转到指定日期
149
+
150
+ > **变更说明**:已移除 `updateGanttOptions()` 和 `renderGantt()` 方法,请通过 `getInstance()` 获取核心实例进行操作。
151
+
152
+ #### useGanttEvents()
153
+
154
+ 提供事件处理的便捷方法:
155
+
156
+ - `onSelect`: 选择事件处理器
157
+ - `onClickRow`: 行点击事件处理器
158
+ - `onMove`: 移动事件处理器
159
+ - `selectedTasks`: 已选择的任务
160
+ - `lastClickedRow`: 最后点击的行
161
+ - `movedTasks`: 移动的任务
162
+
163
+ ## 使用核心实例进行高级操作
164
+
165
+ ```tsx
166
+ import React, { useRef } from 'react';
167
+ import { XGanttReact, useXGantt } from '@xpyjs/gantt-react';
168
+
169
+ function AdvancedGantt() {
170
+ const { ganttRef, getInstance } = useXGantt();
171
+
172
+ const handleAdvancedOperation = () => {
173
+ const instance = getInstance();
174
+ if (instance) {
175
+ // 更新配置
176
+ instance.updateOptions({
177
+ unit: 'week',
178
+ primaryColor: '#007acc'
179
+ });
180
+
181
+ // 手动渲染
182
+ instance.render();
183
+
184
+ // 其他核心方法
185
+ instance.jumpTo('2024-06-01');
186
+ }
187
+ };
188
+
189
+ return (
190
+ <div>
191
+ <button onClick={handleAdvancedOperation}>高级操作</button>
192
+ <XGanttReact ref={ganttRef} options={{ data: [] }} />
193
+ </div>
194
+ );
195
+ }
196
+ ```
197
+
198
+ ## 类型定义
199
+
200
+ 所有核心库的类型都可以从 `@xpyjs/gantt-react` 直接导入:
201
+
202
+ ```tsx
203
+ import type {
204
+ IOptions,
205
+ ILink,
206
+ ErrorType,
207
+ EventMap,
208
+ XGanttReactProps,
209
+ XGanttReactRef
210
+ } from '@xpyjs/gantt-react';
211
+ ```
212
+
213
+ ## 样式
214
+
215
+ 组件已自动导入样式,无需手动引入。如需自定义样式,可以通过 CSS 变量或覆盖样式类来实现。
216
+
217
+ ## 许可证
218
+
219
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react = require("react");
5
+ const ganttCore = require("@xpyjs/gantt-core");
6
+ const XGanttReact = react.forwardRef(
7
+ (props, ref) => {
8
+ const {
9
+ options,
10
+ className,
11
+ style,
12
+ onError,
13
+ onUpdateLink,
14
+ onCreateLink,
15
+ onSelectLink,
16
+ onSelect,
17
+ onClickRow,
18
+ onDoubleClickRow,
19
+ onContextMenuRow,
20
+ onClickSlider,
21
+ onDoubleClickSlider,
22
+ onContextMenuSlider,
23
+ onMove,
24
+ ...restProps
25
+ } = props;
26
+ const containerRef = react.useRef(null);
27
+ const ganttInstanceRef = react.useRef(null);
28
+ const registerEventListeners = react.useCallback(() => {
29
+ const instance = ganttInstanceRef.current;
30
+ if (!instance) return;
31
+ if (onError) {
32
+ instance.on("error", onError);
33
+ }
34
+ if (onUpdateLink) {
35
+ instance.on("update:link", onUpdateLink);
36
+ }
37
+ if (onCreateLink) {
38
+ instance.on("create:link", onCreateLink);
39
+ }
40
+ if (onSelectLink) {
41
+ instance.on("select:link", onSelectLink);
42
+ }
43
+ if (onSelect) {
44
+ instance.on("select", onSelect);
45
+ }
46
+ if (onClickRow) {
47
+ instance.on("click:row", onClickRow);
48
+ }
49
+ if (onDoubleClickRow) {
50
+ instance.on("dblclick:row", onDoubleClickRow);
51
+ }
52
+ if (onContextMenuRow) {
53
+ instance.on("contextmenu:row", onContextMenuRow);
54
+ }
55
+ if (onClickSlider) {
56
+ instance.on("click:slider", onClickSlider);
57
+ }
58
+ if (onDoubleClickSlider) {
59
+ instance.on("dblclick:slider", onDoubleClickSlider);
60
+ }
61
+ if (onContextMenuSlider) {
62
+ instance.on("contextmenu:slider", onContextMenuSlider);
63
+ }
64
+ if (onMove) {
65
+ instance.on("move", onMove);
66
+ }
67
+ }, [
68
+ onError,
69
+ onUpdateLink,
70
+ onCreateLink,
71
+ onSelectLink,
72
+ onSelect,
73
+ onClickRow,
74
+ onDoubleClickRow,
75
+ onContextMenuRow,
76
+ onClickSlider,
77
+ onDoubleClickSlider,
78
+ onContextMenuSlider,
79
+ onMove
80
+ ]);
81
+ const initGantt = react.useCallback(() => {
82
+ if (!containerRef.current) return;
83
+ ganttInstanceRef.current = new ganttCore.XGantt(containerRef.current, options);
84
+ registerEventListeners();
85
+ }, [options, registerEventListeners]);
86
+ const jumpTo = react.useCallback((date) => {
87
+ if (ganttInstanceRef.current) {
88
+ return ganttInstanceRef.current.jumpTo(date);
89
+ }
90
+ return false;
91
+ }, []);
92
+ const destroyGantt = react.useCallback(() => {
93
+ if (ganttInstanceRef.current) {
94
+ ganttInstanceRef.current.destroy();
95
+ ganttInstanceRef.current = null;
96
+ }
97
+ }, []);
98
+ react.useImperativeHandle(ref, () => ({
99
+ getInstance: () => ganttInstanceRef.current,
100
+ jumpTo
101
+ }), [jumpTo]);
102
+ react.useEffect(() => {
103
+ initGantt();
104
+ return () => {
105
+ destroyGantt();
106
+ };
107
+ }, []);
108
+ react.useEffect(() => {
109
+ if (ganttInstanceRef.current) {
110
+ ganttInstanceRef.current.updateOptions(options);
111
+ }
112
+ }, [options]);
113
+ return /* @__PURE__ */ jsxRuntime.jsx(
114
+ "div",
115
+ {
116
+ ref: containerRef,
117
+ "data-testid": "x-gantt-container",
118
+ className: `x-gantt-container ${className || ""}`,
119
+ style: {
120
+ position: "relative",
121
+ width: "100%",
122
+ height: "100%",
123
+ ...style
124
+ },
125
+ ...restProps
126
+ }
127
+ );
128
+ }
129
+ );
130
+ XGanttReact.displayName = "XGanttReact";
131
+ function useXGantt() {
132
+ const ganttRef = react.useRef(null);
133
+ const getInstance = react.useCallback(() => {
134
+ var _a;
135
+ return ((_a = ganttRef.current) == null ? void 0 : _a.getInstance()) || null;
136
+ }, []);
137
+ const jumpTo = react.useCallback((date) => {
138
+ var _a;
139
+ return ((_a = ganttRef.current) == null ? void 0 : _a.jumpTo(date)) || false;
140
+ }, []);
141
+ return {
142
+ ganttRef,
143
+ getInstance,
144
+ jumpTo
145
+ };
146
+ }
147
+ Object.defineProperty(exports, "colorjs", {
148
+ enumerable: true,
149
+ get: () => ganttCore.colorjs
150
+ });
151
+ Object.defineProperty(exports, "dayjs", {
152
+ enumerable: true,
153
+ get: () => ganttCore.dayjs
154
+ });
155
+ Object.defineProperty(exports, "generateId", {
156
+ enumerable: true,
157
+ get: () => ganttCore.generateId
158
+ });
159
+ exports.XGanttReact = XGanttReact;
160
+ exports.default = XGanttReact;
161
+ exports.useXGantt = useXGantt;
@@ -0,0 +1,303 @@
1
+ import { Colorjs } from '@xpyjs/gantt-core';
2
+ import { colorjs } from '@xpyjs/gantt-core';
3
+ import { Dayjs } from '@xpyjs/gantt-core';
4
+ import { dayjs } from '@xpyjs/gantt-core';
5
+ import { default as default_2 } from 'react';
6
+ import { EmitData } from '@xpyjs/gantt-core';
7
+ import { ErrorType } from '@xpyjs/gantt-core';
8
+ import { EventMap } from '@xpyjs/gantt-core';
9
+ import { generateId } from '@xpyjs/gantt-core';
10
+ import { ILink } from '@xpyjs/gantt-core';
11
+ import { IOptionConfig } from '@xpyjs/gantt-core';
12
+ import { IOptions } from '@xpyjs/gantt-core';
13
+ import { RefObject } from 'react';
14
+ import { XGantt } from '@xpyjs/gantt-core';
15
+
16
+ export { Colorjs }
17
+
18
+ export { colorjs }
19
+
20
+ export { Dayjs }
21
+
22
+ export { dayjs }
23
+
24
+ export { EmitData }
25
+
26
+ export { ErrorType }
27
+
28
+ export { EventMap }
29
+
30
+ export { generateId }
31
+
32
+ export { ILink }
33
+
34
+ export { IOptionConfig }
35
+
36
+ export { IOptions }
37
+
38
+ /**
39
+ * 使用甘特图的 Hook
40
+ *
41
+ * @description 提供更便捷的甘特图操作方法
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * import React from 'react';
46
+ * import { XGanttReact, useXGantt } from '@xpyjs/gantt-react';
47
+ *
48
+ * function MyGantt() {
49
+ * const { ganttRef, getInstance, jumpTo } = useXGantt();
50
+ *
51
+ * const handleJumpToToday = () => {
52
+ * jumpTo(); // 没有参数,默认跳转到今天
53
+ * };
54
+ *
55
+ * const handleUpdateOptions = () => {
56
+ * const instance = getInstance();
57
+ * if (instance) {
58
+ * instance.updateOptions({ unit: 'week' });
59
+ * }
60
+ * };
61
+ *
62
+ * return (
63
+ * <div>
64
+ * <button onClick={handleJumpToToday}>跳转到今天</button>
65
+ * <button onClick={handleUpdateOptions}>切换到周视图</button>
66
+ * <XGanttReact
67
+ * ref={ganttRef}
68
+ * options={{ data: [] }}
69
+ * />
70
+ * </div>
71
+ * );
72
+ * }
73
+ * ```
74
+ */
75
+ export declare function useXGantt(): {
76
+ ganttRef: RefObject<XGanttReactRef>;
77
+ getInstance: () => XGantt | null;
78
+ jumpTo: (date?: any) => boolean;
79
+ };
80
+
81
+ /**
82
+ * XGantt React 组件
83
+ *
84
+ * @description 基于 `@xpyjs/gantt-core` 的 React 封装组件,提供完整的甘特图功能
85
+ *
86
+ * @example
87
+ * ```tsx
88
+ * import React, { useRef } from 'react';
89
+ * import { XGanttReact } from '@xpyjs/gantt-react';
90
+ * import type { XGanttReactRef } from '@xpyjs/gantt-react';
91
+ *
92
+ * function App() {
93
+ * const ganttRef = useRef<XGanttReactRef>(null);
94
+ *
95
+ * const handleTaskSelect = (data: any[], checked: boolean, all: any[]) => {
96
+ * console.log('任务选择:', { data, checked, all });
97
+ * };
98
+ *
99
+ * const jumpToToday = () => {
100
+ * ganttRef.current?.jumpTo();
101
+ * };
102
+ *
103
+ * return (
104
+ * <div>
105
+ * <button onClick={jumpToToday}>跳转到今天</button>
106
+ * <XGanttReact
107
+ * ref={ganttRef}
108
+ * style={{ height: '500px', width: '100%' }}
109
+ * options={{
110
+ * data: [
111
+ * {
112
+ * id: '1',
113
+ * name: '任务1',
114
+ * startTime: '2024-01-01',
115
+ * endTime: '2024-01-10',
116
+ * progress: 50
117
+ * }
118
+ * ]
119
+ * }}
120
+ * onSelect={handleTaskSelect}
121
+ * />
122
+ * </div>
123
+ * );
124
+ * }
125
+ * ```
126
+ */
127
+ declare const XGanttReact: default_2.ForwardRefExoticComponent<XGanttReactProps & default_2.RefAttributes<XGanttReactRef>>;
128
+ export { XGanttReact }
129
+ export default XGanttReact;
130
+
131
+ /**
132
+ * XGanttReact 组件的 Props 类型
133
+ */
134
+ export declare interface XGanttReactProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onError" | "onSelect" | "onClick" | "onDoubleClick" | "onContextMenu"> {
135
+ /**
136
+ * XGantt 图表的配置选项
137
+ *
138
+ * @description
139
+ * 该选项包含所有 XGantt 图表的配置参数,包括数据源、表格配置、图表配置、样式配置等
140
+ */
141
+ options: IOptions;
142
+ /**
143
+ * 容器的 className
144
+ */
145
+ className?: string;
146
+ /**
147
+ * 容器的样式
148
+ */
149
+ style?: React.CSSProperties;
150
+ /**
151
+ * 错误事件回调
152
+ *
153
+ * @description 当甘特图发生错误时触发
154
+ * @param error 错误信息对象
155
+ */
156
+ onError?: EventMap["error"];
157
+ /**
158
+ * 关联线更新事件回调
159
+ *
160
+ * @description 当关联线被更新时触发
161
+ * @param link 更新的关联线对象
162
+ */
163
+ onUpdateLink?: EventMap["update:link"];
164
+ /**
165
+ * 关联线创建事件回调
166
+ *
167
+ * @description 当新建关联线时触发
168
+ * @param link 新创建的关联线对象
169
+ */
170
+ onCreateLink?: EventMap["create:link"];
171
+ /**
172
+ * 关联线选择事件回调
173
+ *
174
+ * @description 当关联线的选择状态发生变化时触发
175
+ * @param add 新增选择的关联线
176
+ * @param cancel 取消选择的关联线
177
+ * @param all 所有当前选择的关联线
178
+ */
179
+ onSelectLink?: EventMap["select:link"];
180
+ /**
181
+ * 任务选择事件回调
182
+ *
183
+ * @description 当任务的选择状态发生变化时触发
184
+ * @param data 当前操作的任务数据数组
185
+ * @param checked 是否为选中状态
186
+ * @param all 所有当前选择的任务数据数组
187
+ */
188
+ onSelect?: EventMap["select"];
189
+ /**
190
+ * 行点击事件回调
191
+ *
192
+ * @description 当点击表格行时触发
193
+ * @param e 鼠标事件对象
194
+ * @param data 点击行对应的任务数据
195
+ */
196
+ onClickRow?: EventMap["click:row"];
197
+ /**
198
+ * 行双击事件回调
199
+ *
200
+ * @description 当双击表格行时触发
201
+ * @param e 鼠标事件对象
202
+ * @param data 双击行对应的任务数据
203
+ */
204
+ onDoubleClickRow?: EventMap["dblclick:row"];
205
+ /**
206
+ * 行右键菜单事件回调
207
+ *
208
+ * @description 当在表格行上右键点击时触发
209
+ * @param e 鼠标事件对象
210
+ * @param data 右键行对应的任务数据
211
+ */
212
+ onContextMenuRow?: EventMap["contextmenu:row"];
213
+ /**
214
+ * 任务条点击事件回调
215
+ *
216
+ * @description 当点击甘特图中的任务条时触发
217
+ * @param e 鼠标事件对象
218
+ * @param data 点击任务条对应的任务数据
219
+ */
220
+ onClickSlider?: EventMap["click:slider"];
221
+ /**
222
+ * 任务条双击事件回调
223
+ *
224
+ * @description 当双击甘特图中的任务条时触发
225
+ * @param e 鼠标事件对象
226
+ * @param data 双击任务条对应的任务数据
227
+ */
228
+ onDoubleClickSlider?: EventMap["dblclick:slider"];
229
+ /**
230
+ * 任务条右键菜单事件回调
231
+ *
232
+ * @description 当在甘特图中的任务条上右键点击时触发
233
+ * @param e 鼠标事件对象
234
+ * @param data 右键任务条对应的任务数据
235
+ */
236
+ onContextMenuSlider?: EventMap["contextmenu:slider"];
237
+ /**
238
+ * 任务移动事件回调
239
+ *
240
+ * @description 当任务被拖拽移动完成时触发
241
+ * @param data 移动的任务信息数组,包含新旧位置信息
242
+ */
243
+ onMove?: EventMap["move"];
244
+ }
245
+
246
+ /**
247
+ * XGanttReact 组件实例类型
248
+ */
249
+ export declare interface XGanttReactRef {
250
+ /**
251
+ * 获取甘特图核心实例
252
+ *
253
+ * @description
254
+ * 获取底层的 XGantt 核心实例,通过实例可以调用所有核心方法
255
+ *
256
+ * @returns XGantt 核心实例,如果组件未初始化则返回 null
257
+ *
258
+ * @example
259
+ * ```tsx
260
+ * const ganttRef = useRef<XGanttReactRef>(null);
261
+ *
262
+ * const handleGetInstance = () => {
263
+ * const instance = ganttRef.current?.getInstance();
264
+ * if (instance) {
265
+ * // 调用核心实例的方法
266
+ * instance.updateOptions({ unit: 'week' });
267
+ * instance.render();
268
+ * instance.destroy();
269
+ * }
270
+ * };
271
+ * ```
272
+ */
273
+ getInstance: () => XGantt | null;
274
+ /**
275
+ * 跳转到指定日期
276
+ *
277
+ * @description
278
+ * 将甘特图的视图跳转到指定日期位置,如果不传参数则跳转到今天
279
+ *
280
+ * @param date 要跳转的日期,支持多种格式:
281
+ * - 字符串:'2024-06-01'、'2024/06/01'
282
+ * - Date 对象:new Date()
283
+ * - Dayjs 对象:dayjs('2024-06-01')
284
+ * - undefined:跳转到今天
285
+ *
286
+ * @returns 是否成功跳转
287
+ *
288
+ * @example
289
+ * ```tsx
290
+ * const ganttRef = useRef<XGanttReactRef>(null);
291
+ *
292
+ * // 跳转到今天
293
+ * ganttRef.current?.jumpTo();
294
+ *
295
+ * // 跳转到指定日期
296
+ * ganttRef.current?.jumpTo('2024-06-01');
297
+ * ganttRef.current?.jumpTo(new Date());
298
+ * ```
299
+ */
300
+ jumpTo: (date?: any) => boolean;
301
+ }
302
+
303
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,153 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { forwardRef, useRef, useCallback, useImperativeHandle, useEffect } from "react";
3
+ import { XGantt } from "@xpyjs/gantt-core";
4
+ import { colorjs, dayjs, generateId } from "@xpyjs/gantt-core";
5
+ const XGanttReact = forwardRef(
6
+ (props, ref) => {
7
+ const {
8
+ options,
9
+ className,
10
+ style,
11
+ onError,
12
+ onUpdateLink,
13
+ onCreateLink,
14
+ onSelectLink,
15
+ onSelect,
16
+ onClickRow,
17
+ onDoubleClickRow,
18
+ onContextMenuRow,
19
+ onClickSlider,
20
+ onDoubleClickSlider,
21
+ onContextMenuSlider,
22
+ onMove,
23
+ ...restProps
24
+ } = props;
25
+ const containerRef = useRef(null);
26
+ const ganttInstanceRef = useRef(null);
27
+ const registerEventListeners = useCallback(() => {
28
+ const instance = ganttInstanceRef.current;
29
+ if (!instance) return;
30
+ if (onError) {
31
+ instance.on("error", onError);
32
+ }
33
+ if (onUpdateLink) {
34
+ instance.on("update:link", onUpdateLink);
35
+ }
36
+ if (onCreateLink) {
37
+ instance.on("create:link", onCreateLink);
38
+ }
39
+ if (onSelectLink) {
40
+ instance.on("select:link", onSelectLink);
41
+ }
42
+ if (onSelect) {
43
+ instance.on("select", onSelect);
44
+ }
45
+ if (onClickRow) {
46
+ instance.on("click:row", onClickRow);
47
+ }
48
+ if (onDoubleClickRow) {
49
+ instance.on("dblclick:row", onDoubleClickRow);
50
+ }
51
+ if (onContextMenuRow) {
52
+ instance.on("contextmenu:row", onContextMenuRow);
53
+ }
54
+ if (onClickSlider) {
55
+ instance.on("click:slider", onClickSlider);
56
+ }
57
+ if (onDoubleClickSlider) {
58
+ instance.on("dblclick:slider", onDoubleClickSlider);
59
+ }
60
+ if (onContextMenuSlider) {
61
+ instance.on("contextmenu:slider", onContextMenuSlider);
62
+ }
63
+ if (onMove) {
64
+ instance.on("move", onMove);
65
+ }
66
+ }, [
67
+ onError,
68
+ onUpdateLink,
69
+ onCreateLink,
70
+ onSelectLink,
71
+ onSelect,
72
+ onClickRow,
73
+ onDoubleClickRow,
74
+ onContextMenuRow,
75
+ onClickSlider,
76
+ onDoubleClickSlider,
77
+ onContextMenuSlider,
78
+ onMove
79
+ ]);
80
+ const initGantt = useCallback(() => {
81
+ if (!containerRef.current) return;
82
+ ganttInstanceRef.current = new XGantt(containerRef.current, options);
83
+ registerEventListeners();
84
+ }, [options, registerEventListeners]);
85
+ const jumpTo = useCallback((date) => {
86
+ if (ganttInstanceRef.current) {
87
+ return ganttInstanceRef.current.jumpTo(date);
88
+ }
89
+ return false;
90
+ }, []);
91
+ const destroyGantt = useCallback(() => {
92
+ if (ganttInstanceRef.current) {
93
+ ganttInstanceRef.current.destroy();
94
+ ganttInstanceRef.current = null;
95
+ }
96
+ }, []);
97
+ useImperativeHandle(ref, () => ({
98
+ getInstance: () => ganttInstanceRef.current,
99
+ jumpTo
100
+ }), [jumpTo]);
101
+ useEffect(() => {
102
+ initGantt();
103
+ return () => {
104
+ destroyGantt();
105
+ };
106
+ }, []);
107
+ useEffect(() => {
108
+ if (ganttInstanceRef.current) {
109
+ ganttInstanceRef.current.updateOptions(options);
110
+ }
111
+ }, [options]);
112
+ return /* @__PURE__ */ jsx(
113
+ "div",
114
+ {
115
+ ref: containerRef,
116
+ "data-testid": "x-gantt-container",
117
+ className: `x-gantt-container ${className || ""}`,
118
+ style: {
119
+ position: "relative",
120
+ width: "100%",
121
+ height: "100%",
122
+ ...style
123
+ },
124
+ ...restProps
125
+ }
126
+ );
127
+ }
128
+ );
129
+ XGanttReact.displayName = "XGanttReact";
130
+ function useXGantt() {
131
+ const ganttRef = useRef(null);
132
+ const getInstance = useCallback(() => {
133
+ var _a;
134
+ return ((_a = ganttRef.current) == null ? void 0 : _a.getInstance()) || null;
135
+ }, []);
136
+ const jumpTo = useCallback((date) => {
137
+ var _a;
138
+ return ((_a = ganttRef.current) == null ? void 0 : _a.jumpTo(date)) || false;
139
+ }, []);
140
+ return {
141
+ ganttRef,
142
+ getInstance,
143
+ jumpTo
144
+ };
145
+ }
146
+ export {
147
+ XGanttReact,
148
+ colorjs,
149
+ dayjs,
150
+ XGanttReact as default,
151
+ generateId,
152
+ useXGantt
153
+ };
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .x-gantt{--x-gantt-border-color: #e5e5e5}.x-gantt-table-container{flex-shrink:0;box-sizing:border-box;height:100%;overflow:hidden;display:flex;flex-direction:column;width:100%}.x-gantt-table-header{flex-shrink:0;box-sizing:border-box;border-bottom:1px solid var(--x-gantt-border-color)!important;display:flex;flex-direction:row;overflow:hidden;position:relative;flex-wrap:nowrap}.x-gantt-table-header .x-gantt-table-header-cell{position:relative;box-sizing:border-box;overflow:hidden;font-weight:var(--x-gantt-header-font-weight);flex-shrink:0;padding:0 8px}.x-gantt-table-header .x-gantt-table-header-cell.border{border-right:1px solid var(--x-gantt-border-color)!important}.x-gantt-table-header .x-gantt-table-header-cell .x-gantt-column-resize-handle{transition:background-color .2s ease}.x-gantt-table-header .x-gantt-table-header-cell .x-gantt-column-resize-handle:hover{background-color:#0000001a!important}.x-gantt-table-header>div:last-child.x-gantt-table-header-group.border>.x-gantt-table-header-cell.border{border-right:none}.x-gantt-table-header>div:last-child .x-gantt-table-header-group.border>.x-gantt-table-header-cell.border{border-right:none}.x-gantt-table-header>div:last-child.x-gantt-table-header-cell.border{border-right:none}.x-gantt-table-header-group{display:flex;flex-direction:column;box-sizing:border-box}.x-gantt-table-header-group>.x-gantt-table-header-cell{border-bottom:1px solid var(--x-gantt-border-color)!important}.x-gantt-table-header-group>.x-gantt-table-header-cell>.x-gantt-table-header-title{text-align:center}.x-gantt-table-header-children{display:flex;flex-direction:row}.x-gantt-table-body{flex:1;overflow:hidden;box-sizing:border-box;position:relative;width:100%;height:100%}.x-gantt-table-row{box-sizing:border-box}.x-gantt-table-row.hover>.x-gantt-table-cell{background-color:var(--x-gantt-row-hover-color, rgba(0, 0, 0, .05))!important}.x-gantt-table-row.selected>.x-gantt-table-cell{background-color:var(--x-gantt-row-selected-color, rgba(0, 0, 0, .1))!important}.x-gantt-table-cell{box-sizing:border-box;display:inline-block;border-bottom:1px solid var(--x-gantt-border-color)!important;padding:var(--x-gantt-cell-padding, 4px 8px)}.x-gantt-table-cell .x-gantt-table-cell__content{box-sizing:border-box}.x-gantt-table-cell.border{border-right:1px solid var(--x-gantt-border-color)!important}.x-gantt-content-wrapper{width:100%;height:100%;scrollbar-width:none}.x-gantt-content-wrapper::-webkit-scrollbar{display:none}.gantt-scrollbar{position:absolute;z-index:10;opacity:0;transition:opacity .2s ease-in-out;pointer-events:none}.gantt-scrollbar.visible{opacity:1;pointer-events:auto}.gantt-scrollbar-thumb{position:absolute;cursor:pointer;transition:background-color .2s ease-in-out,height .1s ease-out,width .1s ease-out,transform .05s linear}.gantt-scrollbar-vertical{top:0;right:0;bottom:0}.gantt-scrollbar-vertical .gantt-scrollbar-thumb-vertical{top:0;left:0;right:0}.gantt-scrollbar-horizontal{left:0;bottom:0;right:0}.gantt-scrollbar-horizontal .gantt-scrollbar-thumb-horizontal{left:0;top:0;bottom:0}.x-gantt-checkbox{display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--x-gantt-border-color);border-radius:3px;cursor:pointer;transition:all .15s ease-in-out;box-sizing:border-box;-webkit-user-select:none;user-select:none;position:relative;overflow:hidden}.x-gantt-checkbox:focus{outline:none}.x-gantt-checkbox:focus-visible{outline:none}.x-gantt-checkbox__icon svg{transition:all .15s ease-in-out}.x-gantt-checkbox:hover{border-color:var(--x-gantt-primary-color)}.x-gantt{width:100%;height:100%;display:flex;box-sizing:border-box;flex-wrap:nowrap;padding:0;margin:0;overflow:hidden;position:relative}.x-gantt.border{border:1px solid var(--x-gantt-border-color)}
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@xpyjs/gantt-react",
3
+ "version": "0.0.1-alpha.1",
4
+ "private": false,
5
+ "description": "React wrapper for x-gantt",
6
+ "author": "JeremyJone",
7
+ "license": "MIT",
8
+ "type": "module",
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs"
17
+ },
18
+ "./style.css": "./dist/style.css"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "LICENSE",
23
+ "README.md"
24
+ ],
25
+ "dependencies": {
26
+ "@xpyjs/gantt-core": "0.0.1-alpha.1"
27
+ },
28
+ "peerDependencies": {
29
+ "react": ">=16.8.0",
30
+ "react-dom": ">=16.8.0"
31
+ },
32
+ "devDependencies": {
33
+ "@testing-library/jest-dom": "^6.6.3",
34
+ "@testing-library/react": "^16.0.0",
35
+ "@testing-library/user-event": "^14.6.1",
36
+ "@types/react": "^18.3.3",
37
+ "@types/react-dom": "^18.3.0",
38
+ "jsdom": "^26.1.0",
39
+ "react": "^18.3.1",
40
+ "react-dom": "^18.3.1",
41
+ "typescript": "^5.4.5",
42
+ "vite": "^5.2.11",
43
+ "vite-plugin-dts": "^3.9.1",
44
+ "vitest": "^3.2.1"
45
+ },
46
+ "keywords": [
47
+ "gantt",
48
+ "react",
49
+ "react-component",
50
+ "typescript",
51
+ "project-management",
52
+ "schedule",
53
+ "timeline"
54
+ ],
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/xpyjs/gantt.git",
58
+ "directory": "packages/react"
59
+ },
60
+ "homepage": "https://github.com/xpyjs/gantt#readme",
61
+ "bugs": {
62
+ "url": "https://github.com/xpyjs/gantt/issues"
63
+ },
64
+ "scripts": {
65
+ "dev": "tsc && vite build --watch",
66
+ "build": "tsc && vite build",
67
+ "test": "vitest",
68
+ "test:ui": "vitest --ui",
69
+ "coverage": "vitest run --coverage",
70
+ "release": "pnpm publish --access public --no-git-checks"
71
+ }
72
+ }