@gm-pc/tour 1.27.0 → 1.27.1-beta.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/README.md +11 -11
- package/package.json +5 -5
- package/src/components/action.tsx +29 -29
- package/src/components/guide.tsx +140 -140
- package/src/components/index.ts +1 -1
- package/src/components/portal.tsx +23 -23
- package/src/components/svg_mask.tsx +168 -168
- package/src/hook.ts +19 -19
- package/src/index.ts +2 -2
- package/src/reducer.ts +55 -55
- package/src/stories.tsx +310 -310
- package/src/tour.tsx +276 -276
- package/src/types.ts +52 -52
- package/src/utils.ts +172 -172
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
import React, { FC, MouseEvent } from 'react'
|
|
2
|
-
import { safe } from '../utils'
|
|
3
|
-
|
|
4
|
-
interface SvgMaskProps {
|
|
5
|
-
windowWidth: number
|
|
6
|
-
windowHeight: number
|
|
7
|
-
targetWidth: number
|
|
8
|
-
targetHeight: number
|
|
9
|
-
targetTop: number
|
|
10
|
-
targetLeft: number
|
|
11
|
-
padding: number
|
|
12
|
-
rounded: number
|
|
13
|
-
disableInteraction?: boolean
|
|
14
|
-
disableInteractionClassName?: string
|
|
15
|
-
className?: string
|
|
16
|
-
onClick?(event: MouseEvent<HTMLDivElement>): void
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const SvgMask: FC<SvgMaskProps> = ({
|
|
20
|
-
windowWidth,
|
|
21
|
-
windowHeight,
|
|
22
|
-
targetWidth,
|
|
23
|
-
targetHeight,
|
|
24
|
-
targetTop,
|
|
25
|
-
targetLeft,
|
|
26
|
-
padding,
|
|
27
|
-
rounded,
|
|
28
|
-
disableInteraction,
|
|
29
|
-
disableInteractionClassName,
|
|
30
|
-
className,
|
|
31
|
-
onClick,
|
|
32
|
-
}) => {
|
|
33
|
-
const width = safe(targetWidth + padding * 2)
|
|
34
|
-
const height = safe(targetHeight + padding * 2)
|
|
35
|
-
const top = safe(targetTop - padding)
|
|
36
|
-
const left = safe(targetLeft - padding)
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<div
|
|
40
|
-
onClick={onClick}
|
|
41
|
-
style={{
|
|
42
|
-
opacity: '0.7',
|
|
43
|
-
width: '100%',
|
|
44
|
-
left: 0,
|
|
45
|
-
top: 0,
|
|
46
|
-
height: '100%',
|
|
47
|
-
position: 'fixed',
|
|
48
|
-
zIndex: 99999,
|
|
49
|
-
pointerEvents: 'none',
|
|
50
|
-
color: '#000',
|
|
51
|
-
}}
|
|
52
|
-
>
|
|
53
|
-
<svg
|
|
54
|
-
width={windowWidth}
|
|
55
|
-
height={windowHeight}
|
|
56
|
-
xmlns='http://www.w3.org/2000/svg'
|
|
57
|
-
className={className}
|
|
58
|
-
>
|
|
59
|
-
<defs>
|
|
60
|
-
<mask id='mask-main'>
|
|
61
|
-
<rect x={0} y={0} width={windowWidth} height={windowHeight} fill='white' />
|
|
62
|
-
<rect x={left} y={top} width={width} height={height} fill='black' />
|
|
63
|
-
{/* top left rounded corner */}
|
|
64
|
-
<rect
|
|
65
|
-
x={left - 1}
|
|
66
|
-
y={top - 1}
|
|
67
|
-
width={rounded}
|
|
68
|
-
height={rounded}
|
|
69
|
-
fill='white'
|
|
70
|
-
/>
|
|
71
|
-
<circle cx={left + rounded} cy={top + rounded} r={rounded} fill='black' />
|
|
72
|
-
{/* top right rounded corner */}
|
|
73
|
-
<rect
|
|
74
|
-
x={left + width - rounded + 1}
|
|
75
|
-
y={top - 1}
|
|
76
|
-
width={rounded}
|
|
77
|
-
height={rounded}
|
|
78
|
-
fill='white'
|
|
79
|
-
/>
|
|
80
|
-
<circle
|
|
81
|
-
cx={left + width - rounded}
|
|
82
|
-
cy={top + rounded}
|
|
83
|
-
r={rounded}
|
|
84
|
-
fill='black'
|
|
85
|
-
/>
|
|
86
|
-
{/* bottom left rounded corner */}
|
|
87
|
-
<rect
|
|
88
|
-
x={left - 1}
|
|
89
|
-
y={top + height - rounded + 1}
|
|
90
|
-
width={rounded}
|
|
91
|
-
height={rounded}
|
|
92
|
-
fill='white'
|
|
93
|
-
/>
|
|
94
|
-
<circle
|
|
95
|
-
cx={left + rounded}
|
|
96
|
-
cy={top + height - rounded}
|
|
97
|
-
r={rounded}
|
|
98
|
-
fill='black'
|
|
99
|
-
/>
|
|
100
|
-
{/* bottom right rounded corner */}
|
|
101
|
-
<rect
|
|
102
|
-
x={left + width - rounded + 1}
|
|
103
|
-
y={top + height - rounded + 1}
|
|
104
|
-
width={rounded}
|
|
105
|
-
height={rounded}
|
|
106
|
-
fill='white'
|
|
107
|
-
/>
|
|
108
|
-
<circle
|
|
109
|
-
cx={left + width - rounded}
|
|
110
|
-
cy={top + height - rounded}
|
|
111
|
-
r={rounded}
|
|
112
|
-
fill='black '
|
|
113
|
-
/>
|
|
114
|
-
</mask>
|
|
115
|
-
<clipPath id='clip-path'>
|
|
116
|
-
{/* top */}
|
|
117
|
-
<rect x={0} y={0} width={windowWidth} height={top} />
|
|
118
|
-
{/* left */}
|
|
119
|
-
<rect x={0} y={top} width={left} height={height} />
|
|
120
|
-
{/* right */}
|
|
121
|
-
<rect
|
|
122
|
-
x={targetLeft + targetWidth + padding}
|
|
123
|
-
y={top}
|
|
124
|
-
width={safe(windowWidth - targetWidth - left)}
|
|
125
|
-
height={height}
|
|
126
|
-
/>
|
|
127
|
-
{/* bottom */}
|
|
128
|
-
<rect
|
|
129
|
-
x={0}
|
|
130
|
-
y={targetTop + targetHeight + padding}
|
|
131
|
-
width={windowWidth}
|
|
132
|
-
height={safe(windowHeight - targetHeight - top)}
|
|
133
|
-
/>
|
|
134
|
-
</clipPath>
|
|
135
|
-
</defs>
|
|
136
|
-
<rect
|
|
137
|
-
x={0}
|
|
138
|
-
y={0}
|
|
139
|
-
width={windowWidth}
|
|
140
|
-
height={windowHeight}
|
|
141
|
-
fill='currentColor'
|
|
142
|
-
mask='url(#mask-main)'
|
|
143
|
-
/>
|
|
144
|
-
<rect
|
|
145
|
-
x={0}
|
|
146
|
-
y={0}
|
|
147
|
-
width={windowWidth}
|
|
148
|
-
height={windowHeight}
|
|
149
|
-
fill='currentColor'
|
|
150
|
-
clipPath='url(#clip-path)'
|
|
151
|
-
pointerEvents='auto'
|
|
152
|
-
/>
|
|
153
|
-
<rect
|
|
154
|
-
x={left}
|
|
155
|
-
y={top}
|
|
156
|
-
width={width}
|
|
157
|
-
height={height}
|
|
158
|
-
pointerEvents='auto'
|
|
159
|
-
fill='transparent'
|
|
160
|
-
display={disableInteraction ? 'block' : 'none'}
|
|
161
|
-
className={disableInteractionClassName}
|
|
162
|
-
/>
|
|
163
|
-
</svg>
|
|
164
|
-
</div>
|
|
165
|
-
)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export default SvgMask
|
|
1
|
+
import React, { FC, MouseEvent } from 'react'
|
|
2
|
+
import { safe } from '../utils'
|
|
3
|
+
|
|
4
|
+
interface SvgMaskProps {
|
|
5
|
+
windowWidth: number
|
|
6
|
+
windowHeight: number
|
|
7
|
+
targetWidth: number
|
|
8
|
+
targetHeight: number
|
|
9
|
+
targetTop: number
|
|
10
|
+
targetLeft: number
|
|
11
|
+
padding: number
|
|
12
|
+
rounded: number
|
|
13
|
+
disableInteraction?: boolean
|
|
14
|
+
disableInteractionClassName?: string
|
|
15
|
+
className?: string
|
|
16
|
+
onClick?(event: MouseEvent<HTMLDivElement>): void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const SvgMask: FC<SvgMaskProps> = ({
|
|
20
|
+
windowWidth,
|
|
21
|
+
windowHeight,
|
|
22
|
+
targetWidth,
|
|
23
|
+
targetHeight,
|
|
24
|
+
targetTop,
|
|
25
|
+
targetLeft,
|
|
26
|
+
padding,
|
|
27
|
+
rounded,
|
|
28
|
+
disableInteraction,
|
|
29
|
+
disableInteractionClassName,
|
|
30
|
+
className,
|
|
31
|
+
onClick,
|
|
32
|
+
}) => {
|
|
33
|
+
const width = safe(targetWidth + padding * 2)
|
|
34
|
+
const height = safe(targetHeight + padding * 2)
|
|
35
|
+
const top = safe(targetTop - padding)
|
|
36
|
+
const left = safe(targetLeft - padding)
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
onClick={onClick}
|
|
41
|
+
style={{
|
|
42
|
+
opacity: '0.7',
|
|
43
|
+
width: '100%',
|
|
44
|
+
left: 0,
|
|
45
|
+
top: 0,
|
|
46
|
+
height: '100%',
|
|
47
|
+
position: 'fixed',
|
|
48
|
+
zIndex: 99999,
|
|
49
|
+
pointerEvents: 'none',
|
|
50
|
+
color: '#000',
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<svg
|
|
54
|
+
width={windowWidth}
|
|
55
|
+
height={windowHeight}
|
|
56
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
57
|
+
className={className}
|
|
58
|
+
>
|
|
59
|
+
<defs>
|
|
60
|
+
<mask id='mask-main'>
|
|
61
|
+
<rect x={0} y={0} width={windowWidth} height={windowHeight} fill='white' />
|
|
62
|
+
<rect x={left} y={top} width={width} height={height} fill='black' />
|
|
63
|
+
{/* top left rounded corner */}
|
|
64
|
+
<rect
|
|
65
|
+
x={left - 1}
|
|
66
|
+
y={top - 1}
|
|
67
|
+
width={rounded}
|
|
68
|
+
height={rounded}
|
|
69
|
+
fill='white'
|
|
70
|
+
/>
|
|
71
|
+
<circle cx={left + rounded} cy={top + rounded} r={rounded} fill='black' />
|
|
72
|
+
{/* top right rounded corner */}
|
|
73
|
+
<rect
|
|
74
|
+
x={left + width - rounded + 1}
|
|
75
|
+
y={top - 1}
|
|
76
|
+
width={rounded}
|
|
77
|
+
height={rounded}
|
|
78
|
+
fill='white'
|
|
79
|
+
/>
|
|
80
|
+
<circle
|
|
81
|
+
cx={left + width - rounded}
|
|
82
|
+
cy={top + rounded}
|
|
83
|
+
r={rounded}
|
|
84
|
+
fill='black'
|
|
85
|
+
/>
|
|
86
|
+
{/* bottom left rounded corner */}
|
|
87
|
+
<rect
|
|
88
|
+
x={left - 1}
|
|
89
|
+
y={top + height - rounded + 1}
|
|
90
|
+
width={rounded}
|
|
91
|
+
height={rounded}
|
|
92
|
+
fill='white'
|
|
93
|
+
/>
|
|
94
|
+
<circle
|
|
95
|
+
cx={left + rounded}
|
|
96
|
+
cy={top + height - rounded}
|
|
97
|
+
r={rounded}
|
|
98
|
+
fill='black'
|
|
99
|
+
/>
|
|
100
|
+
{/* bottom right rounded corner */}
|
|
101
|
+
<rect
|
|
102
|
+
x={left + width - rounded + 1}
|
|
103
|
+
y={top + height - rounded + 1}
|
|
104
|
+
width={rounded}
|
|
105
|
+
height={rounded}
|
|
106
|
+
fill='white'
|
|
107
|
+
/>
|
|
108
|
+
<circle
|
|
109
|
+
cx={left + width - rounded}
|
|
110
|
+
cy={top + height - rounded}
|
|
111
|
+
r={rounded}
|
|
112
|
+
fill='black '
|
|
113
|
+
/>
|
|
114
|
+
</mask>
|
|
115
|
+
<clipPath id='clip-path'>
|
|
116
|
+
{/* top */}
|
|
117
|
+
<rect x={0} y={0} width={windowWidth} height={top} />
|
|
118
|
+
{/* left */}
|
|
119
|
+
<rect x={0} y={top} width={left} height={height} />
|
|
120
|
+
{/* right */}
|
|
121
|
+
<rect
|
|
122
|
+
x={targetLeft + targetWidth + padding}
|
|
123
|
+
y={top}
|
|
124
|
+
width={safe(windowWidth - targetWidth - left)}
|
|
125
|
+
height={height}
|
|
126
|
+
/>
|
|
127
|
+
{/* bottom */}
|
|
128
|
+
<rect
|
|
129
|
+
x={0}
|
|
130
|
+
y={targetTop + targetHeight + padding}
|
|
131
|
+
width={windowWidth}
|
|
132
|
+
height={safe(windowHeight - targetHeight - top)}
|
|
133
|
+
/>
|
|
134
|
+
</clipPath>
|
|
135
|
+
</defs>
|
|
136
|
+
<rect
|
|
137
|
+
x={0}
|
|
138
|
+
y={0}
|
|
139
|
+
width={windowWidth}
|
|
140
|
+
height={windowHeight}
|
|
141
|
+
fill='currentColor'
|
|
142
|
+
mask='url(#mask-main)'
|
|
143
|
+
/>
|
|
144
|
+
<rect
|
|
145
|
+
x={0}
|
|
146
|
+
y={0}
|
|
147
|
+
width={windowWidth}
|
|
148
|
+
height={windowHeight}
|
|
149
|
+
fill='currentColor'
|
|
150
|
+
clipPath='url(#clip-path)'
|
|
151
|
+
pointerEvents='auto'
|
|
152
|
+
/>
|
|
153
|
+
<rect
|
|
154
|
+
x={left}
|
|
155
|
+
y={top}
|
|
156
|
+
width={width}
|
|
157
|
+
height={height}
|
|
158
|
+
pointerEvents='auto'
|
|
159
|
+
fill='transparent'
|
|
160
|
+
display={disableInteraction ? 'block' : 'none'}
|
|
161
|
+
className={disableInteractionClassName}
|
|
162
|
+
/>
|
|
163
|
+
</svg>
|
|
164
|
+
</div>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export default SvgMask
|
package/src/hook.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { MutableRefObject, useEffect } from 'react'
|
|
2
|
-
|
|
3
|
-
function useMutationObserver(
|
|
4
|
-
ref: MutableRefObject<HTMLDivElement | undefined>,
|
|
5
|
-
callback: MutationCallback,
|
|
6
|
-
options = { attributes: true, characterData: true, subtree: true, childList: true }
|
|
7
|
-
) {
|
|
8
|
-
useEffect((): void | (() => void) => {
|
|
9
|
-
if (ref.current) {
|
|
10
|
-
const observer = new window.MutationObserver(callback)
|
|
11
|
-
observer.observe(ref.current, options)
|
|
12
|
-
return () => {
|
|
13
|
-
observer.disconnect()
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}, [ref, callback, options])
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export { useMutationObserver }
|
|
1
|
+
import { MutableRefObject, useEffect } from 'react'
|
|
2
|
+
|
|
3
|
+
function useMutationObserver(
|
|
4
|
+
ref: MutableRefObject<HTMLDivElement | undefined>,
|
|
5
|
+
callback: MutationCallback,
|
|
6
|
+
options = { attributes: true, characterData: true, subtree: true, childList: true }
|
|
7
|
+
) {
|
|
8
|
+
useEffect((): void | (() => void) => {
|
|
9
|
+
if (ref.current) {
|
|
10
|
+
const observer = new window.MutationObserver(callback)
|
|
11
|
+
observer.observe(ref.current, options)
|
|
12
|
+
return () => {
|
|
13
|
+
observer.disconnect()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}, [ref, callback, options])
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { useMutationObserver }
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as Tour } from './tour'
|
|
2
|
-
export type { TourProps, TourStepItem } from './types'
|
|
1
|
+
export { default as Tour } from './tour'
|
|
2
|
+
export type { TourProps, TourStepItem } from './types'
|
package/src/reducer.ts
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
interface ReducerState {
|
|
2
|
-
top: number
|
|
3
|
-
right: number
|
|
4
|
-
bottom: number
|
|
5
|
-
left: number
|
|
6
|
-
width: number
|
|
7
|
-
height: number
|
|
8
|
-
w: number
|
|
9
|
-
h: number
|
|
10
|
-
helperWidth?: number
|
|
11
|
-
helperHeight?: number
|
|
12
|
-
helperPosition?: 'top' | 'right' | 'bottom' | 'left' | 'center'
|
|
13
|
-
inDOM?: boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface ReducerAction extends Partial<ReducerState> {
|
|
17
|
-
type: 'HAS_DOM_NODE' | 'NO_DOM_NODE'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const initialState: ReducerState = {
|
|
21
|
-
top: 0,
|
|
22
|
-
right: 0,
|
|
23
|
-
bottom: 0,
|
|
24
|
-
left: 0,
|
|
25
|
-
width: 0,
|
|
26
|
-
height: 0,
|
|
27
|
-
w: 0,
|
|
28
|
-
h: 0,
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export default function (state: ReducerState, action: ReducerAction): ReducerState {
|
|
32
|
-
switch (action.type) {
|
|
33
|
-
case 'HAS_DOM_NODE':
|
|
34
|
-
// @ts-ignore
|
|
35
|
-
delete action.type
|
|
36
|
-
return { ...state, ...action }
|
|
37
|
-
case 'NO_DOM_NODE':
|
|
38
|
-
return {
|
|
39
|
-
...state,
|
|
40
|
-
top: state.h + 10,
|
|
41
|
-
right: state.w / 2 + 9,
|
|
42
|
-
bottom: state.h / 2 + 9,
|
|
43
|
-
left: action.w! / 2 - (state.helperWidth ? state.helperWidth / 2 : 0),
|
|
44
|
-
width: 0,
|
|
45
|
-
height: 0,
|
|
46
|
-
w: action.w!,
|
|
47
|
-
h: action.h!,
|
|
48
|
-
helperPosition: 'center',
|
|
49
|
-
}
|
|
50
|
-
default:
|
|
51
|
-
return state
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export type { ReducerAction, ReducerState }
|
|
1
|
+
interface ReducerState {
|
|
2
|
+
top: number
|
|
3
|
+
right: number
|
|
4
|
+
bottom: number
|
|
5
|
+
left: number
|
|
6
|
+
width: number
|
|
7
|
+
height: number
|
|
8
|
+
w: number
|
|
9
|
+
h: number
|
|
10
|
+
helperWidth?: number
|
|
11
|
+
helperHeight?: number
|
|
12
|
+
helperPosition?: 'top' | 'right' | 'bottom' | 'left' | 'center'
|
|
13
|
+
inDOM?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ReducerAction extends Partial<ReducerState> {
|
|
17
|
+
type: 'HAS_DOM_NODE' | 'NO_DOM_NODE'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const initialState: ReducerState = {
|
|
21
|
+
top: 0,
|
|
22
|
+
right: 0,
|
|
23
|
+
bottom: 0,
|
|
24
|
+
left: 0,
|
|
25
|
+
width: 0,
|
|
26
|
+
height: 0,
|
|
27
|
+
w: 0,
|
|
28
|
+
h: 0,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default function (state: ReducerState, action: ReducerAction): ReducerState {
|
|
32
|
+
switch (action.type) {
|
|
33
|
+
case 'HAS_DOM_NODE':
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
delete action.type
|
|
36
|
+
return { ...state, ...action }
|
|
37
|
+
case 'NO_DOM_NODE':
|
|
38
|
+
return {
|
|
39
|
+
...state,
|
|
40
|
+
top: state.h + 10,
|
|
41
|
+
right: state.w / 2 + 9,
|
|
42
|
+
bottom: state.h / 2 + 9,
|
|
43
|
+
left: action.w! / 2 - (state.helperWidth ? state.helperWidth / 2 : 0),
|
|
44
|
+
width: 0,
|
|
45
|
+
height: 0,
|
|
46
|
+
w: action.w!,
|
|
47
|
+
h: action.h!,
|
|
48
|
+
helperPosition: 'center',
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
return state
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type { ReducerAction, ReducerState }
|