react-extjs 0.0.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 +21 -0
- package/package.json +36 -0
- package/src/components/AbsoluteLayout.tsx +206 -0
- package/src/components/Accordion.tsx +266 -0
- package/src/components/AnchorLayout.tsx +131 -0
- package/src/components/BorderLayout.tsx +512 -0
- package/src/components/Box.tsx +289 -0
- package/src/components/Button.tsx +300 -0
- package/src/components/ButtonGroup.tsx +170 -0
- package/src/components/CalendarPicker.tsx +431 -0
- package/src/components/CardLayout.tsx +122 -0
- package/src/components/CenterLayout.tsx +95 -0
- package/src/components/CheckboxGroup.tsx +200 -0
- package/src/components/ColorMenu.tsx +195 -0
- package/src/components/ColorPalette.tsx +126 -0
- package/src/components/ColumnLayout.tsx +183 -0
- package/src/components/ColumnTree.tsx +383 -0
- package/src/components/CycleButton.tsx +302 -0
- package/src/components/DataView.tsx +244 -0
- package/src/components/DataViewMore.tsx +337 -0
- package/src/components/DataViewTransition.tsx +235 -0
- package/src/components/DateMenu.tsx +163 -0
- package/src/components/DatePicker.tsx +387 -0
- package/src/components/DisplayField.tsx +73 -0
- package/src/components/Editor.tsx +214 -0
- package/src/components/EditorGrid.tsx +361 -0
- package/src/components/FieldLabeler.tsx +81 -0
- package/src/components/FieldReplicator.tsx +135 -0
- package/src/components/FieldSet.tsx +149 -0
- package/src/components/FitLayout.tsx +76 -0
- package/src/components/Form.tsx +3484 -0
- package/src/components/Grid.tsx +2173 -0
- package/src/components/GridFilters.tsx +332 -0
- package/src/components/GroupTab.tsx +274 -0
- package/src/components/HtmlEditor.tsx +391 -0
- package/src/components/ImageOrganizer.tsx +984 -0
- package/src/components/ImageOrganizerService.ts +361 -0
- package/src/components/ListView.tsx +221 -0
- package/src/components/LoadMask.tsx +74 -0
- package/src/components/Menu.tsx +227 -0
- package/src/components/MessageBox.tsx +138 -0
- package/src/components/MultiSlider.tsx +369 -0
- package/src/components/Organizer.tsx +403 -0
- package/src/components/PagingToolbar.tsx +255 -0
- package/src/components/Panel.tsx +451 -0
- package/src/components/ProgressBar.tsx +127 -0
- package/src/components/PropertyGrid.tsx +142 -0
- package/src/components/QuickTip.tsx +174 -0
- package/src/components/Resizable.tsx +241 -0
- package/src/components/RowLayout.tsx +126 -0
- package/src/components/Slider.tsx +353 -0
- package/src/components/SliderField.tsx +206 -0
- package/src/components/SpinnerField.tsx +141 -0
- package/src/components/SplitBar.tsx +215 -0
- package/src/components/Spotlight.tsx +262 -0
- package/src/components/StatusBar.tsx +118 -0
- package/src/components/TabPanel.tsx +540 -0
- package/src/components/TableLayout.tsx +132 -0
- package/src/components/ThemeSwitcher.tsx +167 -0
- package/src/components/ToolTip.tsx +226 -0
- package/src/components/Toolbar.tsx +321 -0
- package/src/components/Tree.tsx +809 -0
- package/src/components/TreeGrid.tsx +418 -0
- package/src/components/Viewport.tsx +218 -0
- package/src/components/Window.tsx +441 -0
- package/src/components/Writer.tsx +303 -0
- package/src/components/XmlTreeLoader.tsx +233 -0
- package/src/components/dnd/DndContext.tsx +328 -0
- package/src/components/dnd/DragSource.tsx +202 -0
- package/src/components/dnd/DragZone.tsx +66 -0
- package/src/components/dnd/DropTarget.tsx +86 -0
- package/src/components/dnd/DropZone.tsx +166 -0
- package/src/components/dnd/PanelProxy.tsx +81 -0
- package/src/components/dnd/PanelResizer.tsx +143 -0
- package/src/components/dnd/Portal.tsx +254 -0
- package/src/components/dnd/Reorderer.tsx +73 -0
- package/src/components/dnd/ToolbarReorderer.tsx +226 -0
- package/src/main.tsx +2649 -0
- package/src/styles/ext-theme.css +889 -0
- package/src/util/theme.ts +95 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
useImperativeHandle,
|
|
5
|
+
useLayoutEffect,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
type CSSProperties,
|
|
9
|
+
type KeyboardEvent as ReactKeyboardEvent,
|
|
10
|
+
type MouseEvent as ReactMouseEvent,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { createPortal } from 'react-dom';
|
|
13
|
+
|
|
14
|
+
export interface MultiSliderProps {
|
|
15
|
+
/** 受控多值(每个元素对应一个 thumb)。提供时完全由该 prop 决定(对齐 Ext 受控模式)。 */
|
|
16
|
+
values?: number[];
|
|
17
|
+
/** 非受控初值(对齐 Ext value 初始数组)。 */
|
|
18
|
+
defaultValue?: number[];
|
|
19
|
+
minValue?: number;
|
|
20
|
+
maxValue?: number;
|
|
21
|
+
/** 吸附步长,0 表示不吸附(默认 0)。 */
|
|
22
|
+
increment?: number;
|
|
23
|
+
/** 键盘方向键每次步进(默认 1)。 */
|
|
24
|
+
keyIncrement?: number;
|
|
25
|
+
decimalPrecision?: number;
|
|
26
|
+
vertical?: boolean;
|
|
27
|
+
/** 水平滑块宽度 / 垂直滑块高度(对应 Ext 配置项的 content 尺寸)。 */
|
|
28
|
+
width?: number;
|
|
29
|
+
height?: number;
|
|
30
|
+
clickToChange?: boolean;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
cls?: string;
|
|
33
|
+
style?: CSSProperties;
|
|
34
|
+
/** 值变化(拖拽/点击/键盘)时实时回调,参数始终为按 thumb 顺序排列的数组。 */
|
|
35
|
+
onValuesChange?: (values: number[]) => void;
|
|
36
|
+
/** 交互结束(鼠标松开 / 按键完成)时回调(对齐 Ext changecomplete)。 */
|
|
37
|
+
onValuesChangeComplete?: (values: number[]) => void;
|
|
38
|
+
/** 可选 tip:提供时拖动 thumb 会浮出跟随的提示气泡(对齐 Ext.slider.Tip)。
|
|
39
|
+
* 参数为 (index, value, maxValue),返回 HTML 字符串(内部 dangerouslySetInnerHTML 渲染)。 */
|
|
40
|
+
getTipText?: (index: number, value: number, maxValue: number) => string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface MultiSliderHandle {
|
|
44
|
+
getValues: () => number[];
|
|
45
|
+
setValues: (v: number[], animate?: boolean) => void;
|
|
46
|
+
/** 设置某个 thumb 的值(对齐 Ext MultiSlider.setValue(index, value))。 */
|
|
47
|
+
setValue: (index: number, v: number, animate?: boolean) => void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const HALF_THUMB = 7;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 复刻 Ext.slider.MultiSlider(Ext 3.2.1 多滑块 / 区间滑块)。
|
|
54
|
+
* 与 Ext 一致:每个 thumb 独立持有值,values 数组按 thumb 顺序排列(默认不约束交叉,可通过业务层排序实现区间)。
|
|
55
|
+
*
|
|
56
|
+
* DOM:.x-slider.{x-slider-horz|x-slider-vert} > .x-slider-end > .x-slider-inner > (.x-slider-focus + 多个 .x-slider-thumb)
|
|
57
|
+
* 定位公式对齐 Ext:
|
|
58
|
+
* ratio = innerSize / (maxValue - minValue)
|
|
59
|
+
* horizontal: thumb.left = (value - min) * ratio - HALF_THUMB
|
|
60
|
+
* vertical: thumb.bottom = (value - min) * ratio - HALF_THUMB
|
|
61
|
+
* Ext 在 onResize 把 inner 显式设为 dim - 14(两端各 7px padding),React 同样给 inner 设 width/height = dim - 14。
|
|
62
|
+
*/
|
|
63
|
+
export const MultiSlider = forwardRef<MultiSliderHandle, MultiSliderProps>(function MultiSlider(
|
|
64
|
+
{
|
|
65
|
+
values,
|
|
66
|
+
defaultValue = [0, 100],
|
|
67
|
+
minValue = 0,
|
|
68
|
+
maxValue = 100,
|
|
69
|
+
increment = 0,
|
|
70
|
+
keyIncrement = 1,
|
|
71
|
+
decimalPrecision = 0,
|
|
72
|
+
vertical = false,
|
|
73
|
+
width,
|
|
74
|
+
height,
|
|
75
|
+
clickToChange = true,
|
|
76
|
+
disabled = false,
|
|
77
|
+
cls = '',
|
|
78
|
+
style,
|
|
79
|
+
onValuesChange,
|
|
80
|
+
onValuesChangeComplete,
|
|
81
|
+
getTipText,
|
|
82
|
+
},
|
|
83
|
+
ref,
|
|
84
|
+
) {
|
|
85
|
+
const innerRef = useRef<HTMLDivElement>(null);
|
|
86
|
+
const thumbRefs = useRef<(HTMLDivElement | null)[]>([]);
|
|
87
|
+
const dragRef = useRef<number | null>(null); // 正在拖拽的 thumb 索引
|
|
88
|
+
const latestValuesRef = useRef<number[]>(defaultValue);
|
|
89
|
+
|
|
90
|
+
const isControlled = values !== undefined;
|
|
91
|
+
const init = isControlled ? (values as number[]) : defaultValue;
|
|
92
|
+
const [internal, setInternal] = useState<number[]>(init);
|
|
93
|
+
// 拖动期间用本地 dragValues 驱动渲染,使受控模式下 thumb 也能实时跟随鼠标。
|
|
94
|
+
const [dragValues, setDragValues] = useState<number[] | null>(null);
|
|
95
|
+
const current: number[] = dragValues !== null ? dragValues : isControlled ? (values as number[]) : internal;
|
|
96
|
+
|
|
97
|
+
const [innerSize, setInnerSize] = useState(0);
|
|
98
|
+
const [hover, setHover] = useState<number | null>(null);
|
|
99
|
+
const [dragging, setDragging] = useState<number | null>(null);
|
|
100
|
+
const [tipText, setTipText] = useState('');
|
|
101
|
+
const [tipPos, setTipPos] = useState<{ left: number; top: number } | null>(null);
|
|
102
|
+
|
|
103
|
+
useLayoutEffect(() => {
|
|
104
|
+
const el = innerRef.current;
|
|
105
|
+
if (!el) return;
|
|
106
|
+
const measure = () => setInnerSize(vertical ? el.offsetHeight : el.offsetWidth);
|
|
107
|
+
measure();
|
|
108
|
+
const ro = new ResizeObserver(measure);
|
|
109
|
+
ro.observe(el);
|
|
110
|
+
return () => ro.disconnect();
|
|
111
|
+
}, [vertical]);
|
|
112
|
+
|
|
113
|
+
const ratio = innerSize > 0 ? innerSize / (maxValue - minValue || 1) : 0;
|
|
114
|
+
|
|
115
|
+
const normalize = useCallback(
|
|
116
|
+
(v: number) => {
|
|
117
|
+
let nv = v;
|
|
118
|
+
if (increment > 0) {
|
|
119
|
+
nv = Math.round((nv - minValue) / increment) * increment + minValue;
|
|
120
|
+
}
|
|
121
|
+
const p = Math.pow(10, decimalPrecision);
|
|
122
|
+
nv = Math.round(nv * p) / p;
|
|
123
|
+
if (nv < minValue) nv = minValue;
|
|
124
|
+
if (nv > maxValue) nv = maxValue;
|
|
125
|
+
return nv;
|
|
126
|
+
},
|
|
127
|
+
[increment, minValue, maxValue, decimalPrecision],
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const commit = useCallback(
|
|
131
|
+
(next: number[], fireChange = true) => {
|
|
132
|
+
latestValuesRef.current = next;
|
|
133
|
+
if (!isControlled) setInternal(next);
|
|
134
|
+
if (fireChange) onValuesChange?.(next);
|
|
135
|
+
},
|
|
136
|
+
[isControlled, onValuesChange],
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
useImperativeHandle(
|
|
140
|
+
ref,
|
|
141
|
+
() => ({
|
|
142
|
+
getValues: () => latestValuesRef.current,
|
|
143
|
+
setValues: (v: number[]) => commit(v.map(normalize)),
|
|
144
|
+
setValue: (index: number, v: number) => {
|
|
145
|
+
const next = latestValuesRef.current.slice();
|
|
146
|
+
next[index] = normalize(v);
|
|
147
|
+
commit(next);
|
|
148
|
+
},
|
|
149
|
+
}),
|
|
150
|
+
[commit, normalize],
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const posFromEvent = useCallback(
|
|
154
|
+
(clientX: number, clientY: number) => {
|
|
155
|
+
const rect = innerRef.current!.getBoundingClientRect();
|
|
156
|
+
return vertical ? rect.height - (clientY - rect.top) : clientX - rect.left;
|
|
157
|
+
},
|
|
158
|
+
[vertical],
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const startDrag = useCallback(
|
|
162
|
+
(index: number) => {
|
|
163
|
+
if (disabled || ratio === 0) return;
|
|
164
|
+
dragRef.current = index;
|
|
165
|
+
setDragging(index);
|
|
166
|
+
const updateTip = () => {
|
|
167
|
+
if (!getTipText || !thumbRefs.current[index]) return;
|
|
168
|
+
const r = thumbRefs.current[index]!.getBoundingClientRect();
|
|
169
|
+
setTipText(getTipText(index, latestValuesRef.current[index], maxValue));
|
|
170
|
+
setTipPos({ left: r.left + r.width / 2, top: r.top - 10 });
|
|
171
|
+
};
|
|
172
|
+
updateTip();
|
|
173
|
+
const move = (ev: MouseEvent) => {
|
|
174
|
+
if (dragRef.current !== index) return;
|
|
175
|
+
const pos = posFromEvent(ev.clientX, ev.clientY);
|
|
176
|
+
const nv = normalize(minValue + pos / ratio);
|
|
177
|
+
const next = latestValuesRef.current.slice();
|
|
178
|
+
next[index] = nv;
|
|
179
|
+
setDragValues(next);
|
|
180
|
+
latestValuesRef.current = next;
|
|
181
|
+
onValuesChange?.(next);
|
|
182
|
+
updateTip();
|
|
183
|
+
};
|
|
184
|
+
const up = () => {
|
|
185
|
+
dragRef.current = null;
|
|
186
|
+
setDragging(null);
|
|
187
|
+
// 非受控模式下把最终值固化进 internal,否则 dragValues 清空后 current 回退到初值(对齐 Ext 拖拽持久化)。
|
|
188
|
+
commit(latestValuesRef.current);
|
|
189
|
+
setDragValues(null);
|
|
190
|
+
setTipPos(null);
|
|
191
|
+
window.removeEventListener('mousemove', move);
|
|
192
|
+
window.removeEventListener('mouseup', up);
|
|
193
|
+
onValuesChangeComplete?.(latestValuesRef.current);
|
|
194
|
+
};
|
|
195
|
+
window.addEventListener('mousemove', move);
|
|
196
|
+
window.addEventListener('mouseup', up);
|
|
197
|
+
},
|
|
198
|
+
[disabled, ratio, getTipText, maxValue, posFromEvent, normalize, minValue, onValuesChange, onValuesChangeComplete],
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const onThumbMouseDown = useCallback(
|
|
202
|
+
(e: ReactMouseEvent, index: number) => {
|
|
203
|
+
if (disabled) return;
|
|
204
|
+
e.preventDefault();
|
|
205
|
+
startDrag(index);
|
|
206
|
+
},
|
|
207
|
+
[disabled, startDrag],
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const onKeyDown = useCallback(
|
|
211
|
+
(e: ReactKeyboardEvent, index: number) => {
|
|
212
|
+
if (disabled) return;
|
|
213
|
+
const cur = latestValuesRef.current[index];
|
|
214
|
+
let v: number | null = null;
|
|
215
|
+
switch (e.key) {
|
|
216
|
+
case 'ArrowUp':
|
|
217
|
+
case 'ArrowRight':
|
|
218
|
+
e.preventDefault();
|
|
219
|
+
v = e.ctrlKey ? maxValue : cur + keyIncrement;
|
|
220
|
+
break;
|
|
221
|
+
case 'ArrowDown':
|
|
222
|
+
case 'ArrowLeft':
|
|
223
|
+
e.preventDefault();
|
|
224
|
+
v = e.ctrlKey ? minValue : cur - keyIncrement;
|
|
225
|
+
break;
|
|
226
|
+
case 'Home':
|
|
227
|
+
e.preventDefault();
|
|
228
|
+
v = minValue;
|
|
229
|
+
break;
|
|
230
|
+
case 'End':
|
|
231
|
+
e.preventDefault();
|
|
232
|
+
v = maxValue;
|
|
233
|
+
break;
|
|
234
|
+
case 'PageUp':
|
|
235
|
+
e.preventDefault();
|
|
236
|
+
v = cur + keyIncrement * 10;
|
|
237
|
+
break;
|
|
238
|
+
case 'PageDown':
|
|
239
|
+
e.preventDefault();
|
|
240
|
+
v = cur - keyIncrement * 10;
|
|
241
|
+
break;
|
|
242
|
+
default:
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const next = latestValuesRef.current.slice();
|
|
246
|
+
next[index] = normalize(v);
|
|
247
|
+
commit(next);
|
|
248
|
+
onValuesChangeComplete?.(next);
|
|
249
|
+
},
|
|
250
|
+
[disabled, maxValue, keyIncrement, minValue, normalize, commit, onValuesChangeComplete],
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const onTrackMouseDown = useCallback(
|
|
254
|
+
(e: ReactMouseEvent) => {
|
|
255
|
+
if (disabled || ratio === 0) return;
|
|
256
|
+
const target = e.target as HTMLElement;
|
|
257
|
+
// 命中某个 thumb 时交由 thumb 的 mousedown 处理(避免重复触发)。
|
|
258
|
+
if (thumbRefs.current.some((t) => t != null && t.contains(target))) return;
|
|
259
|
+
if (!clickToChange) return;
|
|
260
|
+
const pos = posFromEvent(e.clientX, e.clientY);
|
|
261
|
+
const clicked = minValue + pos / ratio;
|
|
262
|
+
// 点击轨道:移动「最近」的那个 thumb(对齐 Ext MultiSlider 行为)。
|
|
263
|
+
let nearest = 0;
|
|
264
|
+
let best = Infinity;
|
|
265
|
+
current.forEach((val, i) => {
|
|
266
|
+
const d = Math.abs(val - clicked);
|
|
267
|
+
if (d < best) {
|
|
268
|
+
best = d;
|
|
269
|
+
nearest = i;
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
const next = current.slice();
|
|
273
|
+
next[nearest] = normalize(clicked);
|
|
274
|
+
commit(next);
|
|
275
|
+
onValuesChangeComplete?.(next);
|
|
276
|
+
},
|
|
277
|
+
[disabled, ratio, clickToChange, posFromEvent, minValue, current, normalize, commit, onValuesChangeComplete],
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const rootClass = [
|
|
281
|
+
'x-slider',
|
|
282
|
+
'x-multi-slider',
|
|
283
|
+
vertical ? 'x-slider-vert' : 'x-slider-horz',
|
|
284
|
+
disabled ? 'x-slider-disabled' : '',
|
|
285
|
+
cls,
|
|
286
|
+
]
|
|
287
|
+
.filter(Boolean)
|
|
288
|
+
.join(' ');
|
|
289
|
+
|
|
290
|
+
const dim = vertical ? height : width;
|
|
291
|
+
const innerDim = dim != null ? dim - 14 : undefined;
|
|
292
|
+
const rootStyle: CSSProperties = {
|
|
293
|
+
boxSizing: 'border-box',
|
|
294
|
+
...(vertical ? (height != null ? { height } : {}) : width != null ? { width } : {}),
|
|
295
|
+
...style,
|
|
296
|
+
};
|
|
297
|
+
const innerStyle: CSSProperties = vertical
|
|
298
|
+
? innerDim != null
|
|
299
|
+
? { height: innerDim }
|
|
300
|
+
: {}
|
|
301
|
+
: innerDim != null
|
|
302
|
+
? { width: innerDim }
|
|
303
|
+
: {};
|
|
304
|
+
|
|
305
|
+
return (
|
|
306
|
+
<>
|
|
307
|
+
<div
|
|
308
|
+
className={rootClass}
|
|
309
|
+
style={rootStyle}
|
|
310
|
+
data-values={current.join(',')}
|
|
311
|
+
tabIndex={disabled ? -1 : 0}
|
|
312
|
+
onMouseDown={onTrackMouseDown}
|
|
313
|
+
>
|
|
314
|
+
<div className="x-slider-end">
|
|
315
|
+
<div className="x-slider-inner" ref={innerRef} style={innerStyle}>
|
|
316
|
+
<a className="x-slider-focus" href="#" tabIndex={-1} />
|
|
317
|
+
{current.map((val, i) => {
|
|
318
|
+
const thumbPos = ratio > 0 ? (val - minValue) * ratio - HALF_THUMB : 0;
|
|
319
|
+
const thumbStyle: CSSProperties = vertical
|
|
320
|
+
? { bottom: `${thumbPos}px` }
|
|
321
|
+
: { left: `${thumbPos}px` };
|
|
322
|
+
const thumbClass = [
|
|
323
|
+
'x-slider-thumb',
|
|
324
|
+
hover === i ? 'x-slider-thumb-over' : '',
|
|
325
|
+
dragging === i ? 'x-slider-thumb-drag' : '',
|
|
326
|
+
]
|
|
327
|
+
.filter(Boolean)
|
|
328
|
+
.join(' ');
|
|
329
|
+
return (
|
|
330
|
+
<div
|
|
331
|
+
key={i}
|
|
332
|
+
ref={(el) => {
|
|
333
|
+
thumbRefs.current[i] = el;
|
|
334
|
+
}}
|
|
335
|
+
className={thumbClass}
|
|
336
|
+
style={thumbStyle}
|
|
337
|
+
tabIndex={disabled ? -1 : 0}
|
|
338
|
+
onMouseDown={(e) => onThumbMouseDown(e, i)}
|
|
339
|
+
onMouseEnter={() => setHover(i)}
|
|
340
|
+
onMouseLeave={() => setHover((h) => (h === i ? null : h))}
|
|
341
|
+
onKeyDown={(e) => onKeyDown(e, i)}
|
|
342
|
+
/>
|
|
343
|
+
);
|
|
344
|
+
})}
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
{tipPos && getTipText && createPortal(
|
|
349
|
+
<div
|
|
350
|
+
className="x-tip"
|
|
351
|
+
style={{ position: 'fixed', left: tipPos.left, top: tipPos.top, visibility: 'visible', zIndex: 20001 }}
|
|
352
|
+
>
|
|
353
|
+
<div className="x-tip-tl"><div className="x-tip-tr"><div className="x-tip-tc" /></div></div>
|
|
354
|
+
<div className="x-tip-bwrap">
|
|
355
|
+
<div className="x-tip-ml"><div className="x-tip-mr"><div className="x-tip-mc">
|
|
356
|
+
<div className="x-tip-body" dangerouslySetInnerHTML={{ __html: tipText }} />
|
|
357
|
+
</div></div></div>
|
|
358
|
+
</div>
|
|
359
|
+
<div className="x-tip-bl"><div className="x-tip-br"><div className="x-tip-bc" /></div></div>
|
|
360
|
+
<div
|
|
361
|
+
className="x-tip-anchor x-tip-anchor-bottom"
|
|
362
|
+
style={{ left: '50%', marginLeft: -4, bottom: -9 }}
|
|
363
|
+
/>
|
|
364
|
+
</div>,
|
|
365
|
+
document.body,
|
|
366
|
+
)}
|
|
367
|
+
</>
|
|
368
|
+
);
|
|
369
|
+
});
|