@ewjdev/anyclick-react 1.1.1 → 1.2.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/dist/index.d.mts +66 -36
- package/dist/index.d.ts +66 -36
- package/dist/index.js +174 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +176 -65
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ __export(index_exports, {
|
|
|
28
28
|
DEFAULT_SENSITIVE_SELECTORS: () => import_anyclick_core4.DEFAULT_SENSITIVE_SELECTORS,
|
|
29
29
|
FeedbackContext: () => FeedbackContext,
|
|
30
30
|
FeedbackProvider: () => FeedbackProvider,
|
|
31
|
+
FunModeBridge: () => FunModeBridge,
|
|
31
32
|
ScreenshotPreview: () => ScreenshotPreview,
|
|
32
33
|
applyHighlights: () => applyHighlights,
|
|
33
34
|
captureAllScreenshots: () => import_anyclick_core4.captureAllScreenshots,
|
|
@@ -120,16 +121,19 @@ var menuStyles = {
|
|
|
120
121
|
...menuCSSVariables
|
|
121
122
|
},
|
|
122
123
|
header: {
|
|
123
|
-
padding: "12px
|
|
124
|
+
padding: "8px 12px",
|
|
124
125
|
borderBottom: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
125
126
|
color: "var(--anyclick-menu-text-muted, #666)",
|
|
126
127
|
fontSize: "12px",
|
|
127
128
|
fontWeight: 500,
|
|
128
129
|
textTransform: "uppercase",
|
|
129
|
-
letterSpacing: "0.5px"
|
|
130
|
+
letterSpacing: "0.5px",
|
|
131
|
+
display: "flex",
|
|
132
|
+
justifyContent: "space-between",
|
|
133
|
+
alignItems: "center"
|
|
130
134
|
},
|
|
131
135
|
itemList: {
|
|
132
|
-
padding: "
|
|
136
|
+
padding: "0px 0px"
|
|
133
137
|
},
|
|
134
138
|
item: {
|
|
135
139
|
display: "flex",
|
|
@@ -531,6 +535,7 @@ function generateHighlightCSS(colors) {
|
|
|
531
535
|
border-radius: 4px !important;
|
|
532
536
|
position: relative;
|
|
533
537
|
z-index: 9997;
|
|
538
|
+
top: 0;
|
|
534
539
|
}
|
|
535
540
|
|
|
536
541
|
.${HIGHLIGHT_CONTAINER_CLASS} {
|
|
@@ -1072,19 +1077,27 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
|
1072
1077
|
var VIEWPORT_PADDING = 10;
|
|
1073
1078
|
var screenshotIndicatorStyle = {
|
|
1074
1079
|
display: "flex",
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
color: "var(--anyclick-menu-text-muted, #9ca3af)",
|
|
1080
|
-
borderTop: "1px solid var(--anyclick-menu-border, #f3f4f6)",
|
|
1081
|
-
marginTop: "4px"
|
|
1080
|
+
marginLeft: "4px",
|
|
1081
|
+
opacity: 0.7,
|
|
1082
|
+
justifyContent: "flex-end",
|
|
1083
|
+
flex: 1
|
|
1082
1084
|
};
|
|
1083
1085
|
var defaultIcons = {
|
|
1084
1086
|
issue: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Flag, { className: "w-4 h-4" }),
|
|
1085
1087
|
feature: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Plus, { className: "w-4 h-4" }),
|
|
1086
1088
|
like: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ThumbsUp, { className: "w-4 h-4" })
|
|
1087
1089
|
};
|
|
1090
|
+
var DefaultHeader = ({
|
|
1091
|
+
styles,
|
|
1092
|
+
className,
|
|
1093
|
+
title = "Send Feedback",
|
|
1094
|
+
children
|
|
1095
|
+
}) => {
|
|
1096
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles, className, children: [
|
|
1097
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: title }),
|
|
1098
|
+
children
|
|
1099
|
+
] });
|
|
1100
|
+
};
|
|
1088
1101
|
function MenuItem({
|
|
1089
1102
|
item,
|
|
1090
1103
|
onClick,
|
|
@@ -1262,7 +1275,9 @@ function ContextMenu({
|
|
|
1262
1275
|
className,
|
|
1263
1276
|
highlightConfig,
|
|
1264
1277
|
screenshotConfig,
|
|
1265
|
-
positionMode = "inView"
|
|
1278
|
+
positionMode = "inView",
|
|
1279
|
+
header,
|
|
1280
|
+
footer
|
|
1266
1281
|
}) {
|
|
1267
1282
|
const [selectedType, setSelectedType] = (0, import_react5.useState)(null);
|
|
1268
1283
|
const [currentView, setCurrentView] = (0, import_react5.useState)("menu");
|
|
@@ -1451,11 +1466,24 @@ function ContextMenu({
|
|
|
1451
1466
|
if (!visible || !targetElement) {
|
|
1452
1467
|
return null;
|
|
1453
1468
|
}
|
|
1454
|
-
const handleItemClick = (item) => {
|
|
1469
|
+
const handleItemClick = async (item) => {
|
|
1455
1470
|
if (item.children && item.children.length > 0) {
|
|
1456
1471
|
setSubmenuStack((prev) => [...prev, item.children]);
|
|
1457
1472
|
return;
|
|
1458
1473
|
}
|
|
1474
|
+
if (item.onClick) {
|
|
1475
|
+
try {
|
|
1476
|
+
const result = await item.onClick({
|
|
1477
|
+
targetElement,
|
|
1478
|
+
containerElement,
|
|
1479
|
+
closeMenu: onClose
|
|
1480
|
+
});
|
|
1481
|
+
return result;
|
|
1482
|
+
} catch (error) {
|
|
1483
|
+
console.error("Anyclick menu onClick error:", error);
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1459
1487
|
if (item.showComment) {
|
|
1460
1488
|
setSelectedType(item.type);
|
|
1461
1489
|
setCurrentView("comment");
|
|
@@ -1536,45 +1564,35 @@ function ContextMenu({
|
|
|
1536
1564
|
role: "menu",
|
|
1537
1565
|
"aria-label": "Feedback options",
|
|
1538
1566
|
children: [
|
|
1539
|
-
currentView !== "screenshot-preview" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1540
|
-
"div",
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
"
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
onMouseLeave: (e) => {
|
|
1569
|
-
e.currentTarget.style.opacity = "0.5";
|
|
1570
|
-
},
|
|
1571
|
-
title: "Drag to move",
|
|
1572
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GripVertical, { className: "w-4 h-4" })
|
|
1573
|
-
}
|
|
1574
|
-
)
|
|
1575
|
-
]
|
|
1576
|
-
}
|
|
1577
|
-
),
|
|
1567
|
+
!header && currentView !== "screenshot-preview" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(DefaultHeader, { styles: menuStyles.header, title: "Send Feedback", children: [
|
|
1568
|
+
showPreview && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: screenshotIndicatorStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Camera, { className: "w-3 h-3" }) }),
|
|
1569
|
+
positionMode === "dynamic" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1570
|
+
"div",
|
|
1571
|
+
{
|
|
1572
|
+
"data-drag-handle": true,
|
|
1573
|
+
onPointerDown: handleDragStart,
|
|
1574
|
+
style: {
|
|
1575
|
+
cursor: isDragging ? "grabbing" : "grab",
|
|
1576
|
+
padding: "4px",
|
|
1577
|
+
marginRight: "-4px",
|
|
1578
|
+
borderRadius: "4px",
|
|
1579
|
+
display: "flex",
|
|
1580
|
+
alignItems: "center",
|
|
1581
|
+
opacity: 0.5,
|
|
1582
|
+
transition: "opacity 0.15s"
|
|
1583
|
+
},
|
|
1584
|
+
onMouseEnter: (e) => {
|
|
1585
|
+
e.currentTarget.style.opacity = "1";
|
|
1586
|
+
},
|
|
1587
|
+
onMouseLeave: (e) => {
|
|
1588
|
+
e.currentTarget.style.opacity = "0.5";
|
|
1589
|
+
},
|
|
1590
|
+
title: "Drag to move",
|
|
1591
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GripVertical, { className: "w-4 h-4" })
|
|
1592
|
+
}
|
|
1593
|
+
)
|
|
1594
|
+
] }),
|
|
1595
|
+
!!header && header,
|
|
1578
1596
|
currentView === "menu" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: menuStyles.itemList, children: [
|
|
1579
1597
|
submenuStack.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BackButton, { onClick: handleBack }),
|
|
1580
1598
|
currentItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -1586,11 +1604,7 @@ function ContextMenu({
|
|
|
1586
1604
|
hasChildren: item.children && item.children.length > 0
|
|
1587
1605
|
},
|
|
1588
1606
|
item.type
|
|
1589
|
-
))
|
|
1590
|
-
showPreview && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotIndicatorStyle, children: [
|
|
1591
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Camera, { className: "w-3 h-3" }),
|
|
1592
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Screenshots will be captured" })
|
|
1593
|
-
] })
|
|
1607
|
+
))
|
|
1594
1608
|
] }),
|
|
1595
1609
|
currentView === "comment" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1596
1610
|
CommentForm,
|
|
@@ -1828,6 +1842,7 @@ function AnyclickProvider({
|
|
|
1828
1842
|
menuClassName,
|
|
1829
1843
|
disabled = false,
|
|
1830
1844
|
highlightConfig,
|
|
1845
|
+
header,
|
|
1831
1846
|
screenshotConfig,
|
|
1832
1847
|
scoped = false,
|
|
1833
1848
|
theme,
|
|
@@ -2038,7 +2053,7 @@ function AnyclickProvider({
|
|
|
2038
2053
|
localThemeColors: localTheme.highlightConfig?.colors
|
|
2039
2054
|
});
|
|
2040
2055
|
}
|
|
2041
|
-
const client = (0, import_anyclick_core3.
|
|
2056
|
+
const client = (0, import_anyclick_core3.createAnyclickClient)({
|
|
2042
2057
|
adapter,
|
|
2043
2058
|
targetFilter,
|
|
2044
2059
|
maxInnerTextLength,
|
|
@@ -2080,13 +2095,13 @@ function AnyclickProvider({
|
|
|
2080
2095
|
touchHoldDurationMs,
|
|
2081
2096
|
touchMoveThreshold
|
|
2082
2097
|
]);
|
|
2083
|
-
const
|
|
2098
|
+
const submitAnyclick = (0, import_react6.useCallback)(
|
|
2084
2099
|
async (element, type, comment, screenshots) => {
|
|
2085
2100
|
const client = clientRef.current;
|
|
2086
2101
|
if (!client) return;
|
|
2087
2102
|
setIsSubmitting(true);
|
|
2088
2103
|
try {
|
|
2089
|
-
await client.
|
|
2104
|
+
await client.submitAnyclick(element, type, {
|
|
2090
2105
|
comment,
|
|
2091
2106
|
metadata,
|
|
2092
2107
|
screenshots
|
|
@@ -2122,10 +2137,10 @@ function AnyclickProvider({
|
|
|
2122
2137
|
const handleMenuSelect = (0, import_react6.useCallback)(
|
|
2123
2138
|
(type, comment, screenshots) => {
|
|
2124
2139
|
if (targetElement) {
|
|
2125
|
-
|
|
2140
|
+
submitAnyclick(targetElement, type, comment, screenshots);
|
|
2126
2141
|
}
|
|
2127
2142
|
},
|
|
2128
|
-
[targetElement,
|
|
2143
|
+
[targetElement, submitAnyclick]
|
|
2129
2144
|
);
|
|
2130
2145
|
const inheritedTheme = getMergedTheme(providerId);
|
|
2131
2146
|
const mergedTheme = (0, import_react6.useMemo)(
|
|
@@ -2168,7 +2183,7 @@ function AnyclickProvider({
|
|
|
2168
2183
|
() => ({
|
|
2169
2184
|
isEnabled: !effectiveDisabled && !isDisabledByAncestor(providerId),
|
|
2170
2185
|
isSubmitting,
|
|
2171
|
-
|
|
2186
|
+
submitAnyclick,
|
|
2172
2187
|
openMenu,
|
|
2173
2188
|
closeMenu,
|
|
2174
2189
|
theme: mergedTheme,
|
|
@@ -2180,7 +2195,7 @@ function AnyclickProvider({
|
|
|
2180
2195
|
providerId,
|
|
2181
2196
|
isDisabledByAncestor,
|
|
2182
2197
|
isSubmitting,
|
|
2183
|
-
|
|
2198
|
+
submitAnyclick,
|
|
2184
2199
|
openMenu,
|
|
2185
2200
|
closeMenu,
|
|
2186
2201
|
mergedTheme,
|
|
@@ -2204,13 +2219,107 @@ function AnyclickProvider({
|
|
|
2204
2219
|
style: effectiveMenuStyle,
|
|
2205
2220
|
className: effectiveMenuClassName,
|
|
2206
2221
|
highlightConfig: effectiveHighlightConfig,
|
|
2207
|
-
screenshotConfig: effectiveScreenshotConfig
|
|
2222
|
+
screenshotConfig: effectiveScreenshotConfig,
|
|
2223
|
+
header
|
|
2208
2224
|
}
|
|
2209
2225
|
)
|
|
2210
2226
|
] });
|
|
2211
2227
|
}
|
|
2212
2228
|
var FeedbackProvider = AnyclickProvider;
|
|
2213
2229
|
|
|
2230
|
+
// src/FunModeBridge.tsx
|
|
2231
|
+
var import_react7 = require("react");
|
|
2232
|
+
var import_anyclick_pointer = require("@ewjdev/anyclick-pointer");
|
|
2233
|
+
function isFunModeEnabled(theme) {
|
|
2234
|
+
if (!theme) return false;
|
|
2235
|
+
if (theme.funMode === void 0) return false;
|
|
2236
|
+
if (typeof theme.funMode === "boolean") return theme.funMode;
|
|
2237
|
+
return theme.funMode.enabled ?? true;
|
|
2238
|
+
}
|
|
2239
|
+
function buildFunConfig(theme, container) {
|
|
2240
|
+
const funTheme = typeof theme?.funMode === "object" ? theme.funMode : {};
|
|
2241
|
+
const resolveTrackElement = () => {
|
|
2242
|
+
let el = container;
|
|
2243
|
+
while (el) {
|
|
2244
|
+
const rect = el.getBoundingClientRect();
|
|
2245
|
+
if (rect.width > 0 && rect.height > 0) {
|
|
2246
|
+
return el;
|
|
2247
|
+
}
|
|
2248
|
+
el = el.parentElement;
|
|
2249
|
+
}
|
|
2250
|
+
return document.body;
|
|
2251
|
+
};
|
|
2252
|
+
const getTrackElement = () => resolveTrackElement();
|
|
2253
|
+
return {
|
|
2254
|
+
maxSpeed: funTheme.maxSpeed,
|
|
2255
|
+
acceleration: funTheme.acceleration,
|
|
2256
|
+
getTrackElement,
|
|
2257
|
+
getObstacles: () => {
|
|
2258
|
+
const trackElement = getTrackElement();
|
|
2259
|
+
const obstacles = [];
|
|
2260
|
+
const parent = trackElement.parentElement;
|
|
2261
|
+
if (parent) {
|
|
2262
|
+
Array.from(parent.children).forEach((sibling) => {
|
|
2263
|
+
if (sibling !== trackElement) {
|
|
2264
|
+
obstacles.push(sibling.getBoundingClientRect());
|
|
2265
|
+
}
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
Array.from(trackElement.children).forEach((child) => {
|
|
2269
|
+
obstacles.push(child.getBoundingClientRect());
|
|
2270
|
+
});
|
|
2271
|
+
return obstacles;
|
|
2272
|
+
}
|
|
2273
|
+
};
|
|
2274
|
+
}
|
|
2275
|
+
function FunModeBridge() {
|
|
2276
|
+
const { setConfig } = (0, import_anyclick_pointer.usePointer)();
|
|
2277
|
+
const providerStore = useProviderStore();
|
|
2278
|
+
const activeProviderRef = (0, import_react7.useRef)(null);
|
|
2279
|
+
const cachedConfigs = (0, import_react7.useRef)({});
|
|
2280
|
+
const findActiveFunProvider = (0, import_react7.useMemo)(() => {
|
|
2281
|
+
return (el) => {
|
|
2282
|
+
if (!el) return null;
|
|
2283
|
+
const providers = providerStore.findProvidersForElement(el);
|
|
2284
|
+
for (const provider of providers) {
|
|
2285
|
+
if (provider.scoped && !provider.disabled && isFunModeEnabled(provider.theme)) {
|
|
2286
|
+
return provider;
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
return null;
|
|
2290
|
+
};
|
|
2291
|
+
}, [providerStore]);
|
|
2292
|
+
(0, import_react7.useEffect)(() => {
|
|
2293
|
+
const handleMove = (event) => {
|
|
2294
|
+
const el = document.elementFromPoint(event.clientX, event.clientY);
|
|
2295
|
+
const provider = findActiveFunProvider(el);
|
|
2296
|
+
if (!provider || !provider.containerRef.current) {
|
|
2297
|
+
if (activeProviderRef.current !== null) {
|
|
2298
|
+
activeProviderRef.current = null;
|
|
2299
|
+
setConfig({ mode: "normal" });
|
|
2300
|
+
}
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
if (activeProviderRef.current === provider.id) {
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
activeProviderRef.current = provider.id;
|
|
2307
|
+
if (!cachedConfigs.current[provider.id]) {
|
|
2308
|
+
cachedConfigs.current[provider.id] = {
|
|
2309
|
+
mode: "fun",
|
|
2310
|
+
funConfig: buildFunConfig(provider.theme, provider.containerRef.current)
|
|
2311
|
+
};
|
|
2312
|
+
}
|
|
2313
|
+
setConfig(cachedConfigs.current[provider.id]);
|
|
2314
|
+
};
|
|
2315
|
+
window.addEventListener("pointermove", handleMove, { passive: true });
|
|
2316
|
+
return () => {
|
|
2317
|
+
window.removeEventListener("pointermove", handleMove);
|
|
2318
|
+
};
|
|
2319
|
+
}, [findActiveFunProvider, setConfig]);
|
|
2320
|
+
return null;
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2214
2323
|
// src/types.ts
|
|
2215
2324
|
function filterMenuItemsByRole(items, userContext) {
|
|
2216
2325
|
if (!userContext) {
|
|
@@ -2238,6 +2347,7 @@ var import_anyclick_core4 = require("@ewjdev/anyclick-core");
|
|
|
2238
2347
|
DEFAULT_SENSITIVE_SELECTORS,
|
|
2239
2348
|
FeedbackContext,
|
|
2240
2349
|
FeedbackProvider,
|
|
2350
|
+
FunModeBridge,
|
|
2241
2351
|
ScreenshotPreview,
|
|
2242
2352
|
applyHighlights,
|
|
2243
2353
|
captureAllScreenshots,
|