Merge branch 'develop' into disable-ripple
This commit is contained in:
@@ -102,7 +102,7 @@ const ActionDescriptionBox = ({ isDarkMode }: { isDarkMode: boolean }) => {
|
||||
sx={{
|
||||
color: isDarkMode ? 'white' : 'default',
|
||||
'&.Mui-checked': {
|
||||
color: '#ff33cc',
|
||||
color: '#ff00c3',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
@@ -138,4 +138,4 @@ const ActionDescriptionBox = ({ isDarkMode }: { isDarkMode: boolean }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionDescriptionBox;
|
||||
export default ActionDescriptionBox;
|
||||
|
||||
@@ -3,8 +3,8 @@ import Tabs from '@mui/material/Tabs';
|
||||
import Tab from '@mui/material/Tab';
|
||||
import Box from '@mui/material/Box';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { Paper, Button, useTheme, Modal, Typography, Stack, TextField, InputAdornment, IconButton } from "@mui/material";
|
||||
import { AutoAwesome, FormatListBulleted, VpnKey, Usb, CloudQueue, Description, Favorite, ContentCopy, SlowMotionVideo } from "@mui/icons-material";
|
||||
import { Paper, Button, useTheme, Modal, Typography, Stack } from "@mui/material";
|
||||
import { AutoAwesome, VpnKey, Usb, CloudQueue, Description, Favorite, SlowMotionVideo, PlayArrow } from "@mui/icons-material";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useGlobalInfoStore } from "../../context/globalInfo";
|
||||
|
||||
@@ -121,7 +121,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp
|
||||
<Button
|
||||
onClick={() => setDocModalOpen(true)}
|
||||
sx={buttonStyles}
|
||||
startIcon={<Description />}
|
||||
startIcon={<Description sx={{ fontSize: 20 }} />}
|
||||
>
|
||||
Documentation
|
||||
</Button>
|
||||
@@ -155,10 +155,10 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp
|
||||
href='https://app.maxun.dev/'
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
sx={buttonStyles} startIcon={<CloudQueue />}>
|
||||
sx={buttonStyles} startIcon={<CloudQueue sx={{ fontSize: 20 }} />}>
|
||||
Join Maxun Cloud
|
||||
</Button>
|
||||
<Button onClick={() => setSponsorModalOpen(true)} sx={buttonStyles} startIcon={<Favorite />}>
|
||||
<Button onClick={() => setSponsorModalOpen(true)} sx={buttonStyles} startIcon={<Favorite sx={{ fontSize: 20 }} />}>
|
||||
Sponsor Us
|
||||
</Button>
|
||||
</Box>
|
||||
@@ -172,15 +172,11 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp
|
||||
<Typography variant="body1" gutterBottom>
|
||||
Maxun is built by a small, full-time team. Your donations directly contribute to making it better.
|
||||
<br />
|
||||
<br />
|
||||
Thank you for your support! 💙
|
||||
Thank you for your support! 🩷
|
||||
</Typography>
|
||||
<Stack direction="row" spacing={2} mt={2}>
|
||||
<Button href="https://checkout.dodopayments.com/buy/pdt_1Bdstszcg9VY8WYGwNBPM?quantity=1" target="_blank" rel="noopener noreferrer" variant="outlined" fullWidth>
|
||||
Sponsor $5 One-Time
|
||||
</Button>
|
||||
<Button href="https://checkout.dodopayments.com/buy/pdt_HDalaYf8hEGVG7hXcfNBj?quantity=1" target="_blank" rel="noopener noreferrer" variant="outlined" fullWidth>
|
||||
Sponsor $5 Monthly
|
||||
<Stack direction="row" spacing={2} mt={4}>
|
||||
<Button href="https://github.com/sponsors/amhsirak" target="_blank" rel="noopener noreferrer" variant="outlined" fullWidth>
|
||||
Sponsor Maxun on GitHub Sponsors
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
@@ -158,14 +158,11 @@ export const NavBar: React.FC<NavBarProps> = ({
|
||||
};
|
||||
|
||||
const renderThemeToggle = () => (
|
||||
<Tooltip title="Toggle Mode">
|
||||
<Tooltip title="Change Mode">
|
||||
<IconButton
|
||||
onClick={toggleTheme}
|
||||
sx={{
|
||||
color: darkMode ? '#ffffff' : '#0000008A',
|
||||
'&:hover': {
|
||||
background: 'inherit'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{darkMode ? <LightMode /> : <DarkMode />}
|
||||
|
||||
@@ -908,6 +908,7 @@ export const DOMBrowserRenderer: React.FC<RRWebDOMBrowserRendererProps> = ({
|
||||
rebuild(snapshotData.snapshot, {
|
||||
doc: iframeDoc,
|
||||
mirror: mirror,
|
||||
hackCss: false,
|
||||
cache: { stylesWithHoverClass: new Map() },
|
||||
afterAppend: (node) => {
|
||||
if (node.nodeType === Node.TEXT_NODE && node.textContent) {
|
||||
|
||||
@@ -188,8 +188,8 @@ export const ScheduleSettingsPage = ({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-start",
|
||||
padding: "20px",
|
||||
"& > *": { marginBottom: "20px" },
|
||||
marginTop: "-20px",
|
||||
}}
|
||||
>
|
||||
<>
|
||||
|
||||
@@ -155,14 +155,14 @@ const darkTheme = createTheme({
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: '#ffffff',
|
||||
"&:hover": {
|
||||
backgroundColor: 'rgba(255, 0, 195, 0.08)',
|
||||
},
|
||||
// "&:hover": {
|
||||
// backgroundColor: 'rgba(255, 0, 195, 0.08)',
|
||||
// },
|
||||
'&.MuiIconButton-colorError': {
|
||||
color: '#f44336',
|
||||
"&:hover": {
|
||||
backgroundColor: 'rgba(244, 67, 54, 0.08)',
|
||||
},
|
||||
// "&:hover": {
|
||||
// backgroundColor: 'rgba(244, 67, 54, 0.08)',
|
||||
// },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -555,38 +555,25 @@ class ClientSelectorGenerator {
|
||||
*/
|
||||
private isMeaningfulElement(element: HTMLElement): boolean {
|
||||
const tagName = element.tagName.toLowerCase();
|
||||
|
||||
// Fast path for common meaningful elements
|
||||
if (["a", "img", "input", "button", "select"].includes(tagName)) {
|
||||
|
||||
if (tagName === "img") {
|
||||
return element.hasAttribute("src");
|
||||
}
|
||||
|
||||
if (tagName === "a" && element.hasAttribute("href")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (element.children.length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const text = (element.textContent || "").trim();
|
||||
const hasHref = element.hasAttribute("href");
|
||||
const hasSrc = element.hasAttribute("src");
|
||||
|
||||
// Quick checks first
|
||||
if (text.length > 0 || hasHref || hasSrc) {
|
||||
|
||||
if (text.length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const isCustomElement = tagName.includes("-");
|
||||
|
||||
// For custom elements, be more lenient about what's considered meaningful
|
||||
if (isCustomElement) {
|
||||
const hasChildren = element.children.length > 0;
|
||||
const hasSignificantAttributes = Array.from(element.attributes).some(
|
||||
(attr) => !["class", "style", "id"].includes(attr.name.toLowerCase())
|
||||
);
|
||||
|
||||
return (
|
||||
hasChildren ||
|
||||
hasSignificantAttributes ||
|
||||
element.hasAttribute("role") ||
|
||||
element.hasAttribute("aria-label")
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2561,12 +2548,9 @@ class ClientSelectorGenerator {
|
||||
|
||||
const MAX_MEANINGFUL_ELEMENTS = 300;
|
||||
const MAX_NODES_TO_CHECK = 1200;
|
||||
const MAX_DEPTH = 12;
|
||||
const MAX_DEPTH = 20;
|
||||
let nodesChecked = 0;
|
||||
|
||||
let adjustedMaxDepth = MAX_DEPTH;
|
||||
const elementDensityThreshold = 50;
|
||||
|
||||
const depths: number[] = [0];
|
||||
let queueIndex = 0;
|
||||
|
||||
@@ -2576,14 +2560,10 @@ class ClientSelectorGenerator {
|
||||
queueIndex++;
|
||||
nodesChecked++;
|
||||
|
||||
if (currentDepth <= 3 && meaningfulDescendants.length > elementDensityThreshold) {
|
||||
adjustedMaxDepth = Math.max(6, adjustedMaxDepth - 2);
|
||||
}
|
||||
|
||||
if (
|
||||
nodesChecked > MAX_NODES_TO_CHECK ||
|
||||
meaningfulDescendants.length >= MAX_MEANINGFUL_ELEMENTS ||
|
||||
currentDepth > adjustedMaxDepth
|
||||
currentDepth > MAX_DEPTH
|
||||
) {
|
||||
break;
|
||||
}
|
||||
@@ -2592,7 +2572,7 @@ class ClientSelectorGenerator {
|
||||
meaningfulDescendants.push(element);
|
||||
}
|
||||
|
||||
if (currentDepth >= adjustedMaxDepth) {
|
||||
if (currentDepth >= MAX_DEPTH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2607,7 +2587,7 @@ class ClientSelectorGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
if (element.shadowRoot && currentDepth < adjustedMaxDepth - 1) {
|
||||
if (element.shadowRoot && currentDepth < MAX_DEPTH - 1) {
|
||||
const shadowChildren = element.shadowRoot.children;
|
||||
const shadowLimit = Math.min(shadowChildren.length, 20);
|
||||
for (let i = 0; i < shadowLimit; i++) {
|
||||
@@ -2716,22 +2696,46 @@ class ClientSelectorGenerator {
|
||||
}
|
||||
|
||||
if (!addPositionToAll) {
|
||||
const meaningfulAttrs = ["role", "type", "name", "src", "aria-label"];
|
||||
const meaningfulAttrs = ["role", "type"];
|
||||
for (const attrName of meaningfulAttrs) {
|
||||
if (element.hasAttribute(attrName)) {
|
||||
const value = element.getAttribute(attrName)!.replace(/'/g, "\\'");
|
||||
return `${tagName}[@${attrName}='${value}']`;
|
||||
const isCommonAttribute = this.isAttributeCommonAcrossLists(
|
||||
element,
|
||||
attrName,
|
||||
value,
|
||||
otherListElements
|
||||
);
|
||||
if (isCommonAttribute) {
|
||||
return `${tagName}[@${attrName}='${value}']`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const testId = element.getAttribute("data-testid");
|
||||
if (testId && !addPositionToAll) {
|
||||
return `${tagName}[@data-testid='${testId}']`;
|
||||
const isCommon = this.isAttributeCommonAcrossLists(
|
||||
element,
|
||||
"data-testid",
|
||||
testId,
|
||||
otherListElements
|
||||
);
|
||||
if (isCommon) {
|
||||
return `${tagName}[@data-testid='${testId}']`;
|
||||
}
|
||||
}
|
||||
|
||||
if (element.id && !element.id.match(/^\d/) && !addPositionToAll) {
|
||||
return `${tagName}[@id='${element.id}']`;
|
||||
const isCommon = this.isAttributeCommonAcrossLists(
|
||||
element,
|
||||
"id",
|
||||
element.id,
|
||||
otherListElements
|
||||
);
|
||||
if (isCommon) {
|
||||
return `${tagName}[@id='${element.id}']`;
|
||||
}
|
||||
}
|
||||
|
||||
if (!addPositionToAll) {
|
||||
@@ -2742,7 +2746,15 @@ class ClientSelectorGenerator {
|
||||
attr.name !== "data-mx-id" &&
|
||||
attr.value
|
||||
) {
|
||||
return `${tagName}[@${attr.name}='${attr.value}']`;
|
||||
const isCommon = this.isAttributeCommonAcrossLists(
|
||||
element,
|
||||
attr.name,
|
||||
attr.value,
|
||||
otherListElements
|
||||
);
|
||||
if (isCommon) {
|
||||
return `${tagName}[@${attr.name}='${attr.value}']`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2906,12 +2918,70 @@ class ClientSelectorGenerator {
|
||||
const result = pathParts.length > 0 ? "/" + pathParts.join("/") : null;
|
||||
|
||||
this.pathCache.set(targetElement, result);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private isAttributeCommonAcrossLists(
|
||||
targetElement: HTMLElement,
|
||||
attrName: string,
|
||||
attrValue: string,
|
||||
otherListElements: HTMLElement[]
|
||||
): boolean {
|
||||
if (otherListElements.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const targetPath = this.getElementPath(targetElement);
|
||||
|
||||
for (const otherListElement of otherListElements) {
|
||||
const correspondingElement = this.findCorrespondingElement(
|
||||
otherListElement,
|
||||
targetPath
|
||||
);
|
||||
if (correspondingElement) {
|
||||
const otherValue = correspondingElement.getAttribute(attrName);
|
||||
if (otherValue !== attrValue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private getElementPath(element: HTMLElement): number[] {
|
||||
const path: number[] = [];
|
||||
let current: HTMLElement | null = element;
|
||||
|
||||
while (current && current.parentElement) {
|
||||
const siblings = Array.from(current.parentElement.children);
|
||||
path.unshift(siblings.indexOf(current));
|
||||
current = current.parentElement;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private findCorrespondingElement(
|
||||
rootElement: HTMLElement,
|
||||
path: number[]
|
||||
): HTMLElement | null {
|
||||
let current: HTMLElement = rootElement;
|
||||
|
||||
for (const index of path) {
|
||||
const children = Array.from(current.children);
|
||||
if (index >= children.length) {
|
||||
return null;
|
||||
}
|
||||
current = children[index] as HTMLElement;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
private getCommonClassesAcrossLists(
|
||||
targetElement: HTMLElement,
|
||||
targetElement: HTMLElement,
|
||||
otherListElements: HTMLElement[]
|
||||
): string[] {
|
||||
if (otherListElements.length === 0) {
|
||||
@@ -3919,9 +3989,48 @@ class ClientSelectorGenerator {
|
||||
);
|
||||
if (!deepestElement) return null;
|
||||
|
||||
if (!this.isMeaningfulElementCached(deepestElement)) {
|
||||
const atomicChild = this.findAtomicChildAtPoint(deepestElement, x, y);
|
||||
if (atomicChild) {
|
||||
return atomicChild;
|
||||
}
|
||||
}
|
||||
|
||||
return deepestElement;
|
||||
}
|
||||
|
||||
private findAtomicChildAtPoint(
|
||||
parent: HTMLElement,
|
||||
x: number,
|
||||
y: number
|
||||
): HTMLElement | null {
|
||||
const stack: HTMLElement[] = [parent];
|
||||
const visited = new Set<HTMLElement>();
|
||||
|
||||
while (stack.length > 0) {
|
||||
const element = stack.pop()!;
|
||||
if (visited.has(element)) continue;
|
||||
visited.add(element);
|
||||
|
||||
if (element !== parent && this.isMeaningfulElementCached(element)) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = element.children.length - 1; i >= 0; i--) {
|
||||
const child = element.children[i] as HTMLElement;
|
||||
const rect = child.getBoundingClientRect();
|
||||
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
|
||||
stack.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper methods used by the unified getDeepestElementFromPoint
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user