ontheway-sdk 0.1.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 +110 -0
- package/dist/checklist.cjs +319 -0
- package/dist/checklist.cjs.map +1 -0
- package/dist/checklist.d.cts +58 -0
- package/dist/checklist.d.ts +58 -0
- package/dist/checklist.js +314 -0
- package/dist/checklist.js.map +1 -0
- package/dist/chunk-254YHUN3.cjs +26 -0
- package/dist/chunk-254YHUN3.cjs.map +1 -0
- package/dist/chunk-DDAAVRWG.js +23 -0
- package/dist/chunk-DDAAVRWG.js.map +1 -0
- package/dist/chunk-NRUQU5AR.cjs +94 -0
- package/dist/chunk-NRUQU5AR.cjs.map +1 -0
- package/dist/chunk-OKJ5GEH3.js +358 -0
- package/dist/chunk-OKJ5GEH3.js.map +1 -0
- package/dist/chunk-RNQLNLNI.js +91 -0
- package/dist/chunk-RNQLNLNI.js.map +1 -0
- package/dist/chunk-UE3T6TSM.cjs +361 -0
- package/dist/chunk-UE3T6TSM.cjs.map +1 -0
- package/dist/components.cjs +211 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.cts +51 -0
- package/dist/components.d.ts +51 -0
- package/dist/components.js +205 -0
- package/dist/components.js.map +1 -0
- package/dist/devtools.cjs +733 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +18 -0
- package/dist/devtools.d.ts +18 -0
- package/dist/devtools.js +727 -0
- package/dist/devtools.js.map +1 -0
- package/dist/index.cjs +19 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +163 -0
- package/dist/index.d.ts +163 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +18 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +68 -0
- package/dist/react.d.ts +68 -0
- package/dist/react.js +5 -0
- package/dist/react.js.map +1 -0
- package/package.json +93 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface HelpMenuProps {
|
|
4
|
+
/** 按钮文字,默认 "?" */
|
|
5
|
+
label?: string | React.ReactNode;
|
|
6
|
+
/** 菜单标题 */
|
|
7
|
+
title?: string;
|
|
8
|
+
/** 自定义位置 */
|
|
9
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
10
|
+
/** 自定义样式类 */
|
|
11
|
+
className?: string;
|
|
12
|
+
/** 自定义按钮样式类 */
|
|
13
|
+
buttonClassName?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 帮助菜单组件 - 显示所有可用的 onboarding 任务
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* // 基础用法
|
|
21
|
+
* <HelpMenu />
|
|
22
|
+
*
|
|
23
|
+
* // 自定义
|
|
24
|
+
* <HelpMenu label="Need help?" title="Guides" position="bottom-left" />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
declare function HelpMenu({ label, title, position, className, buttonClassName, }: HelpMenuProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
interface HelpTriggerProps {
|
|
29
|
+
/** 要触发的任务 slug */
|
|
30
|
+
taskSlug: string;
|
|
31
|
+
children: React.ReactNode;
|
|
32
|
+
className?: string;
|
|
33
|
+
style?: React.CSSProperties;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 内联触发按钮 - 包裹任何元素,点击启动指定任务
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* <HelpTrigger taskSlug="welcome">
|
|
41
|
+
* <button>Show Tour</button>
|
|
42
|
+
* </HelpTrigger>
|
|
43
|
+
*
|
|
44
|
+
* <HelpTrigger taskSlug="settings-guide">
|
|
45
|
+
* <span className="text-blue-500 cursor-pointer">Learn more</span>
|
|
46
|
+
* </HelpTrigger>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare function HelpTrigger({ taskSlug, children, className, style, }: HelpTriggerProps): react_jsx_runtime.JSX.Element;
|
|
50
|
+
|
|
51
|
+
export { HelpMenu, HelpTrigger, HelpMenu as default };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface HelpMenuProps {
|
|
4
|
+
/** 按钮文字,默认 "?" */
|
|
5
|
+
label?: string | React.ReactNode;
|
|
6
|
+
/** 菜单标题 */
|
|
7
|
+
title?: string;
|
|
8
|
+
/** 自定义位置 */
|
|
9
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
10
|
+
/** 自定义样式类 */
|
|
11
|
+
className?: string;
|
|
12
|
+
/** 自定义按钮样式类 */
|
|
13
|
+
buttonClassName?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 帮助菜单组件 - 显示所有可用的 onboarding 任务
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* // 基础用法
|
|
21
|
+
* <HelpMenu />
|
|
22
|
+
*
|
|
23
|
+
* // 自定义
|
|
24
|
+
* <HelpMenu label="Need help?" title="Guides" position="bottom-left" />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
declare function HelpMenu({ label, title, position, className, buttonClassName, }: HelpMenuProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
interface HelpTriggerProps {
|
|
29
|
+
/** 要触发的任务 slug */
|
|
30
|
+
taskSlug: string;
|
|
31
|
+
children: React.ReactNode;
|
|
32
|
+
className?: string;
|
|
33
|
+
style?: React.CSSProperties;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 内联触发按钮 - 包裹任何元素,点击启动指定任务
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* <HelpTrigger taskSlug="welcome">
|
|
41
|
+
* <button>Show Tour</button>
|
|
42
|
+
* </HelpTrigger>
|
|
43
|
+
*
|
|
44
|
+
* <HelpTrigger taskSlug="settings-guide">
|
|
45
|
+
* <span className="text-blue-500 cursor-pointer">Learn more</span>
|
|
46
|
+
* </HelpTrigger>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare function HelpTrigger({ taskSlug, children, className, style, }: HelpTriggerProps): react_jsx_runtime.JSX.Element;
|
|
50
|
+
|
|
51
|
+
export { HelpMenu, HelpTrigger, HelpMenu as default };
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { useOnTheWay } from './chunk-RNQLNLNI.js';
|
|
2
|
+
import './chunk-OKJ5GEH3.js';
|
|
3
|
+
import { __spreadProps, __spreadValues } from './chunk-DDAAVRWG.js';
|
|
4
|
+
import { useState, useRef, useEffect } from 'react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function HelpMenu({
|
|
8
|
+
label = "?",
|
|
9
|
+
title = "Help & Guides",
|
|
10
|
+
position = "bottom-right",
|
|
11
|
+
className = "",
|
|
12
|
+
buttonClassName = ""
|
|
13
|
+
}) {
|
|
14
|
+
var _a;
|
|
15
|
+
const { otw, ready, start } = useOnTheWay();
|
|
16
|
+
const [open, setOpen] = useState(false);
|
|
17
|
+
const menuRef = useRef(null);
|
|
18
|
+
const tasks = ready ? (_a = otw == null ? void 0 : otw.getTasks()) != null ? _a : [] : [];
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const handleClick = (e) => {
|
|
21
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
22
|
+
setOpen(false);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
if (open) document.addEventListener("mousedown", handleClick);
|
|
26
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
27
|
+
}, [open]);
|
|
28
|
+
const positionStyles = {
|
|
29
|
+
"bottom-right": { position: "fixed", bottom: 24, right: 24 },
|
|
30
|
+
"bottom-left": { position: "fixed", bottom: 24, left: 24 },
|
|
31
|
+
"top-right": { position: "fixed", top: 24, right: 24 },
|
|
32
|
+
"top-left": { position: "fixed", top: 24, left: 24 }
|
|
33
|
+
};
|
|
34
|
+
const menuPosition = {
|
|
35
|
+
"bottom-right": { bottom: "100%", right: 0, marginBottom: 8 },
|
|
36
|
+
"bottom-left": { bottom: "100%", left: 0, marginBottom: 8 },
|
|
37
|
+
"top-right": { top: "100%", right: 0, marginTop: 8 },
|
|
38
|
+
"top-left": { top: "100%", left: 0, marginTop: 8 }
|
|
39
|
+
};
|
|
40
|
+
const triggerLabels = {
|
|
41
|
+
auto: "\u{1F504}",
|
|
42
|
+
manual: "\u{1F446}",
|
|
43
|
+
"first-visit": "\u{1F44B}"
|
|
44
|
+
};
|
|
45
|
+
return /* @__PURE__ */ jsxs(
|
|
46
|
+
"div",
|
|
47
|
+
{
|
|
48
|
+
ref: menuRef,
|
|
49
|
+
style: __spreadProps(__spreadValues({}, positionStyles[position]), { zIndex: 2147483640 }),
|
|
50
|
+
className,
|
|
51
|
+
children: [
|
|
52
|
+
open && /* @__PURE__ */ jsxs(
|
|
53
|
+
"div",
|
|
54
|
+
{
|
|
55
|
+
style: __spreadProps(__spreadValues({
|
|
56
|
+
position: "absolute"
|
|
57
|
+
}, menuPosition[position]), {
|
|
58
|
+
width: 280,
|
|
59
|
+
background: "#fff",
|
|
60
|
+
borderRadius: 12,
|
|
61
|
+
boxShadow: "0 8px 32px rgba(0,0,0,0.15)",
|
|
62
|
+
border: "1px solid #e5e7eb",
|
|
63
|
+
overflow: "hidden",
|
|
64
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
65
|
+
}),
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ jsx(
|
|
68
|
+
"div",
|
|
69
|
+
{
|
|
70
|
+
style: {
|
|
71
|
+
padding: "14px 16px",
|
|
72
|
+
borderBottom: "1px solid #f3f4f6",
|
|
73
|
+
fontWeight: 600,
|
|
74
|
+
fontSize: 14,
|
|
75
|
+
color: "#111"
|
|
76
|
+
},
|
|
77
|
+
children: title
|
|
78
|
+
}
|
|
79
|
+
),
|
|
80
|
+
/* @__PURE__ */ jsx("div", { style: { maxHeight: 320, overflowY: "auto" }, children: tasks.length === 0 ? /* @__PURE__ */ jsx(
|
|
81
|
+
"div",
|
|
82
|
+
{
|
|
83
|
+
style: {
|
|
84
|
+
padding: "24px 16px",
|
|
85
|
+
textAlign: "center",
|
|
86
|
+
color: "#9ca3af",
|
|
87
|
+
fontSize: 13
|
|
88
|
+
},
|
|
89
|
+
children: ready ? "No guides available" : "Loading..."
|
|
90
|
+
}
|
|
91
|
+
) : tasks.map((task) => {
|
|
92
|
+
var _a2;
|
|
93
|
+
return /* @__PURE__ */ jsxs(
|
|
94
|
+
"button",
|
|
95
|
+
{
|
|
96
|
+
onClick: () => {
|
|
97
|
+
start(task.slug);
|
|
98
|
+
setOpen(false);
|
|
99
|
+
},
|
|
100
|
+
style: {
|
|
101
|
+
display: "flex",
|
|
102
|
+
alignItems: "center",
|
|
103
|
+
gap: 10,
|
|
104
|
+
width: "100%",
|
|
105
|
+
padding: "12px 16px",
|
|
106
|
+
border: "none",
|
|
107
|
+
background: "none",
|
|
108
|
+
cursor: "pointer",
|
|
109
|
+
textAlign: "left",
|
|
110
|
+
fontSize: 14,
|
|
111
|
+
color: "#374151",
|
|
112
|
+
borderBottom: "1px solid #f9fafb",
|
|
113
|
+
transition: "background 0.15s"
|
|
114
|
+
},
|
|
115
|
+
onMouseEnter: (e) => e.currentTarget.style.background = "#f9fafb",
|
|
116
|
+
onMouseLeave: (e) => e.currentTarget.style.background = "none",
|
|
117
|
+
children: [
|
|
118
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: 16 }, children: (_a2 = triggerLabels[task.trigger]) != null ? _a2 : "\u{1F4D6}" }),
|
|
119
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
120
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 500 }, children: task.slug.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) }),
|
|
121
|
+
/* @__PURE__ */ jsxs("div", { style: { fontSize: 12, color: "#9ca3af" }, children: [
|
|
122
|
+
task.steps.length,
|
|
123
|
+
" steps"
|
|
124
|
+
] })
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsx("span", { style: { color: "#d1d5db", fontSize: 18 }, children: "\u203A" })
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
task.id
|
|
130
|
+
);
|
|
131
|
+
}) })
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
),
|
|
135
|
+
/* @__PURE__ */ jsx(
|
|
136
|
+
"button",
|
|
137
|
+
{
|
|
138
|
+
onClick: () => setOpen(!open),
|
|
139
|
+
className: buttonClassName,
|
|
140
|
+
style: buttonClassName ? void 0 : {
|
|
141
|
+
width: 48,
|
|
142
|
+
height: 48,
|
|
143
|
+
borderRadius: "50%",
|
|
144
|
+
border: "none",
|
|
145
|
+
background: "#111",
|
|
146
|
+
color: "#fff",
|
|
147
|
+
fontSize: 20,
|
|
148
|
+
fontWeight: 700,
|
|
149
|
+
cursor: "pointer",
|
|
150
|
+
boxShadow: "0 4px 14px rgba(0,0,0,0.2)",
|
|
151
|
+
display: "flex",
|
|
152
|
+
alignItems: "center",
|
|
153
|
+
justifyContent: "center",
|
|
154
|
+
transition: "transform 0.2s, box-shadow 0.2s"
|
|
155
|
+
},
|
|
156
|
+
onMouseEnter: (e) => {
|
|
157
|
+
if (!buttonClassName) {
|
|
158
|
+
e.currentTarget.style.transform = "scale(1.1)";
|
|
159
|
+
e.currentTarget.style.boxShadow = "0 6px 20px rgba(0,0,0,0.25)";
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
onMouseLeave: (e) => {
|
|
163
|
+
if (!buttonClassName) {
|
|
164
|
+
e.currentTarget.style.transform = "scale(1)";
|
|
165
|
+
e.currentTarget.style.boxShadow = "0 4px 14px rgba(0,0,0,0.2)";
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"aria-label": "Help menu",
|
|
169
|
+
children: label
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
function HelpTrigger({
|
|
177
|
+
taskSlug,
|
|
178
|
+
children,
|
|
179
|
+
className,
|
|
180
|
+
style
|
|
181
|
+
}) {
|
|
182
|
+
const { start, ready } = useOnTheWay();
|
|
183
|
+
return /* @__PURE__ */ jsx(
|
|
184
|
+
"span",
|
|
185
|
+
{
|
|
186
|
+
onClick: () => ready && start(taskSlug),
|
|
187
|
+
className,
|
|
188
|
+
style: __spreadValues({ cursor: ready ? "pointer" : "default" }, style),
|
|
189
|
+
role: "button",
|
|
190
|
+
tabIndex: 0,
|
|
191
|
+
onKeyDown: (e) => {
|
|
192
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
ready && start(taskSlug);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
children
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
var components_default = HelpMenu;
|
|
202
|
+
|
|
203
|
+
export { HelpMenu, HelpTrigger, components_default as default };
|
|
204
|
+
//# sourceMappingURL=components.js.map
|
|
205
|
+
//# sourceMappingURL=components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components.tsx"],"names":["_a"],"mappings":"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","file":"components.js","sourcesContent":["'use client'\n\nimport { useState, useRef, useEffect } from 'react'\nimport { useOnTheWay } from './react'\n\n// ---- Types ----\n\ninterface HelpMenuProps {\n /** 按钮文字,默认 \"?\" */\n label?: string | React.ReactNode\n /** 菜单标题 */\n title?: string\n /** 自定义位置 */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'\n /** 自定义样式类 */\n className?: string\n /** 自定义按钮样式类 */\n buttonClassName?: string\n}\n\n/**\n * 帮助菜单组件 - 显示所有可用的 onboarding 任务\n *\n * @example\n * ```tsx\n * // 基础用法\n * <HelpMenu />\n *\n * // 自定义\n * <HelpMenu label=\"Need help?\" title=\"Guides\" position=\"bottom-left\" />\n * ```\n */\nexport function HelpMenu({\n label = '?',\n title = 'Help & Guides',\n position = 'bottom-right',\n className = '',\n buttonClassName = '',\n}: HelpMenuProps) {\n const { otw, ready, start } = useOnTheWay()\n const [open, setOpen] = useState(false)\n const menuRef = useRef<HTMLDivElement>(null)\n\n const tasks = ready ? otw?.getTasks() ?? [] : []\n\n // 点击外部关闭\n useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\n setOpen(false)\n }\n }\n if (open) document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [open])\n\n const positionStyles: Record<string, React.CSSProperties> = {\n 'bottom-right': { position: 'fixed', bottom: 24, right: 24 },\n 'bottom-left': { position: 'fixed', bottom: 24, left: 24 },\n 'top-right': { position: 'fixed', top: 24, right: 24 },\n 'top-left': { position: 'fixed', top: 24, left: 24 },\n }\n\n const menuPosition: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: '100%', right: 0, marginBottom: 8 },\n 'bottom-left': { bottom: '100%', left: 0, marginBottom: 8 },\n 'top-right': { top: '100%', right: 0, marginTop: 8 },\n 'top-left': { top: '100%', left: 0, marginTop: 8 },\n }\n\n const triggerLabels: Record<string, string> = {\n auto: '🔄',\n manual: '👆',\n 'first-visit': '👋',\n }\n\n return (\n <div\n ref={menuRef}\n style={{ ...positionStyles[position], zIndex: 2147483640 }}\n className={className}\n >\n {/* 菜单面板 */}\n {open && (\n <div\n style={{\n position: 'absolute',\n ...menuPosition[position],\n width: 280,\n background: '#fff',\n borderRadius: 12,\n boxShadow: '0 8px 32px rgba(0,0,0,0.15)',\n border: '1px solid #e5e7eb',\n overflow: 'hidden',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '14px 16px',\n borderBottom: '1px solid #f3f4f6',\n fontWeight: 600,\n fontSize: 14,\n color: '#111',\n }}\n >\n {title}\n </div>\n\n {/* Task list */}\n <div style={{ maxHeight: 320, overflowY: 'auto' }}>\n {tasks.length === 0 ? (\n <div\n style={{\n padding: '24px 16px',\n textAlign: 'center',\n color: '#9ca3af',\n fontSize: 13,\n }}\n >\n {ready ? 'No guides available' : 'Loading...'}\n </div>\n ) : (\n tasks.map((task) => (\n <button\n key={task.id}\n onClick={() => {\n start(task.slug)\n setOpen(false)\n }}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n width: '100%',\n padding: '12px 16px',\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n textAlign: 'left',\n fontSize: 14,\n color: '#374151',\n borderBottom: '1px solid #f9fafb',\n transition: 'background 0.15s',\n }}\n onMouseEnter={(e) =>\n (e.currentTarget.style.background = '#f9fafb')\n }\n onMouseLeave={(e) =>\n (e.currentTarget.style.background = 'none')\n }\n >\n <span style={{ fontSize: 16 }}>\n {triggerLabels[task.trigger] ?? '📖'}\n </span>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: 500 }}>\n {task.slug\n .replace(/[-_]/g, ' ')\n .replace(/\\b\\w/g, (c) => c.toUpperCase())}\n </div>\n <div style={{ fontSize: 12, color: '#9ca3af' }}>\n {task.steps.length} steps\n </div>\n </div>\n <span style={{ color: '#d1d5db', fontSize: 18 }}>›</span>\n </button>\n ))\n )}\n </div>\n </div>\n )}\n\n {/* 触发按钮 */}\n <button\n onClick={() => setOpen(!open)}\n className={buttonClassName}\n style={\n buttonClassName\n ? undefined\n : {\n width: 48,\n height: 48,\n borderRadius: '50%',\n border: 'none',\n background: '#111',\n color: '#fff',\n fontSize: 20,\n fontWeight: 700,\n cursor: 'pointer',\n boxShadow: '0 4px 14px rgba(0,0,0,0.2)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'transform 0.2s, box-shadow 0.2s',\n }\n }\n onMouseEnter={(e) => {\n if (!buttonClassName) {\n e.currentTarget.style.transform = 'scale(1.1)'\n e.currentTarget.style.boxShadow = '0 6px 20px rgba(0,0,0,0.25)'\n }\n }}\n onMouseLeave={(e) => {\n if (!buttonClassName) {\n e.currentTarget.style.transform = 'scale(1)'\n e.currentTarget.style.boxShadow = '0 4px 14px rgba(0,0,0,0.2)'\n }\n }}\n aria-label=\"Help menu\"\n >\n {label}\n </button>\n </div>\n )\n}\n\n// ---- Inline trigger ----\n\ninterface HelpTriggerProps {\n /** 要触发的任务 slug */\n taskSlug: string\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\n/**\n * 内联触发按钮 - 包裹任何元素,点击启动指定任务\n *\n * @example\n * ```tsx\n * <HelpTrigger taskSlug=\"welcome\">\n * <button>Show Tour</button>\n * </HelpTrigger>\n *\n * <HelpTrigger taskSlug=\"settings-guide\">\n * <span className=\"text-blue-500 cursor-pointer\">Learn more</span>\n * </HelpTrigger>\n * ```\n */\nexport function HelpTrigger({\n taskSlug,\n children,\n className,\n style,\n}: HelpTriggerProps) {\n const { start, ready } = useOnTheWay()\n\n return (\n <span\n onClick={() => ready && start(taskSlug)}\n className={className}\n style={{ cursor: ready ? 'pointer' : 'default', ...style }}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n ready && start(taskSlug)\n }\n }}\n >\n {children}\n </span>\n )\n}\n\nexport default HelpMenu\n"]}
|